├── src
├── Tests
│ ├── Global.asax
│ ├── Content
│ │ └── Images
│ │ │ └── app-icon-1024.png
│ ├── Models
│ │ ├── TestModel.cs
│ │ ├── LoginModel.cs
│ │ └── PdfLayout.cs
│ ├── Tests.csproj.DotSettings
│ ├── Global.asax.cs
│ ├── App_Start
│ │ └── WebApiConfig.cs
│ ├── Extensions
│ │ ├── HttpContentExtensions.cs
│ │ ├── ByteArrayExtensions.cs
│ │ ├── TimeSpanExtensions.cs
│ │ ├── LongExtensions.cs
│ │ └── HttpResponseMessageExtensions.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── app.config
│ ├── Tests.v2.ncrunchproject
│ ├── packages.config
│ ├── web.config
│ ├── Tests
│ │ ├── Integration
│ │ │ ├── CompressionHandlerWithoutThresholdTests.cs
│ │ │ ├── AcceptEncodingStarCompressionHandlerWithThresholdTests.cs
│ │ │ └── CompressionHandlerWithThresholdTests.cs
│ │ ├── Facade
│ │ │ └── OwinHostTests.cs
│ │ └── Common
│ │ │ └── TestFixture.cs
│ ├── Handlers
│ │ └── TraceMessageHandler.cs
│ ├── Controllers
│ │ ├── TestController.cs
│ │ └── FileController.cs
│ ├── Tests.csproj
│ └── Tests.StrongName.csproj
├── StrongKey.snk
├── Microsoft.AspNet.WebApi.MessageHandlers.Compression.jmconfig
├── Core
│ ├── Interfaces
│ │ ├── IStreamManager.cs
│ │ └── ICompressor.cs
│ ├── StreamManager.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── HttpContentOperations.cs
│ ├── Compressors
│ │ ├── GZipCompressor.cs
│ │ ├── DeflateCompressor.cs
│ │ └── BaseCompressor.cs
│ ├── Extensions
│ │ └── HttpContentHeaderExtensions.cs
│ ├── Core.csproj
│ ├── Models
│ │ └── CompressedContent.cs
│ └── Core.StrongName.csproj
├── Server
│ ├── packages.config
│ ├── app.config
│ ├── RecyclableStreamManager.cs
│ ├── Attributes
│ │ └── CompressionAttribute.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Server.csproj
│ ├── Server.StrongName.csproj
│ └── ServerCompressionHandler.cs
├── Server.Owin
│ ├── app.config
│ ├── packages.config
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Server.Owin.csproj
│ ├── Server.Owin.StrongName.csproj
│ └── OwinServerCompressionHandler.cs
├── Microsoft.AspNet.WebApi.MessageHandlers.Compression.v2.ncrunchsolution
├── Client
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Client.csproj
│ ├── Client.StrongName.csproj
│ └── ClientCompressionHandler.cs
└── Microsoft.AspNet.WebApi.MessageHandlers.Compression.sln
├── .gitattributes
├── appveyor.yml
├── dist
└── nuget
│ ├── Microsoft.AspNet.WebApi.MessageHandlers.Compression.nuspec
│ ├── Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin.nuspec
│ ├── Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin.StrongName.nuspec
│ ├── Microsoft.AspNet.WebApi.Extensions.Compression.Server.nuspec
│ ├── Microsoft.AspNet.WebApi.Extensions.Compression.Server.StrongName.nuspec
│ ├── System.Net.Http.Extensions.Compression.Client.nuspec
│ └── System.Net.Http.Extensions.Compression.Client.StrongName.nuspec
├── .gitignore
├── README.md
└── LICENSE
/src/Tests/Global.asax:
--------------------------------------------------------------------------------
1 | <%@ Application Codebehind="Global.asax.cs" Inherits="Tests.WebApiApplication" Language="C#" %>
2 |
--------------------------------------------------------------------------------
/src/StrongKey.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression/HEAD/src/StrongKey.snk
--------------------------------------------------------------------------------
/src/Tests/Content/Images/app-icon-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression/HEAD/src/Tests/Content/Images/app-icon-1024.png
--------------------------------------------------------------------------------
/src/Microsoft.AspNet.WebApi.MessageHandlers.Compression.jmconfig:
--------------------------------------------------------------------------------
1 | false
--------------------------------------------------------------------------------
/src/Tests/Models/TestModel.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Models
2 | {
3 | public class TestModel
4 | {
5 | public TestModel()
6 | {
7 | }
8 |
9 | public TestModel(string data)
10 | {
11 | this.Data = data;
12 | }
13 |
14 | public string Data { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Core/Interfaces/IStreamManager.cs:
--------------------------------------------------------------------------------
1 | namespace System.Net.Http.Extensions.Compression.Core.Interfaces
2 | {
3 | using System.IO;
4 |
5 | public interface IStreamManager
6 | {
7 | /// Gets a stream.
8 | /// (Optional) the stream name.
9 | /// The stream.
10 | Stream GetStream(string tag = null);
11 | }
12 | }
--------------------------------------------------------------------------------
/src/Server/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/Tests/Tests.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
--------------------------------------------------------------------------------
/src/Server.Owin/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/Tests/Global.asax.cs:
--------------------------------------------------------------------------------
1 | namespace Tests
2 | {
3 | using System.Web;
4 | using System.Web.Http;
5 |
6 | // Note: For instructions on enabling IIS6 or IIS7 classic mode,
7 | // visit http://go.microsoft.com/?LinkId=9394801
8 |
9 | public class WebApiApplication : HttpApplication
10 | {
11 | protected void Application_Start()
12 | {
13 | WebApiConfig.Register(GlobalConfiguration.Configuration);
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/Core/StreamManager.cs:
--------------------------------------------------------------------------------
1 | namespace System.Net.Http.Extensions.Compression.Core
2 | {
3 | using System.IO;
4 | using System.Net.Http.Extensions.Compression.Core.Interfaces;
5 |
6 | /// Manager for streams.
7 | public class StreamManager : IStreamManager
8 | {
9 | public static IStreamManager Instance { get; } = new StreamManager();
10 |
11 | public Stream GetStream(string tag = null)
12 | {
13 | return new MemoryStream();
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/Server/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/Server.Owin/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/src/Tests/Models/LoginModel.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Models
2 | {
3 | public class LoginModel
4 | {
5 | public LoginModel()
6 | {
7 | }
8 |
9 | public LoginModel(string username, string password, string returnUrl)
10 | {
11 | this.Username = username;
12 | this.Password = password;
13 | this.ReturnUrl = returnUrl;
14 | }
15 |
16 | public string Username { get; set; }
17 |
18 | public string Password { get; set; }
19 |
20 | public string ReturnUrl { get; set; }
21 | }
22 | }
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: $(Major).$(Minor).0.{build}
2 | branches:
3 | only:
4 | - develop
5 | configuration: Release
6 | platform: Any CPU
7 | assembly_info:
8 | patch: true
9 | file: '**\AssemblyInfo.*'
10 | assembly_version: $(Major).$(Minor).0
11 | assembly_file_version: $(Major).$(Minor).0.{build}
12 | assembly_informational_version: $(Major).$(Minor).0.{build}-{branch}
13 | environment:
14 | Major: 2
15 | Minor: 1
16 | before_build:
17 | - cmd: nuget restore src\Microsoft.AspNet.WebApi.MessageHandlers.Compression.sln
18 | build:
19 | project: src\Microsoft.AspNet.WebApi.MessageHandlers.Compression.sln
20 | verbosity: minimal
21 | cache:
22 | - packages -> **\packages.config
--------------------------------------------------------------------------------
/src/Tests/Models/PdfLayout.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Models
2 | {
3 | using iTextSharp.text;
4 | using iTextSharp.text.pdf;
5 |
6 | public class PdfLayout : PdfPageEventHelper
7 | {
8 | public override void OnStartPage(PdfWriter writer, Document doc)
9 | {
10 | }
11 |
12 | public override void OnEndPage(PdfWriter writer, Document doc)
13 | {
14 | var cb = writer.DirectContent;
15 | cb.MoveTo(doc.LeftMargin, doc.BottomMargin - 10f);
16 | cb.LineTo(doc.PageSize.Width - doc.RightMargin, doc.BottomMargin - 10f);
17 | cb.SetRGBColorStroke(255, 85, 0);
18 | cb.Stroke();
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/src/Microsoft.AspNet.WebApi.MessageHandlers.Compression.v2.ncrunchsolution:
--------------------------------------------------------------------------------
1 |
2 | 1
3 | false
4 | true
5 | true
6 | UseDynamicAnalysis
7 | UseStaticAnalysis
8 | UseStaticAnalysis
9 | UseStaticAnalysis
10 | UseStaticAnalysis
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/Tests/App_Start/WebApiConfig.cs:
--------------------------------------------------------------------------------
1 | namespace Tests
2 | {
3 | using System.Net.Http.Extensions.Compression.Core.Compressors;
4 | using System.Web.Http;
5 |
6 | using Microsoft.AspNet.WebApi.Extensions.Compression.Server;
7 |
8 | public static class WebApiConfig
9 | {
10 | public static void Register(HttpConfiguration config)
11 | {
12 | config.MapHttpAttributeRoutes();
13 |
14 | config.Routes.MapHttpRoute(
15 | name: "DefaultApi",
16 | routeTemplate: "api/{controller}/{id}",
17 | defaults: new { id = RouteParameter.Optional });
18 |
19 | // Add compression message handler
20 | config.MessageHandlers.Insert(0, new ServerCompressionHandler(0, new GZipCompressor(RecyclableStreamManager.Instance), new DeflateCompressor(RecyclableStreamManager.Instance)));
21 |
22 | // Configure error details policy
23 | config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
24 |
25 | config.EnsureInitialized();
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/src/Server/RecyclableStreamManager.cs:
--------------------------------------------------------------------------------
1 | namespace Microsoft.AspNet.WebApi.Extensions.Compression.Server
2 | {
3 | using System.IO;
4 | using System.Net.Http.Extensions.Compression.Core.Interfaces;
5 |
6 | using Microsoft.IO;
7 |
8 | /// Manager for streams.
9 | public class RecyclableStreamManager : IStreamManager
10 | {
11 | private readonly RecyclableMemoryStreamManager recyclableMemoryStreamManager;
12 |
13 | /// Initializes a new instance of the class.
14 | public RecyclableStreamManager()
15 | {
16 | this.recyclableMemoryStreamManager = new RecyclableMemoryStreamManager();
17 | }
18 |
19 | public static IStreamManager Instance { get; } = new RecyclableStreamManager();
20 |
21 | public Stream GetStream(string tag = null)
22 | {
23 | return !string.IsNullOrEmpty(tag)
24 | ? this.recyclableMemoryStreamManager.GetStream(tag)
25 | : this.recyclableMemoryStreamManager.GetStream();
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/src/Tests/Extensions/HttpContentExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Extensions
2 | {
3 | using System.Net.Http;
4 | using System.Threading.Tasks;
5 |
6 | public static class HttpContentExtensions
7 | {
8 | ///
9 | /// Gets the payload size as a human readable string.
10 | ///
11 | /// The content.
12 | /// The payload size as a human readable string.
13 | public static string SizeAsHumanReadableString(this HttpContent content)
14 | {
15 | if (content.Headers.ContentLength.HasValue)
16 | {
17 | return content.Headers.ContentLength.Value.SizeAsHumanReadableString(LongExtensions.SIType.Byte);
18 | }
19 |
20 | var tcs = new TaskCompletionSource();
21 | Task.Run(async () =>
22 | {
23 | await content.LoadIntoBufferAsync();
24 |
25 | tcs.SetResult(await content.ReadAsByteArrayAsync());
26 | }).ConfigureAwait(false);
27 |
28 | return tcs.Task.Result.SizeAsHumanReadableString();
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/src/Core/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Resources;
2 | using System.Reflection;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 |
6 | // General Information about an assembly is controlled through the following
7 | // set of attributes. Change these attribute values to modify the information
8 | // associated with an assembly.
9 | [assembly: AssemblyTitle("Core")]
10 | [assembly: AssemblyDescription("")]
11 | [assembly: AssemblyConfiguration("")]
12 | [assembly: AssemblyCompany("")]
13 | [assembly: AssemblyProduct("Core")]
14 | [assembly: AssemblyCopyright("Copyright © 2016")]
15 | [assembly: AssemblyTrademark("")]
16 | [assembly: AssemblyCulture("")]
17 | [assembly: NeutralResourcesLanguage("en")]
18 |
19 | // Version information for an assembly consists of the following four values:
20 | //
21 | // Major Version
22 | // Minor Version
23 | // Build Number
24 | // Revision
25 | //
26 | // You can specify all the values or you can default the Build and Revision Numbers
27 | // by using the '*' as shown below:
28 | // [assembly: AssemblyVersion("1.0.*")]
29 | [assembly: AssemblyVersion("1.0.0.0")]
30 | [assembly: AssemblyFileVersion("1.0.0.0")]
31 |
--------------------------------------------------------------------------------
/src/Tests/Extensions/ByteArrayExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Extensions
2 | {
3 | internal static class ByteArrayExtensions
4 | {
5 | ///
6 | /// Gets the size as a human readable string.
7 | ///
8 | /// The byte array.
9 | /// The size as a human readable string..
10 | public static string SizeAsHumanReadableString(this byte[] s)
11 | {
12 | // Larger or equal to 1KB but lesser than 1MB
13 | if (s.Length >= 1024 && s.Length < 1048576)
14 | {
15 | return string.Format("{0}KB", s.Length / 1024);
16 | }
17 |
18 | // Larger or equal to 1MB but lesser than 1GB
19 | if (s.Length >= 1048576 && s.Length < 1073741824)
20 | {
21 | return string.Format("{0}MB", s.Length / 1024 / 1024);
22 | }
23 |
24 | // Larger or equal to 1Gt but lesser than 1TB
25 | if (s.Length >= 1073741824)
26 | {
27 | return string.Format("{0}GB", s.Length / 1024 / 1024 / 1024);
28 | }
29 |
30 | return string.Format("{0}bytes", s.Length);
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/src/Core/Interfaces/ICompressor.cs:
--------------------------------------------------------------------------------
1 | namespace System.Net.Http.Extensions.Compression.Core.Interfaces
2 | {
3 | using System.IO;
4 | using System.Threading.Tasks;
5 |
6 | ///
7 | /// Interface for stream compressors.
8 | ///
9 | public interface ICompressor
10 | {
11 | ///
12 | /// Gets the encoding type.
13 | ///
14 | /// The encoding type.
15 | string EncodingType { get; }
16 |
17 | ///
18 | /// Compresses the specified source stream onto the destination stream.
19 | ///
20 | /// The source.
21 | /// The destination.
22 | /// The compressed content length.
23 | Task Compress(Stream source, Stream destination);
24 |
25 | ///
26 | /// Decompresses the specified source stream onto the destination stream.
27 | ///
28 | /// The source.
29 | /// The destination.
30 | /// An async void.
31 | Task Decompress(Stream source, Stream destination);
32 | }
33 | }
--------------------------------------------------------------------------------
/src/Client/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("System.Net.Http.Extensions.Compression.Client")]
8 | [assembly: AssemblyDescription("Module for Microsoft HTTP Client that enables GZip and Deflate support for incoming and outgoing requests")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("EyeCatch")]
11 | [assembly: AssemblyProduct("System.Net.Http.Extensions.Compression.Client")]
12 | [assembly: AssemblyCopyright("Copyright © EyeCatch 2016")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 | [assembly: NeutralResourcesLanguage("en")]
16 |
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Build and Revision Numbers
25 | // by using the '*' as shown below:
26 | // [assembly: AssemblyVersion("1.0.*")]
27 | [assembly: AssemblyVersion("1.0.0.0")]
28 | [assembly: AssemblyFileVersion("1.0.0.0")]
29 |
--------------------------------------------------------------------------------
/src/Tests/Extensions/TimeSpanExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Extensions
2 | {
3 | using System;
4 |
5 | public static class TimeSpanExtensions
6 | {
7 | ///
8 | /// Returns the timespan as a human readable string.
9 | ///
10 | /// The timespan.
11 | /// The timespan as a human readable string.
12 | public static string AsHumanReadableString(this TimeSpan ts)
13 | {
14 | // Larger or equal to 1 second but lesser than 1 minute
15 | if (ts.TotalMilliseconds >= 1000 && ts.TotalMilliseconds < 60000)
16 | {
17 | return string.Format("{0}s", ts.TotalMilliseconds / 1000);
18 | }
19 |
20 | // Larger or equal to 1 minute but lesser than 1 hour
21 | if (ts.TotalMilliseconds >= 60000 && ts.TotalMilliseconds < 3600000)
22 | {
23 | return string.Format("{0}m", ts.TotalMilliseconds / 1000 / 60);
24 | }
25 |
26 | // Larger or equal to 1 hour but lesser than 1 day
27 | if (ts.TotalMilliseconds >= 3600000 && ts.TotalMilliseconds < 86400000)
28 | {
29 | return string.Format("{0}h", ts.TotalMilliseconds / 1000 / 60 / 60);
30 | }
31 |
32 | return string.Format("{0}ms", ts.TotalMilliseconds);
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/src/Server/Attributes/CompressionAttribute.cs:
--------------------------------------------------------------------------------
1 | namespace Microsoft.AspNet.WebApi.Extensions.Compression.Server.Attributes
2 | {
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using System.Web.Http.Controllers;
6 | using System.Web.Http.Filters;
7 |
8 | public class CompressionAttribute : ActionFilterAttribute
9 | {
10 | /// Initializes a new instance of the class.
11 | public CompressionAttribute()
12 | {
13 | this.Enabled = true;
14 | }
15 |
16 | /// Gets or sets a value indicating whether to enable compression for this request.
17 | /// true if enabled, false if not. The default value is false.
18 | public bool Enabled { get; set; }
19 |
20 | /// Executes the action executing asynchronous action.
21 | /// The action context.
22 | /// The cancellation token.
23 | /// A Task.
24 | public override Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
25 | {
26 | actionContext.Request.Properties["compression:Enable"] = this.Enabled;
27 |
28 | return base.OnActionExecutingAsync(actionContext, cancellationToken);
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/src/Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("45ecb0d8-a4c6-4e4a-866e-7de3bcf4f1a8")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/Tests/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/dist/nuget/Microsoft.AspNet.WebApi.MessageHandlers.Compression.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Microsoft.AspNet.WebApi.MessageHandlers.Compression
5 | 2.0.0
6 | Microsoft ASP.NET Web API Compression Support
7 | Ove Andersen
8 | EyeCatch
9 |
10 | NOTE!!!
11 |
12 | This is an obsolete package, it only installs the Microsoft.AspNet.WebApi.Extensions.Compression.Server and System.Net.Http.Extensions.Compression.Client packages.
13 |
14 | NOTE!!! This is an obsolete package, it only installs the Microsoft.AspNet.WebApi.Extensions.Compression.Server and System.Net.Http.Extensions.Compression.Client packages.
15 | en-US
16 | https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression
17 | http://www.eyecatch.no/favicon.ico
18 | false
19 | http://www.eyecatch.no/licenses/apache-20/
20 | Copyright EyeCatch 2016
21 |
22 |
23 |
24 |
25 |
26 | aspnet webapi aspnetwebapi compression gzip deflate eyecatch
27 |
28 |
--------------------------------------------------------------------------------
/src/Tests/Tests.v2.ncrunchproject:
--------------------------------------------------------------------------------
1 |
2 | 1000
3 | false
4 | false
5 | false
6 | true
7 | false
8 | false
9 | false
10 | false
11 | false
12 | true
13 | true
14 | false
15 | true
16 | true
17 | true
18 | 60000
19 |
20 |
21 |
22 | AutoDetect
23 | STA
24 | x86
25 |
26 |
27 | Tests.Tests.Facade.WebHostTests
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/Server.Owin/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin")]
8 | [assembly: AssemblyDescription("OWIN support for Microsoft.AspNet.WebApi.Extensions.Compression.Server")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("EyeCatch")]
11 | [assembly: AssemblyProduct("Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin")]
12 | [assembly: AssemblyCopyright("Copyright © EyeCatch 2016")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Setting ComVisible to false makes the types in this assembly not visible
17 | // to COM components. If you need to access a type in this assembly from
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 |
21 | // The following GUID is for the ID of the typelib if this project is exposed to COM
22 | [assembly: Guid("daa0a504-7ed7-4906-9d6b-fb566ae47084")]
23 |
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | // Major Version
27 | // Minor Version
28 | // Build Number
29 | // Revision
30 | //
31 | // You can specify all the values or you can default the Build and Revision Numbers
32 | // by using the '*' as shown below:
33 | // [assembly: AssemblyVersion("1.0.*")]
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
36 |
--------------------------------------------------------------------------------
/src/Server/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("Microsoft.AspNet.WebApi.Extensions.Compression.Server")]
8 | [assembly: AssemblyDescription("Module for ASP.NET WebApi that enables GZip and Deflate support for incoming and outgoing requests")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("EyeCatch")]
11 | [assembly: AssemblyProduct("Microsoft.AspNet.WebApi.Extensions.Compression.Server")]
12 | [assembly: AssemblyCopyright("Copyright © EyeCatch 2016")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Setting ComVisible to false makes the types in this assembly not visible
17 | // to COM components. If you need to access a type in this assembly from
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 |
21 | // The following GUID is for the ID of the typelib if this project is exposed to COM
22 | [assembly: Guid("ee709c23-849d-43c5-9f47-0b8d8ddb43d8")]
23 |
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | // Major Version
27 | // Minor Version
28 | // Build Number
29 | // Revision
30 | //
31 | // You can specify all the values or you can default the Build and Revision Numbers
32 | // by using the '*' as shown below:
33 | // [assembly: AssemblyVersion("1.0.*")]
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
36 |
--------------------------------------------------------------------------------
/src/Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/Core/HttpContentOperations.cs:
--------------------------------------------------------------------------------
1 | namespace System.Net.Http.Extensions.Compression.Core
2 | {
3 | using System.IO;
4 | using System.Net.Http;
5 | using System.Net.Http.Extensions.Compression.Core.Extensions;
6 | using System.Net.Http.Extensions.Compression.Core.Interfaces;
7 | using System.Threading.Tasks;
8 |
9 | ///
10 | /// Helper methods for operating on instances.
11 | ///
12 | public class HttpContentOperations
13 | {
14 | ///
15 | /// Decompresses the compressed HTTP content.
16 | ///
17 | /// The compressed HTTP content.
18 | /// The compressor.
19 | /// The decompressed content.
20 | public async Task DecompressContent(HttpContent compressedContent, ICompressor compressor)
21 | {
22 | var decompressedContentStream = new MemoryStream();
23 |
24 | // Decompress buffered content
25 | using (var ms = new MemoryStream(await compressedContent.ReadAsByteArrayAsync()))
26 | {
27 | await compressor.Decompress(ms, decompressedContentStream).ConfigureAwait(false);
28 | }
29 |
30 | // Set position back to 0 so it can be read again
31 | decompressedContentStream.Position = 0;
32 |
33 | var decompressedContent = new StreamContent(decompressedContentStream);
34 |
35 | // Copy content headers so we know what got sent back
36 | compressedContent.Headers.CopyTo(decompressedContent.Headers);
37 |
38 | return decompressedContent;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/dist/nuget/Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin
5 | 2.0.0
6 | OWIN support for Microsoft.AspNet.WebApi.Extensions.Compression.Server
7 | Ove Andersen
8 | EyeCatch
9 | Package for supporting OWIN when using Microsoft ASP.NET Web API Compression Support
10 | Package for supporting OWIN when using Microsoft ASP.NET Web API Compression Support.
11 | en-US
12 | https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression
13 | http://www.eyecatch.no/favicon.ico
14 | false
15 | http://www.eyecatch.no/licenses/apache-20/
16 | Copyright EyeCatch 2016
17 |
18 |
19 |
20 |
21 |
22 | aspnet webapi aspnetwebapi http compression gzip deflate eyecatch
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/Tests/Extensions/LongExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Extensions
2 | {
3 | using System;
4 |
5 | internal static class LongExtensions
6 | {
7 | ///
8 | /// Gets the size as a human readable string.
9 | ///
10 | /// The byte array.
11 | /// The size as a human readable string.
12 | public static string SizeAsHumanReadableString(this long input, SIType siType)
13 | {
14 | if (siType == SIType.Byte)
15 | {
16 | // Larger or equal to 1KB but lesser than 1MB
17 | if (input >= 1024 && input < 1048576)
18 | {
19 | return string.Format("{0}KB", input / 1024);
20 | }
21 |
22 | // Larger or equal to 1MB but lesser than 1GB
23 | if (input >= 1048576 && input < 1073741824)
24 | {
25 | return string.Format("{0}MB", input / 1024 / 1024);
26 | }
27 |
28 | // Larger or equal to 1Gt but lesser than 1TB
29 | if (input >= 1073741824 && input < 1099511627776)
30 | {
31 | return string.Format("{0}GB", input / 1024 / 1024 / 1024);
32 | }
33 |
34 | return string.Format("{0}bytes", input);
35 | }
36 |
37 | throw new NotImplementedException();
38 | }
39 |
40 | ///
41 | /// Enumeration for the Internation System of Units (SI).
42 | ///
43 | public enum SIType
44 | {
45 | ///
46 | /// The byte unit type (B, kB, MB, GB, TB, etc.)
47 | ///
48 | Byte
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/dist/nuget/Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin.StrongName.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin.StrongName
5 | 2.0.0
6 | OWIN support for Microsoft.AspNet.WebApi.Extensions.Compression.Server.StrongName
7 | Ove Andersen
8 | EyeCatch
9 | Package for supporting OWIN when using Microsoft ASP.NET Web API Compression Support
10 | Package for supporting OWIN when using Microsoft ASP.NET Web API Compression Support.
11 | en-US
12 | https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression
13 | http://www.eyecatch.no/favicon.ico
14 | false
15 | http://www.eyecatch.no/licenses/apache-20/
16 | Copyright EyeCatch 2016
17 |
18 |
19 |
20 |
21 |
22 | aspnet webapi aspnetwebapi http compression gzip deflate eyecatch
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/Tests/Extensions/HttpResponseMessageExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Extensions
2 | {
3 | using Newtonsoft.Json;
4 | using System.Net.Http;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | public static class HttpResponseMessageExtensions
9 | {
10 | public static async Task ToTestString(this HttpResponseMessage response)
11 | {
12 | var sb = new StringBuilder();
13 |
14 | sb.AppendLine();
15 | sb.AppendLine($"Response Code: {(int)response.StatusCode} {response.StatusCode}");
16 | sb.AppendLine();
17 | sb.AppendLine("Headers:");
18 |
19 | foreach (var header in response.Headers)
20 | {
21 | sb.AppendLine($" {header.Key}: {string.Join(", ", header.Value)}");
22 | }
23 |
24 | if (response.Content != null)
25 | {
26 | foreach (var header in response.Content.Headers)
27 | {
28 | sb.AppendLine($" {header.Key}: {string.Join(", ", header.Value)}");
29 | }
30 |
31 | sb.AppendLine();
32 | sb.AppendLine("Content:");
33 |
34 | if (response.Content.Headers.ContentType?.MediaType == "application/json")
35 | {
36 | sb.AppendLine(
37 | JsonConvert.SerializeObject(
38 | JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()),
39 | Formatting.Indented));
40 | }
41 | else
42 | {
43 | sb.AppendLine(await response.Content.ReadAsStringAsync());
44 | }
45 |
46 | sb.AppendLine();
47 | }
48 |
49 | return sb.ToString();
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/src/Tests/web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/Core/Compressors/GZipCompressor.cs:
--------------------------------------------------------------------------------
1 | namespace System.Net.Http.Extensions.Compression.Core.Compressors
2 | {
3 | using System.IO;
4 | using System.IO.Compression;
5 | using System.Net.Http.Extensions.Compression.Core.Interfaces;
6 |
7 | ///
8 | /// Compressor for handling gzip encodings.
9 | ///
10 | public class GZipCompressor : BaseCompressor
11 | {
12 | /// Initializes a new instance of the class.
13 | public GZipCompressor()
14 | {
15 | }
16 |
17 | /// Initializes a new instance of the class.
18 | /// Manager for stream.
19 | public GZipCompressor(IStreamManager streamManager)
20 | : base(streamManager)
21 | {
22 | }
23 |
24 | ///
25 | /// Gets the encoding type.
26 | ///
27 | /// The encoding type.
28 | public override string EncodingType
29 | {
30 | get { return "gzip"; }
31 | }
32 |
33 | ///
34 | /// Creates the compression stream.
35 | ///
36 | /// The output stream.
37 | /// The compressed stream.
38 | public override Stream CreateCompressionStream(Stream output)
39 | {
40 | return new GZipStream(output, CompressionMode.Compress, true);
41 | }
42 |
43 | ///
44 | /// Creates the decompression stream.
45 | ///
46 | /// The input stream.
47 | /// The decompressed stream.
48 | public override Stream CreateDecompressionStream(Stream input)
49 | {
50 | return new GZipStream(input, CompressionMode.Decompress, true);
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/src/Core/Compressors/DeflateCompressor.cs:
--------------------------------------------------------------------------------
1 | namespace System.Net.Http.Extensions.Compression.Core.Compressors
2 | {
3 | using System.IO;
4 | using System.IO.Compression;
5 | using System.Net.Http.Extensions.Compression.Core.Interfaces;
6 |
7 | ///
8 | /// Compressor for handling deflate encodings.
9 | ///
10 | public class DeflateCompressor : BaseCompressor
11 | {
12 | ///
13 | /// Initializes a new instance of the class.
14 | ///
15 | public DeflateCompressor()
16 | {
17 | }
18 |
19 | ///
20 | /// Initializes a new instance of the class.
21 | ///
22 | /// Manager for stream.
23 | public DeflateCompressor(IStreamManager streamManager)
24 | : base(streamManager)
25 | {
26 | }
27 |
28 | ///
29 | /// Gets the encoding type.
30 | ///
31 | /// The encoding type.
32 | public override string EncodingType
33 | {
34 | get { return "deflate"; }
35 | }
36 |
37 | ///
38 | /// Creates the compression stream.
39 | ///
40 | /// The output stream.
41 | /// The compressed stream.
42 | public override Stream CreateCompressionStream(Stream output)
43 | {
44 | return new DeflateStream(output, CompressionMode.Compress, true);
45 | }
46 |
47 | ///
48 | /// Creates the decompression stream.
49 | ///
50 | /// The input stream.
51 | /// The decompressed stream.
52 | public override Stream CreateDecompressionStream(Stream input)
53 | {
54 | return new DeflateStream(input, CompressionMode.Decompress, true);
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/src/Core/Extensions/HttpContentHeaderExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace System.Net.Http.Extensions.Compression.Core.Extensions
2 | {
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Net.Http.Headers;
6 |
7 | public static class HttpContentHeaderExtensions
8 | {
9 | /// Copies all headers from the source to the target.
10 | /// The source.
11 | /// The target.
12 | /// true to handle content length.
13 | /// true to handle changed values.
14 | public static void CopyTo(
15 | this HttpContentHeaders source,
16 | HttpContentHeaders target,
17 | bool handleContentLength = true,
18 | bool handleChangedValues = false)
19 | {
20 | // Copy all other headers unless they have been modified and we want to preserve that
21 | foreach (var header in source)
22 | {
23 | try
24 | {
25 | if (!handleContentLength && header.Key.Equals("Content-Length", StringComparison.OrdinalIgnoreCase))
26 | {
27 | continue;
28 | }
29 |
30 | if (!handleChangedValues)
31 | {
32 | // If values have changed, dont update it
33 | if (target.Contains(header.Key))
34 | {
35 | if (target.GetValues(header.Key).Any(targetValue => header.Value.Any(originalValue => originalValue != targetValue)))
36 | {
37 | continue;
38 | }
39 | }
40 | }
41 |
42 | target.Add(header.Key, header.Value);
43 | }
44 | catch (Exception ex)
45 | {
46 | Debug.WriteLine(ex);
47 | }
48 | }
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/src/Tests/Tests/Integration/CompressionHandlerWithoutThresholdTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Tests.Integration
2 | {
3 | using global::Tests.Tests.Common;
4 | using Microsoft.AspNet.WebApi.Extensions.Compression.Server;
5 | using NUnit.Framework;
6 | using System.Net.Http;
7 | using System.Net.Http.Extensions.Compression.Client;
8 | using System.Net.Http.Extensions.Compression.Core;
9 | using System.Net.Http.Extensions.Compression.Core.Compressors;
10 | using System.Net.Http.Headers;
11 | using System.Web.Http;
12 |
13 | [TestFixture]
14 | public class CompressionHandlerWithoutThresholdTests : TestFixture
15 | {
16 | private HttpServer server;
17 |
18 | [TestFixtureSetUp]
19 | public void TestFixtureSetUp()
20 | {
21 | var config = new HttpConfiguration();
22 |
23 | config.MapHttpAttributeRoutes();
24 |
25 | config.Routes.MapHttpRoute(
26 | name: "DefaultApi",
27 | routeTemplate: "api/{controller}/{id}",
28 | defaults: new { id = RouteParameter.Optional });
29 |
30 | config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
31 |
32 | config.MessageHandlers.Insert(0, new ServerCompressionHandler(0, new GZipCompressor(StreamManager.Instance), new DeflateCompressor(StreamManager.Instance)));
33 |
34 | this.server = new HttpServer(config);
35 | }
36 |
37 | [SetUp]
38 | public void SetUp()
39 | {
40 | var client = new HttpClient(new ClientCompressionHandler(this.server, 0, new GZipCompressor(), new DeflateCompressor()));
41 | client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
42 | client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
43 |
44 | this.Client = client;
45 | }
46 |
47 | [TestFixtureTearDown]
48 | public void TestFixtureTearDown()
49 | {
50 | if (this.server != null)
51 | {
52 | this.server.Dispose();
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/dist/nuget/Microsoft.AspNet.WebApi.Extensions.Compression.Server.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Microsoft.AspNet.WebApi.Extensions.Compression.Server
5 | 2.0.0
6 | Microsoft ASP.NET Web API Compression Support
7 | Ove Andersen
8 | EyeCatch
9 |
10 | Module for ASP.NET Web API that enables GZip and Deflate support for incoming and outgoing requests.
11 | Please note that this is not an official Microsoft package.
12 |
13 |
14 | Module for ASP.NET Web API that enables GZip and Deflate support for incoming and outgoing requests. Please note that this is not an official Microsoft package.
15 |
16 | en-US
17 | https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression
18 | http://www.eyecatch.no/favicon.ico
19 | false
20 | http://www.eyecatch.no/licenses/apache-20/
21 | Copyright EyeCatch 2016
22 |
23 |
24 |
25 |
26 |
27 | aspnet webapi aspnetwebapi http compression gzip deflate eyecatch
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/dist/nuget/Microsoft.AspNet.WebApi.Extensions.Compression.Server.StrongName.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Microsoft.AspNet.WebApi.Extensions.Compression.Server.StrongName
5 | 2.0.0
6 | Microsoft ASP.NET Web API Compression Support
7 | Ove Andersen
8 | EyeCatch
9 |
10 | Module for ASP.NET Web API that enables GZip and Deflate support for incoming and outgoing requests.
11 | Please note that this is not an official Microsoft package.
12 |
13 |
14 | Module for ASP.NET Web API that enables GZip and Deflate support for incoming and outgoing requests. Please note that this is not an official Microsoft package.
15 |
16 | en-US
17 | https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression
18 | http://www.eyecatch.no/favicon.ico
19 | false
20 | http://www.eyecatch.no/licenses/apache-20/
21 | Copyright EyeCatch 2016
22 |
23 |
24 |
25 |
26 |
27 | aspnet webapi aspnetwebapi http compression gzip deflate eyecatch
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/dist/nuget/System.Net.Http.Extensions.Compression.Client.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | System.Net.Http.Extensions.Compression.Client
5 | 2.0.0
6 | Microsoft HTTP Client Compression Support
7 | Ove Andersen
8 | EyeCatch
9 |
10 | Module for Microsoft HTTP Client that enables GZip and Deflate support for incoming and outgoing requests.
11 | Please note that this is not an official Microsoft package.
12 |
13 |
14 | Module for Microsoft HTTP Client that enables GZip and Deflate support for incoming and outgoing requests. Please note that this is not an official Microsoft package.
15 |
16 | en-US
17 | https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression
18 | http://www.eyecatch.no/favicon.ico
19 | false
20 | http://www.eyecatch.no/licenses/apache-20/
21 | Copyright EyeCatch 2016
22 |
23 |
24 | aspnet webapi aspnetwebapi http compression gzip deflate eyecatch
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/dist/nuget/System.Net.Http.Extensions.Compression.Client.StrongName.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | System.Net.Http.Extensions.Compression.Client.StrongName
5 | 2.0.0
6 | Microsoft HTTP Client Compression Support
7 | Ove Andersen
8 | EyeCatch
9 |
10 | Module for Microsoft HTTP Client that enables GZip and Deflate support for incoming and outgoing requests.
11 | Please note that this is not an official Microsoft package.
12 |
13 |
14 | Module for Microsoft HTTP Client that enables GZip and Deflate support for incoming and outgoing requests. Please note that this is not an official Microsoft package.
15 |
16 | en-US
17 | https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression
18 | http://www.eyecatch.no/favicon.ico
19 | false
20 | http://www.eyecatch.no/licenses/apache-20/
21 | Copyright EyeCatch 2016
22 |
23 |
24 | aspnet webapi aspnetwebapi http compression gzip deflate eyecatch
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/Tests/Tests/Integration/AcceptEncodingStarCompressionHandlerWithThresholdTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Tests.Integration
2 | {
3 | using global::Tests.Extensions;
4 | using global::Tests.Tests.Common;
5 |
6 | using Microsoft.AspNet.WebApi.Extensions.Compression.Server;
7 | using NUnit.Framework;
8 | using System;
9 | using System.Net.Http;
10 | using System.Net.Http.Extensions.Compression.Client;
11 | using System.Net.Http.Extensions.Compression.Core;
12 | using System.Net.Http.Extensions.Compression.Core.Compressors;
13 | using System.Net.Http.Headers;
14 | using System.Web.Http;
15 |
16 | [TestFixture]
17 | public class AcceptEncodingStarCompressionHandlerWithThresholdTests
18 | {
19 | private HttpServer server;
20 |
21 | public HttpClient Client { get; set; }
22 |
23 | [TestFixtureSetUp]
24 | public void TestFixtureSetUp()
25 | {
26 | var config = new HttpConfiguration();
27 |
28 | config.MapHttpAttributeRoutes();
29 |
30 | config.Routes.MapHttpRoute(
31 | name: "DefaultApi",
32 | routeTemplate: "api/{controller}/{id}",
33 | defaults: new { id = RouteParameter.Optional });
34 |
35 | config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
36 |
37 | config.MessageHandlers.Insert(0, new ServerCompressionHandler(4096, new GZipCompressor(StreamManager.Instance), new DeflateCompressor(StreamManager.Instance)));
38 |
39 | this.server = new HttpServer(config);
40 | }
41 |
42 | [SetUp]
43 | public void SetUp()
44 | {
45 | var client = new HttpClient(new ClientCompressionHandler(this.server, 0, new GZipCompressor(), new DeflateCompressor()));
46 | client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("*"));
47 |
48 | this.Client = client;
49 | }
50 |
51 | [TestFixtureTearDown]
52 | public void TestFixtureTearDown()
53 | {
54 | if (this.server != null)
55 | {
56 | this.server.Dispose();
57 | }
58 | }
59 |
60 | [Test]
61 | public async void Get_WhenResponseSizeIsLessThanTreshold_ShouldReturnUncompressedContent()
62 | {
63 | var response = await this.Client.GetAsync("http://localhost:55399/api/test");
64 |
65 | var content = await response.Content.ReadAsStringAsync();
66 |
67 | Console.Write(await response.ToTestString());
68 |
69 | Assert.IsTrue(response.IsSuccessStatusCode);
70 | Assert.AreEqual(response.Content.Headers.ContentLength, content.Length);
71 | Assert.IsFalse(response.Content.Headers.ContentEncoding.Contains("gzip"));
72 | }
73 |
74 | [Test]
75 | public async void Get_WhenResponseSizeIsLargerThanTreshold_ShouldReturnCompressedContent()
76 | {
77 | var response = await this.Client.GetAsync("http://localhost:55399/api/file/image");
78 |
79 | var content = await response.Content.ReadAsStringAsync();
80 |
81 | Console.Write(await response.ToTestString());
82 |
83 | Assert.IsTrue(response.IsSuccessStatusCode);
84 | Assert.AreNotEqual(response.Content.Headers.ContentLength, content.Length);
85 | Assert.IsTrue(response.Content.Headers.ContentEncoding.Contains("gzip"));
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/Tests/Tests/Integration/CompressionHandlerWithThresholdTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Tests.Integration
2 | {
3 | using global::Tests.Extensions;
4 | using global::Tests.Tests.Common;
5 |
6 | using Microsoft.AspNet.WebApi.Extensions.Compression.Server;
7 | using NUnit.Framework;
8 | using System;
9 | using System.Net.Http;
10 | using System.Net.Http.Extensions.Compression.Client;
11 | using System.Net.Http.Extensions.Compression.Core;
12 | using System.Net.Http.Extensions.Compression.Core.Compressors;
13 | using System.Net.Http.Headers;
14 | using System.Web.Http;
15 |
16 | [TestFixture]
17 | public class CompressionHandlerWithThresholdTests
18 | {
19 | private HttpServer server;
20 |
21 | public HttpClient Client { get; set; }
22 |
23 | [TestFixtureSetUp]
24 | public void TestFixtureSetUp()
25 | {
26 | var config = new HttpConfiguration();
27 |
28 | config.MapHttpAttributeRoutes();
29 |
30 | config.Routes.MapHttpRoute(
31 | name: "DefaultApi",
32 | routeTemplate: "api/{controller}/{id}",
33 | defaults: new { id = RouteParameter.Optional });
34 |
35 | config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
36 |
37 | config.MessageHandlers.Insert(0, new ServerCompressionHandler(4096, new GZipCompressor(StreamManager.Instance), new DeflateCompressor(StreamManager.Instance)));
38 |
39 | this.server = new HttpServer(config);
40 | }
41 |
42 | [SetUp]
43 | public void SetUp()
44 | {
45 | var client = new HttpClient(new ClientCompressionHandler(this.server, 0, new GZipCompressor(), new DeflateCompressor()));
46 | client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
47 | client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
48 |
49 | this.Client = client;
50 | }
51 |
52 | [TestFixtureTearDown]
53 | public void TestFixtureTearDown()
54 | {
55 | if (this.server != null)
56 | {
57 | this.server.Dispose();
58 | }
59 | }
60 |
61 | [Test]
62 | public async void Get_WhenResponseSizeIsLessThanTreshold_ShouldReturnUncompressedContent()
63 | {
64 | var response = await this.Client.GetAsync("http://localhost:55399/api/test");
65 |
66 | var content = await response.Content.ReadAsStringAsync();
67 |
68 | Console.Write(await response.ToTestString());
69 |
70 | Assert.IsTrue(response.IsSuccessStatusCode);
71 | Assert.AreEqual(response.Content.Headers.ContentLength, content.Length);
72 | Assert.IsFalse(response.Content.Headers.ContentEncoding.Contains("gzip"));
73 | }
74 |
75 | [Test]
76 | public async void Get_WhenResponseSizeIsLargerThanTreshold_ShouldReturnCompressedContent()
77 | {
78 | var response = await this.Client.GetAsync("http://localhost:55399/api/file/image");
79 |
80 | var content = await response.Content.ReadAsStringAsync();
81 |
82 | Console.Write(await response.ToTestString());
83 |
84 | Assert.IsTrue(response.IsSuccessStatusCode);
85 | Assert.AreNotEqual(response.Content.Headers.ContentLength, content.Length);
86 | Assert.IsTrue(response.Content.Headers.ContentEncoding.Contains("gzip"));
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 | [Dd]ebug/
11 | [Dd]ebugPublic/
12 | [Rr]elease/
13 | x64/
14 | build/
15 | bld/
16 | [Bb]in/
17 | [Oo]bj/
18 |
19 | # MSTest test Results
20 | [Tt]est[Rr]esult*/
21 | [Bb]uild[Ll]og.*
22 |
23 | #NUNIT
24 | *.VisualState.xml
25 | TestResult.xml
26 |
27 | # Build Results of an ATL Project
28 | [Dd]ebugPS/
29 | [Rr]eleasePS/
30 | dlldata.c
31 |
32 | *_i.c
33 | *_p.c
34 | *_i.h
35 | *.ilk
36 | *.meta
37 | *.obj
38 | *.pch
39 | *.pdb
40 | *.pgc
41 | *.pgd
42 | *.rsp
43 | *.sbr
44 | *.tlb
45 | *.tli
46 | *.tlh
47 | *.tmp
48 | *.tmp_proj
49 | *.log
50 | *.vspscc
51 | *.vssscc
52 | .builds
53 | *.pidb
54 | *.svclog
55 | *.scc
56 |
57 | # Chutzpah Test files
58 | _Chutzpah*
59 |
60 | # Visual C++ cache files
61 | ipch/
62 | *.aps
63 | *.ncb
64 | *.opensdf
65 | *.sdf
66 | *.cachefile
67 |
68 | # Visual Studio profiler
69 | *.psess
70 | *.vsp
71 | *.vspx
72 |
73 | # TFS 2012 Local Workspace
74 | $tf/
75 |
76 | # Guidance Automation Toolkit
77 | *.gpState
78 |
79 | # ReSharper is a .NET coding add-in
80 | _ReSharper*/
81 | *.[Rr]e[Ss]harper
82 | *.DotSettings.user
83 |
84 | # JustCode is a .NET coding addin-in
85 | .JustCode
86 |
87 | # TeamCity is a build add-in
88 | _TeamCity*
89 |
90 | # DotCover is a Code Coverage Tool
91 | *.dotCover
92 |
93 | # NCrunch
94 | *.ncrunch*
95 | _NCrunch_*
96 | .*crunch*.local.xml
97 |
98 | # MightyMoose
99 | *.mm.*
100 | AutoTest.Net/
101 |
102 | # Web workbench (sass)
103 | .sass-cache/
104 |
105 | # Installshield output folder
106 | [Ee]xpress/
107 |
108 | # DocProject is a documentation generator add-in
109 | DocProject/buildhelp/
110 | DocProject/Help/*.HxT
111 | DocProject/Help/*.HxC
112 | DocProject/Help/*.hhc
113 | DocProject/Help/*.hhk
114 | DocProject/Help/*.hhp
115 | DocProject/Help/Html2
116 | DocProject/Help/html
117 |
118 | # Click-Once directory
119 | publish/
120 |
121 | # Publish Web Output
122 | *.[Pp]ublish.xml
123 | *.azurePubxml
124 |
125 | # NuGet Packages Directory
126 | packages/
127 | ## TODO: If the tool you use requires repositories.config uncomment the next line
128 | #!packages/repositories.config
129 |
130 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
131 | # This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented)
132 | !packages/build/
133 |
134 | # Windows Azure Build Output
135 | csx/
136 | *.build.csdef
137 |
138 | # Windows Store app package directory
139 | AppPackages/
140 |
141 | # Others
142 | sql/
143 | *.Cache
144 | ClientBin/
145 | [Ss]tyle[Cc]op.*
146 | ~$*
147 | *~
148 | *.dbmdl
149 | *.dbproj.schemaview
150 | *.pfx
151 | *.publishsettings
152 | node_modules/
153 |
154 | # RIA/Silverlight projects
155 | Generated_Code/
156 |
157 | # Backup & report files from converting an old project file to a newer
158 | # Visual Studio version. Backup files are not needed, because we have git ;-)
159 | _UpgradeReport_Files/
160 | Backup*/
161 | UpgradeLog*.XML
162 | UpgradeLog*.htm
163 |
164 | # SQL Server files
165 | *.mdf
166 | *.ldf
167 |
168 | # Business Intelligence projects
169 | *.rdl.data
170 | *.bim.layout
171 | *.bim_*.settings
172 |
173 | # Microsoft Fakes
174 | FakesAssemblies/
175 | src/NuGetPackage/*.nupkg
176 | src/NuGetPackage/lib/
177 | src/NuGetPackage/src/
178 | *.nupkg
179 |
--------------------------------------------------------------------------------
/src/Tests/Tests/Facade/OwinHostTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Tests.Facade
2 | {
3 | using System;
4 | using System.Net.Http;
5 | using System.Net.Http.Extensions.Compression.Client;
6 | using System.Net.Http.Extensions.Compression.Core.Compressors;
7 | using System.Net.Http.Headers;
8 | using System.Text;
9 | using System.Web.Http;
10 |
11 | using global::Tests.Extensions;
12 | using global::Tests.Handlers;
13 | using global::Tests.Models;
14 | using global::Tests.Tests.Common;
15 |
16 | using Microsoft.AspNet.Identity;
17 | using Microsoft.AspNet.WebApi.Extensions.Compression.Server;
18 | using Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin;
19 | using Microsoft.Owin;
20 | using Microsoft.Owin.Security.Cookies;
21 | using Microsoft.Owin.Testing;
22 |
23 | using Newtonsoft.Json;
24 |
25 | using NUnit.Framework;
26 |
27 | using Owin;
28 |
29 | [TestFixture]
30 | public class OwinHostTests : TestFixture
31 | {
32 | private TestServer server;
33 |
34 | [TestFixtureSetUp]
35 | public void TestFixtureSetup()
36 | {
37 | this.server = TestServer.Create();
38 | }
39 |
40 | [SetUp]
41 | public void SetUp()
42 | {
43 | var client = new HttpClient(new TraceMessageHandler(new ClientCompressionHandler(this.server.Handler, new GZipCompressor(), new DeflateCompressor())))
44 | {
45 | BaseAddress = new Uri("http://localhost:55399")
46 | };
47 |
48 | client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
49 | client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
50 |
51 | this.Client = client;
52 | }
53 |
54 | [TestFixtureTearDown]
55 | public void TestFixtureTearDown()
56 | {
57 | this.server.Dispose();
58 | }
59 |
60 | [Test]
61 | public async void Post_WhenHeaderIsModifiedOnServer_ShouldReturnModifiedHeader()
62 | {
63 | var loginModel = new LoginModel("Test", "Test", "http://localhost:55399/api/test");
64 | var response = await this.Client.PostAsync("http://localhost:55399/api/test/login", new StringContent(JsonConvert.SerializeObject(loginModel), Encoding.UTF8, "application/json"));
65 |
66 | Console.Write(await response.ToTestString());
67 |
68 | Assert.AreEqual(loginModel.ReturnUrl, response.Headers.Location.ToString());
69 | }
70 |
71 | public class OwinStartup
72 | {
73 | public void Configuration(IAppBuilder appBuilder)
74 | {
75 | var config = new HttpConfiguration();
76 | config.MapHttpAttributeRoutes();
77 | config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional });
78 |
79 | // Add compression message handler
80 | config.MessageHandlers.Insert(0, new OwinServerCompressionHandler(0, new GZipCompressor(), new DeflateCompressor()));
81 |
82 | appBuilder.UseCookieAuthentication(
83 | new CookieAuthenticationOptions()
84 | {
85 | AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
86 | LoginPath = new PathString("/api/test/login")
87 | });
88 |
89 | appBuilder.UseWebApi(config);
90 | }
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/src/Tests/Handlers/TraceMessageHandler.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Handlers
2 | {
3 | using System;
4 | using System.Diagnostics;
5 | using System.Net.Http;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | using global::Tests.Extensions;
10 |
11 | public class TraceMessageHandler : DelegatingHandler
12 | {
13 | ///
14 | /// Initializes a new instance of the class.
15 | ///
16 | public TraceMessageHandler()
17 | : this(new HttpClientHandler())
18 | {
19 | }
20 |
21 | ///
22 | /// Initializes a new instance of the class.
23 | ///
24 | /// The inner handler.
25 | public TraceMessageHandler(HttpMessageHandler innerHandler)
26 | {
27 | this.InnerHandler = innerHandler;
28 | }
29 |
30 | ///
31 | /// Sends an HTTP request to the inner handler to send to the server as an asynchronous operation.
32 | ///
33 | /// The HTTP request message to send to the server.
34 | /// A cancellation token to cancel operation.
35 | /// Returns . The task object representing the asynchronous operation.
36 | protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
37 | {
38 | var startTime = DateTime.Now;
39 |
40 | var requestMessage = string.Format("Request: {0} {1}", request.Method, request.RequestUri);
41 | Trace.TraceInformation(requestMessage);
42 |
43 | // Try to read out the request content
44 | if (request.Content != null)
45 | {
46 | await request.Content.LoadIntoBufferAsync();
47 |
48 | Trace.TraceInformation("Request Body: {0}", await request.Content.ReadAsStringAsync());
49 | }
50 |
51 | var response = await base.SendAsync(request, cancellationToken);
52 |
53 | var responseMessage = string.Format(
54 | "Response: {0} {1} - {{ Time: {2}, Size: {3} }}",
55 | (int)response.StatusCode,
56 | response.ReasonPhrase,
57 | DateTime.Now.Subtract(startTime).AsHumanReadableString(),
58 | response.Content != null ? response.Content.SizeAsHumanReadableString() : "0");
59 |
60 | // Try to read out the response content
61 | if (response.Content != null)
62 | {
63 | await response.Content.LoadIntoBufferAsync();
64 | }
65 |
66 | if (!response.IsSuccessStatusCode)
67 | {
68 | Trace.TraceError(responseMessage);
69 |
70 | if (response.Content != null)
71 | {
72 | Trace.TraceError(string.Format("Response Body: {0}", await response.Content.ReadAsStringAsync()));
73 | }
74 | }
75 | else
76 | {
77 | Trace.TraceInformation(responseMessage);
78 |
79 | if (response.Content != null)
80 | {
81 | Trace.TraceInformation("Response Body: {0}", await response.Content.ReadAsStringAsync());
82 | }
83 | }
84 |
85 | return response;
86 | }
87 | }
88 | }
--------------------------------------------------------------------------------
/src/Client/Client.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 10.0
6 | Debug
7 | AnyCPU
8 | {56E19FF7-9AC7-48C5-9AC2-105F55AA16E1}
9 | Library
10 | Properties
11 | System.Net.Http.Extensions.Compression.Client
12 | System.Net.Http.Extensions.Compression.Client
13 | en-US
14 | 512
15 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
16 | Profile111
17 | v4.5
18 |
19 |
20 |
21 |
22 | true
23 | full
24 | false
25 | bin\Debug\
26 | DEBUG;TRACE
27 | prompt
28 | 4
29 |
30 |
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 |
38 |
39 | true
40 | bin\Test\
41 | DEBUG;TRACE
42 | full
43 | AnyCPU
44 | prompt
45 | MinimumRecommendedRules.ruleset
46 |
47 |
48 | true
49 | bin\Staging\
50 | DEBUG;TRACE
51 | full
52 | AnyCPU
53 | prompt
54 | MinimumRecommendedRules.ruleset
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | {b7534554-ab6c-44ac-bf34-424dbe596216}
63 | Core
64 |
65 |
66 |
67 |
74 |
--------------------------------------------------------------------------------
/src/Tests/Controllers/TestController.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Controllers
2 | {
3 | using global::Tests.Models;
4 | using Microsoft.AspNet.Identity;
5 | using Microsoft.Owin.Security;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Net;
9 | using System.Net.Http;
10 | using System.Security.Claims;
11 | using System.Threading.Tasks;
12 | using System.Web.Http;
13 |
14 | public class TestController : ApiController
15 | {
16 | private IAuthenticationManager Authentication => this.Request.GetOwinContext().Authentication;
17 |
18 | public async Task Get()
19 | {
20 | return this.Request.CreateResponse(new TestModel("Get()"));
21 | }
22 |
23 | [Route("api/test/customheader")]
24 | public async Task GetCustomHeader()
25 | {
26 | var response = this.Request.CreateResponse(new TestModel("Get()"));
27 | response.Headers.Add("DataServiceVersion", "3.0");
28 |
29 | return response;
30 | }
31 |
32 | [Route("api/test/customcontentencoding")]
33 | public async Task GetCustomContentEncoding()
34 | {
35 | var response = this.Request.CreateResponse(new TestModel("Get()"));
36 | response.Content.Headers.ContentEncoding.Add("lol");
37 |
38 | return response;
39 | }
40 |
41 | [Route("api/test/redirect")]
42 | public async Task GetRedirect()
43 | {
44 | var response = this.Request.CreateResponse(HttpStatusCode.Redirect);
45 | response.Content = new ByteArrayContent(new byte[1024]);
46 | response.Content.Headers.ContentLength = 1024;
47 | response.Headers.Location = new Uri($"{this.Request.RequestUri.Scheme}://{this.Request.RequestUri.Authority}/api/test");
48 |
49 | return response;
50 | }
51 |
52 | public async Task Get(string id)
53 | {
54 | return this.Request.CreateResponse(new TestModel("Get(" + id + ")"));
55 | }
56 |
57 | [HttpPost]
58 | public async Task Post(TestModel m)
59 | {
60 | return this.Request.CreateResponse(m);
61 | }
62 |
63 | [HttpPost]
64 | [Route("api/test/login")]
65 | public async Task Login(LoginModel m)
66 | {
67 | if (m.Username == m.Password)
68 | {
69 | this.Authentication.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
70 | this.Authentication.SignIn(
71 | new AuthenticationProperties
72 | {
73 | IsPersistent = false,
74 | ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(1),
75 | RedirectUri = m.ReturnUrl
76 | },
77 | new ClaimsIdentity(new List() { new Claim(ClaimTypes.NameIdentifier, m.Username) }, DefaultAuthenticationTypes.ApplicationCookie));
78 |
79 | var response = this.Request.CreateResponse(HttpStatusCode.Redirect);
80 | response.Headers.Location = new Uri(m.ReturnUrl);
81 |
82 | return response;
83 | }
84 |
85 | return this.Request.CreateResponse(HttpStatusCode.Unauthorized);
86 | }
87 |
88 | [HttpPut]
89 | public async Task Put(string id, TestModel m)
90 | {
91 | return this.Request.CreateResponse(m);
92 | }
93 |
94 | [HttpDelete]
95 | public async Task Delete(string id)
96 | {
97 | return this.Request.CreateResponse();
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/Core/Compressors/BaseCompressor.cs:
--------------------------------------------------------------------------------
1 | namespace System.Net.Http.Extensions.Compression.Core.Compressors
2 | {
3 | using System.IO;
4 | using System.Net.Http.Extensions.Compression.Core.Interfaces;
5 | using System.Threading.Tasks;
6 |
7 | ///
8 | /// Base compressor for compressing streams.
9 | ///
10 | ///
11 | /// Based on the work by:
12 | /// Ben Foster (http://benfoster.io/blog/aspnet-web-api-compression)
13 | /// Kiran Challa (http://blogs.msdn.com/b/kiranchalla/archive/2012/09/04/handling-compression-accept-encoding-sample.aspx)
14 | ///
15 | public abstract class BaseCompressor : ICompressor
16 | {
17 | /// Manager for stream.
18 | private readonly IStreamManager streamManager;
19 |
20 | /// Initializes a new instance of the class.
21 | protected BaseCompressor()
22 | {
23 | this.streamManager = StreamManager.Instance;
24 | }
25 |
26 | /// Initializes a new instance of the class.
27 | /// The stream manager.
28 | protected BaseCompressor(IStreamManager streamManager)
29 | {
30 | this.streamManager = streamManager;
31 | }
32 |
33 | ///
34 | /// Gets the encoding type.
35 | ///
36 | /// The encoding type.
37 | public abstract string EncodingType { get; }
38 |
39 | ///
40 | /// Creates the compression stream.
41 | ///
42 | /// The output stream.
43 | /// The compressed stream.
44 | public abstract Stream CreateCompressionStream(Stream output);
45 |
46 | ///
47 | /// Creates the decompression stream.
48 | ///
49 | /// The input stream.
50 | /// The decompressed stream.
51 | public abstract Stream CreateDecompressionStream(Stream input);
52 |
53 | ///
54 | /// Compresses the specified source stream onto the destination stream.
55 | ///
56 | /// The source.
57 | /// The destination.
58 | /// An async void.
59 | public virtual async Task Compress(Stream source, Stream destination)
60 | {
61 | using (var mem = this.streamManager.GetStream())
62 | {
63 | using (var gzip = this.CreateCompressionStream(mem))
64 | {
65 | await source.CopyToAsync(gzip);
66 | }
67 |
68 | mem.Position = 0;
69 |
70 | await mem.CopyToAsync(destination);
71 |
72 | return mem.Length;
73 | }
74 | }
75 |
76 | ///
77 | /// Decompresses the specified source stream onto the destination stream.
78 | ///
79 | /// The source.
80 | /// The destination.
81 | /// An async void.
82 | public virtual async Task Decompress(Stream source, Stream destination)
83 | {
84 | var decompressed = this.CreateDecompressionStream(source);
85 |
86 | await this.Pump(decompressed, destination);
87 |
88 | decompressed.Dispose();
89 | }
90 |
91 | ///
92 | /// Copies the specified input stream onto the output stream.
93 | ///
94 | /// The input.
95 | /// The output.
96 | /// An async void.
97 | protected virtual async Task Pump(Stream input, Stream output)
98 | {
99 | await input.CopyToAsync(output);
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/Core/Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 10.0
6 | Debug
7 | AnyCPU
8 | {B7534554-AB6C-44AC-BF34-424DBE596216}
9 | Library
10 | Properties
11 | System.Net.Http.Extensions.Compression.Core
12 | System.Net.Http.Extensions.Compression.Core
13 | en-US
14 | 512
15 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
16 | Profile111
17 | v4.5
18 |
19 |
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 |
28 |
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 | true
38 | bin\Test\
39 | DEBUG;TRACE
40 | full
41 | AnyCPU
42 | prompt
43 | MinimumRecommendedRules.ruleset
44 |
45 |
46 | true
47 | bin\Staging\
48 | DEBUG;TRACE
49 | full
50 | AnyCPU
51 | prompt
52 | MinimumRecommendedRules.ruleset
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\System.Net.Http.dll
69 |
70 |
71 |
72 |
79 |
--------------------------------------------------------------------------------
/src/Client/Client.StrongName.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 10.0
6 | Debug
7 | AnyCPU
8 | {FF00D5E5-9581-4047-A5EE-CB968A567EE2}
9 | Library
10 | Properties
11 | System.Net.Http.Extensions.Compression.Client
12 | System.Net.Http.Extensions.Compression.Client
13 | en-US
14 | 512
15 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
16 | Profile111
17 | v4.5
18 |
19 |
20 |
21 |
22 | true
23 | full
24 | false
25 | bin\Debug.StrongName\
26 | DEBUG;TRACE
27 | prompt
28 | 4
29 |
30 |
31 | pdbonly
32 | true
33 | bin\Release.StrongName\
34 | TRACE
35 | prompt
36 | 4
37 |
38 |
39 | true
40 | bin\Test.StrongName\
41 | DEBUG;TRACE
42 | full
43 | AnyCPU
44 | prompt
45 | MinimumRecommendedRules.ruleset
46 |
47 |
48 | true
49 | bin\Staging.StrongName\
50 | DEBUG;TRACE
51 | full
52 | AnyCPU
53 | prompt
54 | MinimumRecommendedRules.ruleset
55 |
56 |
57 | true
58 |
59 |
60 | ..\StrongKey.snk
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | StrongKey.snk
69 |
70 |
71 |
72 |
73 | {2ef04e20-6cd8-420d-bac4-192ecd3f9ad5}
74 | Core.StrongName
75 |
76 |
77 |
78 |
85 |
--------------------------------------------------------------------------------
/src/Core/Models/CompressedContent.cs:
--------------------------------------------------------------------------------
1 | namespace System.Net.Http.Extensions.Compression.Core.Models
2 | {
3 | using System;
4 | using System.IO;
5 | using System.Net;
6 | using System.Net.Http;
7 | using System.Net.Http.Extensions.Compression.Core.Extensions;
8 | using System.Net.Http.Extensions.Compression.Core.Interfaces;
9 | using System.Threading.Tasks;
10 |
11 | ///
12 | /// Represents compressed HTTP content.
13 | ///
14 | public class CompressedContent : HttpContent
15 | {
16 | ///
17 | /// The original content
18 | ///
19 | private readonly HttpContent originalContent;
20 |
21 | ///
22 | /// The compressor
23 | ///
24 | private readonly ICompressor compressor;
25 |
26 | ///
27 | /// Initializes a new instance of the class.
28 | ///
29 | /// The content.
30 | /// The compressor.
31 | public CompressedContent(HttpContent content, ICompressor compressor)
32 | {
33 | if (content == null)
34 | {
35 | throw new ArgumentNullException(nameof(content));
36 | }
37 |
38 | if (compressor == null)
39 | {
40 | throw new ArgumentNullException(nameof(compressor));
41 | }
42 |
43 | this.originalContent = content;
44 | this.compressor = compressor;
45 |
46 | this.CopyHeaders();
47 | }
48 |
49 | ///
50 | /// Determines whether the HTTP content has a valid length in bytes.
51 | ///
52 | /// The length in bytes of the HTTP content.
53 | /// Returns .true if is a valid length; otherwise, false.
54 | protected override bool TryComputeLength(out long length)
55 | {
56 | length = -1;
57 |
58 | return false;
59 | }
60 |
61 | ///
62 | /// serialize to stream as an asynchronous operation.
63 | ///
64 | /// The target stream.
65 | /// Information about the transport (channel binding token, for example). This parameter may be null.
66 | /// Returns .The task object representing the asynchronous operation.
67 | protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
68 | {
69 | if (stream == null)
70 | {
71 | throw new ArgumentNullException(nameof(stream));
72 | }
73 |
74 | // Read and compress stream
75 | using (var ms = new MemoryStream(await this.originalContent.ReadAsByteArrayAsync()))
76 | {
77 | var compressedLength = await this.compressor.Compress(ms, stream).ConfigureAwait(false);
78 |
79 | // Content-Length: {size}
80 | this.Headers.ContentLength = compressedLength;
81 | }
82 | }
83 |
84 | ///
85 | /// Adds the headers.
86 | ///
87 | private void CopyHeaders()
88 | {
89 | this.originalContent.Headers.CopyTo(this.Headers, false);
90 |
91 | // Content-Encoding: {content-encodings}
92 | this.Headers.ContentEncoding.Add(this.compressor.EncodingType);
93 | }
94 |
95 | ///
96 | /// Releases the unmanaged resources used by the and optionally disposes of the managed resources.
97 | ///
98 | /// true to release both managed and unmanaged resources; false to releases only unmanaged resources.
99 | protected override void Dispose(bool disposing)
100 | {
101 | // Dispose original stream
102 | this.originalContent.Dispose();
103 |
104 | base.Dispose(disposing);
105 | }
106 | }
107 | }
--------------------------------------------------------------------------------
/src/Tests/Controllers/FileController.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Controllers
2 | {
3 | using global::Tests.Models;
4 | using iTextSharp.text;
5 | using iTextSharp.text.pdf;
6 | using Microsoft.AspNet.WebApi.Extensions.Compression.Server.Attributes;
7 | using System;
8 | using System.IO;
9 | using System.Net;
10 | using System.Net.Http;
11 | using System.Net.Http.Headers;
12 | using System.Threading.Tasks;
13 | using System.Web.Http;
14 |
15 | public class FileController : ApiController
16 | {
17 | [Route("api/file/image")]
18 | public async Task GetImage()
19 | {
20 | using (var ms = new MemoryStream())
21 | {
22 | var baseDir = Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).Parent;
23 | var filePath = baseDir.FullName + "/Content/Images/app-icon-1024.png";
24 |
25 | using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
26 | {
27 | fs.Position = 0;
28 | await fs.CopyToAsync(ms);
29 | }
30 |
31 | var result = new HttpResponseMessage(HttpStatusCode.OK)
32 | {
33 | Content = new ByteArrayContent(ms.ToArray())
34 | };
35 | result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
36 |
37 | return result;
38 | }
39 | }
40 |
41 | [Compression(Enabled = false)]
42 | [Route("api/file/uncompressedimage")]
43 | public async Task GetUncompressedImage()
44 | {
45 | using (var ms = new MemoryStream())
46 | {
47 | var baseDir = Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).Parent;
48 | var filePath = baseDir.FullName + "/Content/Images/app-icon-1024.png";
49 |
50 | using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
51 | {
52 | fs.Position = 0;
53 | await fs.CopyToAsync(ms);
54 | }
55 |
56 | var result = new HttpResponseMessage(HttpStatusCode.OK)
57 | {
58 | Content = new ByteArrayContent(ms.ToArray())
59 | };
60 | result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
61 |
62 | return result;
63 | }
64 | }
65 |
66 | [Route("api/file/pdf")]
67 | public async Task GetPdf()
68 | {
69 | var document = new Document(PageSize.A4);
70 | var pdfstream = new MemoryStream();
71 |
72 | document.SetMargins(document.LeftMargin, document.RightMargin, document.TopMargin, document.BottomMargin + 10f);
73 |
74 | var writer = PdfWriter.GetInstance(document, pdfstream);
75 | writer.PageEvent = new PdfLayout();
76 |
77 | // Write PDF document
78 | document.Open();
79 |
80 | var baseDir = Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).Parent;
81 |
82 | var logoHeader = Image.GetInstance(baseDir.FullName + "/Content/Images/app-icon-1024.png");
83 | logoHeader.ScalePercent(10);
84 | logoHeader.SetAbsolutePosition(document.PageSize.Width - logoHeader.ScaledWidth - document.RightMargin, document.PageSize.Height - document.TopMargin - logoHeader.ScaledHeight);
85 | document.Add(logoHeader);
86 |
87 | var headline = new Paragraph("Unicorns!");
88 |
89 | document.Add(headline);
90 |
91 | document.Add(new Paragraph(" "));
92 |
93 | document.Close();
94 |
95 | var result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StreamContent(new MemoryStream(pdfstream.ToArray())) };
96 |
97 | result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
98 | result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
99 | {
100 | FileName = "unicorns.pdf"
101 | };
102 |
103 | return result;
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/Core/Core.StrongName.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 10.0
6 | Debug
7 | AnyCPU
8 | {2EF04E20-6CD8-420D-BAC4-192ECD3F9AD5}
9 | Library
10 | Properties
11 | System.Net.Http.Extensions.Compression.Core
12 | System.Net.Http.Extensions.Compression.Core
13 | en-US
14 | 512
15 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
16 | Profile111
17 | v4.5
18 |
19 |
20 | true
21 | full
22 | false
23 | bin\Debug.StrongName\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 |
28 |
29 | pdbonly
30 | true
31 | bin\Release.StrongName\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 | true
38 | bin\Test.StrongName\
39 | DEBUG;TRACE
40 | full
41 | AnyCPU
42 | prompt
43 | MinimumRecommendedRules.ruleset
44 |
45 |
46 | true
47 | bin\Staging.StrongName\
48 | DEBUG;TRACE
49 | full
50 | AnyCPU
51 | prompt
52 | MinimumRecommendedRules.ruleset
53 |
54 |
55 | true
56 |
57 |
58 | ..\StrongKey.snk
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\System.Net.Http.dll
75 |
76 |
77 |
78 |
79 | StrongKey.snk
80 |
81 |
82 |
83 |
90 |
--------------------------------------------------------------------------------
/src/Server/Server.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {EE709C23-849D-43C5-9F47-0B8D8DDB43D8}
8 | Library
9 | Properties
10 | Microsoft.AspNet.WebApi.Extensions.Compression.Server
11 | Microsoft.AspNet.WebApi.Extensions.Compression.Server
12 | v4.5
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 | true
35 | bin\Test\
36 | DEBUG;TRACE
37 | full
38 | AnyCPU
39 | prompt
40 | MinimumRecommendedRules.ruleset
41 |
42 |
43 | true
44 | bin\Staging\
45 | DEBUG;TRACE
46 | full
47 | AnyCPU
48 | prompt
49 | MinimumRecommendedRules.ruleset
50 |
51 |
52 |
53 | ..\packages\Microsoft.IO.RecyclableMemoryStream.1.1.0.0\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll
54 | True
55 |
56 |
57 | ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll
58 | True
59 |
60 |
61 |
62 |
63 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
64 | True
65 |
66 |
67 | False
68 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | {B7534554-AB6C-44AC-BF34-424DBE596216}
91 | Core
92 |
93 |
94 |
95 |
102 |
--------------------------------------------------------------------------------
/src/Server/Server.StrongName.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {297AC86E-3B54-4E76-A4EA-A5BF1E730D6F}
8 | Library
9 | Properties
10 | Microsoft.AspNet.WebApi.Extensions.Compression.Server
11 | Microsoft.AspNet.WebApi.Extensions.Compression.Server
12 | v4.5
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug.StrongName\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release.StrongName\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 | true
35 | bin\Test.StrongName\
36 | DEBUG;TRACE
37 | full
38 | AnyCPU
39 | prompt
40 | MinimumRecommendedRules.ruleset
41 |
42 |
43 | true
44 | bin\Staging.StrongName\
45 | DEBUG;TRACE
46 | full
47 | AnyCPU
48 | prompt
49 | MinimumRecommendedRules.ruleset
50 |
51 |
52 | true
53 |
54 |
55 | ..\StrongKey.snk
56 |
57 |
58 |
59 | ..\packages\Microsoft.IO.RecyclableMemoryStream.1.1.0.0\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll
60 | True
61 |
62 |
63 | ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll
64 | True
65 |
66 |
67 |
68 |
69 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
70 | True
71 |
72 |
73 | False
74 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 | StrongKey.snk
93 |
94 |
95 |
96 |
97 |
98 |
99 | {2ef04e20-6cd8-420d-bac4-192ecd3f9ad5}
100 | Core.StrongName
101 |
102 |
103 |
104 |
111 |
--------------------------------------------------------------------------------
/src/Server.Owin/Server.Owin.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {DAA0A504-7ED7-4906-9D6B-FB566AE47084}
8 | Library
9 | Properties
10 | Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin
11 | Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin
12 | v4.5
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 | true
34 | bin\Test\
35 | DEBUG;TRACE
36 | full
37 | AnyCPU
38 | prompt
39 | MinimumRecommendedRules.ruleset
40 |
41 |
42 | true
43 | bin\Staging\
44 | DEBUG;TRACE
45 | full
46 | AnyCPU
47 | prompt
48 | MinimumRecommendedRules.ruleset
49 |
50 |
51 |
52 | ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll
53 | True
54 |
55 |
56 | ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll
57 | True
58 |
59 |
60 | ..\packages\Owin.1.0\lib\net40\Owin.dll
61 | True
62 |
63 |
64 |
65 |
66 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
67 | True
68 |
69 |
70 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll
71 | True
72 |
73 |
74 | ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll
75 | True
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | {b7534554-ab6c-44ac-bf34-424dbe596216}
91 | Core
92 |
93 |
94 | {ee709c23-849d-43c5-9f47-0b8d8ddb43d8}
95 | Server
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
110 |
--------------------------------------------------------------------------------
/src/Server.Owin/Server.Owin.StrongName.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {AA0CD548-E262-44AB-9AA2-A7ADA6998C99}
8 | Library
9 | Properties
10 | Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin
11 | Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin
12 | v4.5
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug.StrongName\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release.StrongName\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 | true
34 | bin\Test.StrongName\
35 | DEBUG;TRACE
36 | full
37 | AnyCPU
38 | prompt
39 | MinimumRecommendedRules.ruleset
40 |
41 |
42 | true
43 | bin\Staging.StrongName\
44 | DEBUG;TRACE
45 | full
46 | AnyCPU
47 | prompt
48 | MinimumRecommendedRules.ruleset
49 |
50 |
51 | true
52 |
53 |
54 | ..\StrongKey.snk
55 |
56 |
57 |
58 | ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll
59 | True
60 |
61 |
62 | ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll
63 | True
64 |
65 |
66 | ..\packages\Owin.1.0\lib\net40\Owin.dll
67 | True
68 |
69 |
70 |
71 |
72 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
73 | True
74 |
75 |
76 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll
77 | True
78 |
79 |
80 | ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll
81 | True
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | StrongKey.snk
97 |
98 |
99 |
100 |
101 |
102 |
103 | {2ef04e20-6cd8-420d-bac4-192ecd3f9ad5}
104 | Core.StrongName
105 |
106 |
107 | {297ac86e-3b54-4e76-a4ea-a5bf1e730d6f}
108 | Server.StrongName
109 |
110 |
111 |
112 |
119 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Compression support for ASP.NET WebAPI and HttpClient
2 | ===================================================
3 | [](https://ci.appveyor.com/project/azzlack/microsoft-aspnet-webapi-messagehandlers-compressio)
4 |
5 |
6 | Drop-in module for ASP.Net WebAPI that enables `GZip` and `Deflate` support.
7 | This module is based on [this blog post by Ben Foster](http://benfoster.io/blog/aspnet-web-api-compression) which in turn is based on this blog post by [Kiran Challa](http://blogs.msdn.com/b/kiranchalla/archive/2012/09/04/handling-compression-accept-encoding-sample.aspx).
8 | This code improves on their work by adding several new options, as well as fixing some issues with the original code.
9 |
10 | | Package | Version | Downloads |
11 | | ------- | ------- | --------- |
12 | | Microsoft.AspNet.WebApi.Extensions.Compression.Server | [](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Extensions.Compression.Server/) | [](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Extensions.Compression.Server/) |
13 | | System.Net.Http.Extensions.Compression.Client | [](https://www.nuget.org/packages/System.Net.Http.Extensions.Compression.Client/) | [](https://www.nuget.org/packages/System.Net.Http.Extensions.Compression.Client/) |
14 |
15 | ## How to use
16 | ### Server side
17 | You need to add the compression handler as the last applied message handler on outgoing requests, and the first one on incoming requests.
18 | To do that, just add the following line to your `App_Start\WebApiConfig.cs` file after adding all your other message handlers:
19 | ```csharp
20 | GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new ServerCompressionHandler(new GZipCompressor(), new DeflateCompressor()));
21 | ```
22 | This will insert the `ServerCompressionHandler` to the request pipeline as the first on incoming requests, and the last on outgoing requests.
23 |
24 | ### Client side
25 |
26 | #### JavaScript
27 | If you are doing your requests with `JavaScript` you probably don't have to do do anything.
28 | Just make sure the `gzip` and `deflate` values are included in the `Accept-Encoding` header. (Most browsers do this by default)
29 |
30 | #### C\#
31 | You need to apply the following code when creating your `HttpClient`.
32 | ```csharp
33 | var client = new HttpClient(new ClientCompressionHandler(new GZipCompressor(), new DeflateCompressor()));
34 |
35 | client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
36 | client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
37 | ```
38 |
39 | Thats it! You should now immediately start experiencing smaller payloads when doing GET, POST, PUT, etc.
40 |
41 | ## Advanced use
42 | #### Skip compression of requests/responses that are smaller than a specified value
43 | By default, both `ServerCompressionHandler` and `ClientCompressionHandler` compress everything larger than `860 bytes`.
44 | However, this can be overriden by inserting a threshold as the first parameter like this:
45 | ```csharp
46 | var serverCompressionHandler = new ServerCompressionHandler(4096, new GZipCompressor(), new DeflateCompressor());
47 | var clientCompressionHandler = new ClientCompressionHandler(4096, new GZipCompressor(), new DeflateCompressor());
48 | ```
49 | The above code will skip compression for any request/response that is smaller than `4096 bytes` / `4 kB`.
50 |
51 | #### Disable compression for endpoint
52 | It is possible to disable compression for a specific endpoint. Just add the `[Compression(Enabled = false)]` attribute to your endpoint method. (Or the whole controller if you want to disable for all endpoints in it)
53 |
54 | #### OWIN Authentication
55 | When using the OWIN Authentication pipeline, you might encounter errors saying that `Server cannot append header after http headers have been sent`. This is a [bug with OWIN](http://katanaproject.codeplex.com/discussions/540202), but as of this moment it has not been fixed.
56 |
57 | The workaround is to install the [Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin/) package and use the included `OwinServerCompressionHandler` instead of the default `ServerCompressionHandler`. This class contains code to detect whether the headers have been sent already and prevent any attempts at compression.
58 |
59 | ## Version history
60 | #### 2.0.3 (current)
61 | * [Fixed unnecessary dependency on .NET 4.5.2](https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression/issues/28)
62 | * [Fixed System.ArgumentException in CompressionAttribute](https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression/issues/25) (Thanks to [SneakyMax](https://github.com/SneakyMax))
63 | * Various readme fixes (Thanks to [wiltodelta](https://github.com/wiltodelta), [IainCole](https://github.com/IainCole), [coni2k](https://github.com/coni2k) and [altumano](https://github.com/altumano))
64 |
65 | #### 2.0.0
66 | * Fixed [UWP projects referencing Microsoft.AspNet.WebApi.MessageHandlers.Compression does not compile](https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression/issues/17)
67 | * Fixed [Remove Microsoft.Bcl dependency in .NET 4.5](https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression/issues/23)
68 | * Fixed [compressing even when accept encoding is null](https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression/issues/21)
69 | * Fixed [Possible issue while redirecting after de-compression](https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression/issues/11) and [Owin UseCookieAuthentication does not work anymore after we insert ServerCompressionHandler](https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression/issues/22)
70 | * Fixed [Async throttled actions with disabled compression](https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression/issues/20)
71 | * Improved performance a little by not always buffering the response. See #6
72 | * Fixed [Server cannot append header after HTTP headers have been sent](https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression/issues/13). NOTE: The fix is in a [separate package](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin/)
73 |
74 | #### [1.3.0](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.MessageHandlers.Compression/1.3.0)
75 | * Added attribute for disable compression for certain routes
76 | * Fixed clearing of non-standard properties when compressing and decompressing
77 |
78 | #### [1.2.2](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.MessageHandlers.Compression/1.2.2)
79 | * Stop trying to compress requests/responses with no content
80 |
81 | #### [1.2.1](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.MessageHandlers.Compression/1.2.1)
82 | * Properly copy HTTP headers from the content that is going to be compressed
83 |
84 | #### [1.2.0](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.MessageHandlers.Compression/1.2.0)
85 | * Fixed 504 timeout error when returning `ByteArrayContent` from an `ApiController`
86 | * Fixed bug with content stream sometimes being disposed before returning
87 | * Added better test coverage
88 |
89 | #### [1.1.2](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.MessageHandlers.Compression/1.1.2)
90 | * Changed default threshold for compression to 860 bytes (what Akamai uses)
91 | * Now reports proper Content-Length
92 |
93 | #### [1.1.0](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.MessageHandlers.Compression/1.1.0)
94 | * Simplified usage
95 | * Added support for setting a minimum content size for compressing
96 |
97 | #### [1.0.3](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.MessageHandlers.Compression/1.0.3)
98 | * First release, basic compression of server responses and client requests
99 | * Did not support compressing POSTs and PUTs
100 |
--------------------------------------------------------------------------------
/src/Server/ServerCompressionHandler.cs:
--------------------------------------------------------------------------------
1 | namespace Microsoft.AspNet.WebApi.Extensions.Compression.Server
2 | {
3 | using System;
4 | using System.Net.Http;
5 | using System.Net.Http.Extensions.Compression.Core.Compressors;
6 | using System.Net.Http.Extensions.Compression.Core.Interfaces;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | ///
11 | /// Message handler for handling gzip/deflate requests/responses.
12 | ///
13 | public class ServerCompressionHandler : BaseServerCompressionHandler
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | public ServerCompressionHandler()
19 | : base(null, 860, new GZipCompressor(RecyclableStreamManager.Instance), new DeflateCompressor(RecyclableStreamManager.Instance))
20 | {
21 | }
22 |
23 | ///
24 | /// Initializes a new instance of the class.
25 | ///
26 | /// The compressors.
27 | public ServerCompressionHandler(params ICompressor[] compressors)
28 | : base(null, 860, null, false, compressors)
29 | {
30 | }
31 |
32 | ///
33 | /// Initializes a new instance of the class.
34 | ///
35 | /// ConfigureAwait value.
36 | /// The compressors.
37 | public ServerCompressionHandler(bool continueOnCapturedContext, params ICompressor[] compressors)
38 | : base(null, 860, null, continueOnCapturedContext, compressors)
39 | {
40 | }
41 |
42 | ///
43 | /// Initializes a new instance of the class.
44 | ///
45 | /// The content size threshold before compressing.
46 | /// The compressors.
47 | public ServerCompressionHandler(int contentSizeThreshold, params ICompressor[] compressors)
48 | : base(null, contentSizeThreshold, null, false, compressors)
49 | {
50 | }
51 |
52 | ///
53 | /// Initializes a new instance of the class.
54 | ///
55 | /// The content size threshold before compressing.
56 | /// ConfigureAwait value.
57 | /// The compressors.
58 | public ServerCompressionHandler(int contentSizeThreshold, bool continueOnCapturedContext, params ICompressor[] compressors)
59 | : base(null, contentSizeThreshold, null, continueOnCapturedContext, compressors)
60 | {
61 | }
62 |
63 | ///
64 | /// Initializes a new instance of the class.
65 | ///
66 | /// The inner handler.
67 | /// The compressors.
68 | public ServerCompressionHandler(HttpMessageHandler innerHandler, params ICompressor[] compressors)
69 | : base(innerHandler, 860, null, false, compressors)
70 | {
71 | }
72 |
73 | ///
74 | /// Initializes a new instance of the class.
75 | ///
76 | /// The inner handler.
77 | /// ConfigureAwait value.
78 | /// The compressors.
79 | public ServerCompressionHandler(HttpMessageHandler innerHandler, bool continueOnCapturedContext, params ICompressor[] compressors)
80 | : base(innerHandler, 860, null, continueOnCapturedContext, compressors)
81 | {
82 | }
83 |
84 | ///
85 | /// Initializes a new instance of the class.
86 | ///
87 | /// The inner handler.
88 | /// The content size threshold before compressing.
89 | /// The compressors.
90 | public ServerCompressionHandler(HttpMessageHandler innerHandler, int contentSizeThreshold, params ICompressor[] compressors)
91 | : base(innerHandler, contentSizeThreshold, null, false, compressors)
92 | {
93 | }
94 |
95 | ///
96 | /// Initializes a new instance of the class.
97 | ///
98 | /// The inner handler.
99 | /// The content size threshold before compressing.
100 | /// ConfigureAwait value.
101 | /// The compressors.
102 | public ServerCompressionHandler(HttpMessageHandler innerHandler, int contentSizeThreshold, bool continueOnCapturedContext, params ICompressor[] compressors)
103 | : base(innerHandler, contentSizeThreshold, null, continueOnCapturedContext, compressors)
104 | {
105 | }
106 |
107 | ///
108 | /// Initializes a new instance of the class.
109 | ///
110 | /// The inner handler.
111 | /// The content size threshold before compressing.
112 | /// Custom delegate to enable or disable compression.
113 | /// The compressors.
114 | public ServerCompressionHandler(HttpMessageHandler innerHandler, int contentSizeThreshold, Predicate enableCompression, params ICompressor[] compressors)
115 | : base(innerHandler, contentSizeThreshold, enableCompression, false, compressors)
116 | {
117 | }
118 |
119 | ///
120 | /// Initializes a new instance of the class.
121 | ///
122 | /// The inner handler.
123 | /// The content size threshold before compressing.
124 | /// Custom delegate to enable or disable compression.
125 | /// ConfigureAwait value.
126 | /// The compressors.
127 | public ServerCompressionHandler(HttpMessageHandler innerHandler, int contentSizeThreshold,
128 | Predicate enableCompression, bool continueOnCapturedContext,
129 | params ICompressor[] compressors)
130 | : base(innerHandler, contentSizeThreshold, enableCompression, continueOnCapturedContext, compressors)
131 | {
132 | }
133 |
134 | /// Handles the request.
135 | /// The request.
136 | /// A cancellation token to cancel operation.
137 | /// A Task<HttpResponseMessage>
138 | public override Task HandleRequest(HttpRequestMessage request, CancellationToken cancellationToken)
139 | {
140 | return this.HandleDecompression(request, cancellationToken);
141 | }
142 |
143 | /// Handles the response.
144 | /// The request.
145 | /// The response.
146 | /// A cancellation token to cancel operation.
147 | /// The handled response.
148 | public override Task HandleResponse(HttpRequestMessage request, HttpResponseMessage response, CancellationToken cancellationToken)
149 | {
150 | return this.HandleCompression(request, response, cancellationToken);
151 | }
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/src/Server.Owin/OwinServerCompressionHandler.cs:
--------------------------------------------------------------------------------
1 | namespace Microsoft.AspNet.WebApi.Extensions.Compression.Server.Owin
2 | {
3 | using Microsoft.AspNet.WebApi.Extensions.Compression.Server;
4 | using Microsoft.Owin;
5 | using System;
6 | using System.Net.Http;
7 | using System.Net.Http.Extensions.Compression.Core.Interfaces;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 |
11 | public class OwinServerCompressionHandler : ServerCompressionHandler
12 | {
13 | ///
14 | /// Initializes a new instance of the class.
15 | ///
16 | /// The compressors.
17 | public OwinServerCompressionHandler(params ICompressor[] compressors)
18 | : base(null, 860, null, false, compressors)
19 | {
20 | }
21 |
22 | ///
23 | /// Initializes a new instance of the class.
24 | ///
25 | /// ConfigureAwait value.
26 | /// The compressors.
27 | public OwinServerCompressionHandler(bool continueOnCapturedContext, params ICompressor[] compressors)
28 | : base(null, 860, null, continueOnCapturedContext, compressors)
29 | {
30 | }
31 |
32 | ///
33 | /// Initializes a new instance of the class.
34 | ///
35 | /// The content size threshold before compressing.
36 | /// The compressors.
37 | public OwinServerCompressionHandler(int contentSizeThreshold, params ICompressor[] compressors)
38 | : base(null, contentSizeThreshold, null, false, compressors)
39 | {
40 | }
41 |
42 | ///
43 | /// Initializes a new instance of the class.
44 | ///
45 | /// The content size threshold before compressing.
46 | /// ConfigureAwait value.
47 | /// The compressors.
48 | public OwinServerCompressionHandler(int contentSizeThreshold, bool continueOnCapturedContext, params ICompressor[] compressors)
49 | : base(null, contentSizeThreshold, null, continueOnCapturedContext, compressors)
50 | {
51 | }
52 |
53 | ///
54 | /// Initializes a new instance of the class.
55 | ///
56 | /// The inner handler.
57 | /// The compressors.
58 | public OwinServerCompressionHandler(HttpMessageHandler innerHandler, params ICompressor[] compressors)
59 | : base(innerHandler, 860, null, false, compressors)
60 | {
61 | }
62 |
63 | ///
64 | /// Initializes a new instance of the class.
65 | ///
66 | /// The inner handler.
67 | /// ConfigureAwait value.
68 | /// The compressors.
69 | public OwinServerCompressionHandler(HttpMessageHandler innerHandler, bool continueOnCapturedContext, params ICompressor[] compressors)
70 | : base(innerHandler, 860, null, continueOnCapturedContext, compressors)
71 | {
72 | }
73 |
74 | ///
75 | /// Initializes a new instance of the class.
76 | ///
77 | /// The inner handler.
78 | /// The content size threshold before compressing.
79 | /// The compressors.
80 | public OwinServerCompressionHandler(HttpMessageHandler innerHandler, int contentSizeThreshold, params ICompressor[] compressors)
81 | : base(innerHandler, contentSizeThreshold, null, false, compressors)
82 | {
83 | }
84 |
85 | ///
86 | /// Initializes a new instance of the class.
87 | ///
88 | /// The inner handler.
89 | /// The content size threshold before compressing.
90 | /// ConfigureAwait value.
91 | /// The compressors.
92 | public OwinServerCompressionHandler(HttpMessageHandler innerHandler, int contentSizeThreshold, bool continueOnCapturedContext, params ICompressor[] compressors)
93 | : base(innerHandler, contentSizeThreshold, null, continueOnCapturedContext, compressors)
94 | {
95 | }
96 |
97 | ///
98 | /// Initializes a new instance of the class.
99 | ///
100 | /// The inner handler.
101 | /// The content size threshold before compressing.
102 | /// Custom delegate to enable or disable compression.
103 | /// The compressors.
104 | public OwinServerCompressionHandler(HttpMessageHandler innerHandler, int contentSizeThreshold, Predicate enableCompression, params ICompressor[] compressors)
105 | : base(innerHandler, contentSizeThreshold, enableCompression, false, compressors)
106 | {
107 | }
108 |
109 | ///
110 | /// Initializes a new instance of the class.
111 | ///
112 | /// The inner handler.
113 | /// The content size threshold before compressing.
114 | /// Custom delegate to enable or disable compression.
115 | /// ConfigureAwait value.
116 | /// The compressors.
117 | public OwinServerCompressionHandler(HttpMessageHandler innerHandler, int contentSizeThreshold, Predicate enableCompression, bool continueOnCapturedContext, params ICompressor[] compressors)
118 | : base(innerHandler, contentSizeThreshold, enableCompression, continueOnCapturedContext, compressors)
119 | {
120 | }
121 |
122 | /// Handles the request.
123 | /// The request.
124 | /// A cancellation token to cancel operation.
125 | /// A Task<HttpResponseMessage>
126 | public override Task HandleRequest(HttpRequestMessage request, CancellationToken cancellationToken)
127 | {
128 | request.GetOwinContext().Response.OnSendingHeaders(
129 | response =>
130 | {
131 | ((IOwinResponse)response).Environment["HeadersWritten"] = true;
132 | },
133 | request.GetOwinContext().Response);
134 |
135 | return base.HandleRequest(request, cancellationToken);
136 | }
137 |
138 | /// Handles the response.
139 | /// The request.
140 | /// The response.
141 | /// A cancellation token to cancel operation.
142 | /// The handled response.
143 | public override async Task HandleResponse(HttpRequestMessage request, HttpResponseMessage response, CancellationToken cancellationToken)
144 | {
145 | // Check if headers are already written, and skip processing if they are
146 | if (request.GetOwinContext().Response.Environment.ContainsKey("HeadersWritten"))
147 | {
148 | bool written;
149 | bool.TryParse(request.GetOwinContext().Response.Environment["HeadersWritten"].ToString(), out written);
150 |
151 | if (written)
152 | {
153 | return response;
154 | }
155 | }
156 |
157 | return await base.HandleResponse(request, response, cancellationToken);
158 | }
159 | }
160 | }
--------------------------------------------------------------------------------
/src/Client/ClientCompressionHandler.cs:
--------------------------------------------------------------------------------
1 | namespace System.Net.Http.Extensions.Compression.Client
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Linq;
7 | using System.Net.Http;
8 | using System.Net.Http.Extensions.Compression.Core;
9 | using System.Net.Http.Extensions.Compression.Core.Interfaces;
10 | using System.Net.Http.Extensions.Compression.Core.Models;
11 | using System.Threading;
12 | using System.Threading.Tasks;
13 |
14 | ///
15 | /// Message handler for handling gzip/deflate requests/responses on a .
16 | ///
17 | public class ClientCompressionHandler : DelegatingHandler
18 | {
19 | ///
20 | /// The content size threshold before compressing.
21 | ///
22 | private readonly int contentSizeThreshold;
23 |
24 | ///
25 | /// The HTTP content operations
26 | ///
27 | private readonly HttpContentOperations httpContentOperations;
28 |
29 | ///
30 | /// Initializes a new instance of the class.
31 | ///
32 | /// The compressors.
33 | public ClientCompressionHandler(params ICompressor[] compressors)
34 | : this(new HttpClientHandler(), 860, compressors)
35 | {
36 | }
37 |
38 | ///
39 | /// Initializes a new instance of the class.
40 | ///
41 | /// The content size threshold before compressing.
42 | /// The compressors.
43 | public ClientCompressionHandler(int contentSizeThreshold, params ICompressor[] compressors)
44 | : this(new HttpClientHandler(), contentSizeThreshold, compressors)
45 | {
46 | }
47 |
48 | ///
49 | /// Initializes a new instance of the class.
50 | ///
51 | /// The inner handler.
52 | /// The compressors.
53 | public ClientCompressionHandler(HttpMessageHandler innerHandler, params ICompressor[] compressors)
54 | : this(innerHandler, 860, compressors)
55 | {
56 | }
57 |
58 | ///
59 | /// Initializes a new instance of the class.
60 | ///
61 | /// The inner handler.
62 | /// The content size threshold before compressing.
63 | /// The compressors.
64 | public ClientCompressionHandler(HttpMessageHandler innerHandler, int contentSizeThreshold, params ICompressor[] compressors)
65 | {
66 | if (innerHandler != null)
67 | {
68 | this.InnerHandler = innerHandler;
69 | }
70 |
71 | this.Compressors = compressors;
72 | this.contentSizeThreshold = contentSizeThreshold;
73 |
74 | this.httpContentOperations = new HttpContentOperations();
75 | }
76 |
77 | ///
78 | /// Gets the compressors.
79 | ///
80 | /// The compressors.
81 | public ICollection Compressors { get; private set; }
82 |
83 | ///
84 | /// send as an asynchronous operation.
85 | ///
86 | /// The HTTP request message to send to the server.
87 | /// A cancellation token to cancel operation.
88 | /// Returns . The task object representing the asynchronous operation.
89 | protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
90 | {
91 | // Compress uncompressed requests from the client to the server
92 | if (request.Content != null && request.Headers.AcceptEncoding.Any())
93 | {
94 | await this.CompressRequest(request);
95 | }
96 |
97 | var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
98 |
99 | var process = true;
100 |
101 | try
102 | {
103 | if (response.Content != null)
104 | {
105 | // Buffer content for further processing
106 | await response.Content.LoadIntoBufferAsync();
107 | }
108 | else
109 | {
110 | process = false;
111 | }
112 | }
113 | catch (Exception ex)
114 | {
115 | process = false;
116 |
117 | Debug.WriteLine(ex.Message);
118 | }
119 |
120 | // Decompress compressed responses to the client from the server
121 | if (process && response.Content != null && response.Content.Headers.ContentEncoding.Any())
122 | {
123 | await this.DecompressResponse(response);
124 | }
125 |
126 | return response;
127 | }
128 |
129 | ///
130 | /// Compresses the content.
131 | ///
132 | /// The request.
133 | /// An async void.
134 | private async Task CompressRequest(HttpRequestMessage request)
135 | {
136 | // As per RFC2616.14.3:
137 | // Ignores encodings with quality == 0
138 | // If multiple content-codings are acceptable, then the acceptable content-coding with the highest non-zero qvalue is preferred.
139 | var compressor = (from encoding in request.Headers.AcceptEncoding
140 | let quality = encoding.Quality ?? 1.0
141 | where quality > 0
142 | join c in this.Compressors on encoding.Value.ToLowerInvariant() equals
143 | c.EncodingType.ToLowerInvariant()
144 | orderby quality descending
145 | select c).FirstOrDefault();
146 |
147 | if (compressor != null)
148 | {
149 | // Try to set content-length by loading the content into memory if the content-length is not already set
150 | if (request.Content.Headers.ContentLength == null)
151 | {
152 | await request.Content.LoadIntoBufferAsync();
153 | }
154 |
155 | try
156 | {
157 | // Only compress request if size is larger than threshold (if set)
158 | if (this.contentSizeThreshold == 0)
159 | {
160 | request.Content = new CompressedContent(request.Content, compressor);
161 | }
162 | else if (this.contentSizeThreshold > 0 && request.Content.Headers.ContentLength >= this.contentSizeThreshold)
163 | {
164 | request.Content = new CompressedContent(request.Content, compressor);
165 | }
166 | }
167 | catch (Exception ex)
168 | {
169 | throw new Exception(string.Format("Unable to compress request using compressor '{0}'", compressor.GetType()), ex);
170 | }
171 | }
172 | }
173 |
174 | ///
175 | /// Decompresses the response.
176 | ///
177 | /// The response.
178 | /// An async void.
179 | private async Task DecompressResponse(HttpResponseMessage response)
180 | {
181 | var encoding = response.Content.Headers.ContentEncoding.FirstOrDefault();
182 |
183 | if (encoding != null)
184 | {
185 | var compressor = this.Compressors.FirstOrDefault(c => c.EncodingType.Equals(encoding, StringComparison.OrdinalIgnoreCase));
186 |
187 | if (compressor != null)
188 | {
189 | try
190 | {
191 | response.Content = await this.httpContentOperations.DecompressContent(response.Content, compressor).ConfigureAwait(false);
192 | }
193 | catch (Exception ex)
194 | {
195 | throw new Exception(string.Format("Unable to decompress response using compressor '{0}'", compressor.GetType()), ex);
196 | }
197 | }
198 | }
199 | }
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/src/Tests/Tests/Common/TestFixture.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Tests.Common
2 | {
3 | using global::Tests.Extensions;
4 | using global::Tests.Models;
5 | using Newtonsoft.Json;
6 | using NUnit.Framework;
7 | using System;
8 | using System.Net.Http;
9 | using System.Text;
10 |
11 | public abstract class TestFixture
12 | {
13 | public HttpClient Client { get; set; }
14 |
15 | [Test]
16 | public async void Get_WhenMessageHandlerIsConfigured_ShouldReturnCompressedContent()
17 | {
18 | var response = await this.Client.GetAsync("http://localhost:55399/api/test");
19 |
20 | Console.Write(await response.ToTestString());
21 |
22 | Assert.IsTrue(response.Content.Headers.ContentEncoding.Contains("gzip"));
23 |
24 | var result = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());
25 |
26 | Assert.AreEqual("Get()", result.Data);
27 | }
28 |
29 | [Test]
30 | public async void Get_WhenGivenCustomHeader_ShouldReturnCompressedContentWithCustomHeader()
31 | {
32 | var response = await this.Client.GetAsync("http://localhost:55399/api/test/customheader");
33 |
34 | Console.Write(await response.ToTestString());
35 |
36 | Assert.IsTrue(response.Content.Headers.ContentEncoding.Contains("gzip"));
37 | Assert.IsTrue(response.Headers.Contains("DataServiceVersion"), "The response did not contain the DataServiceVersion header");
38 | }
39 |
40 | [Test]
41 | public async void Get_WhenGivenCustomContentEncoding_ShouldReturnCompressedContentWithCustomContentEncoding()
42 | {
43 | var response = await this.Client.GetAsync("http://localhost:55399/api/test/customcontentencoding");
44 |
45 | Console.WriteLine($"Content-Encoding: {string.Join(", ", response.Content.Headers.ContentEncoding)}");
46 |
47 | Assert.IsTrue(response.Content.Headers.ContentEncoding.Contains("gzip"));
48 | Assert.IsTrue(response.Content.Headers.ContentEncoding.Contains("lol"));
49 | }
50 |
51 | [Test]
52 | public async void Get_WhenGivenAcceptEncodingNull_ShouldReturnUncompressedContent()
53 | {
54 | var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost:55399/api/test");
55 | this.Client.DefaultRequestHeaders.AcceptEncoding.Clear();
56 |
57 | Console.WriteLine("Accept-Encoding: {0}", string.Join(", ", request.Headers.AcceptEncoding));
58 |
59 | var response = await this.Client.SendAsync(request);
60 |
61 | Console.Write(await response.ToTestString());
62 |
63 | Assert.IsFalse(response.Content.Headers.ContentEncoding.Contains("gzip"), "The server returned compressed content");
64 | }
65 |
66 | [Test]
67 | public async void Get_WhenResponseHeaderIsModified_ShouldReturnModifiedResponse()
68 | {
69 | var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost:55399/api/test/redirect");
70 |
71 | var response = await this.Client.SendAsync(request);
72 |
73 | Console.Write(await response.ToTestString());
74 |
75 | Assert.AreEqual(29, response.Content.Headers.ContentLength);
76 | Assert.AreEqual("http://localhost:55399/api/test", response.Headers.Location.ToString());
77 | }
78 |
79 | [Test]
80 | public async void GetImage_WhenMessageHandlerIsConfigured_ShouldReturnCompressedContent()
81 | {
82 | var response = await this.Client.GetAsync("http://localhost:55399/api/file/image");
83 |
84 | Console.Write(await response.ToTestString());
85 |
86 | Assert.IsTrue(response.Content.Headers.ContentType.MediaType == "image/png");
87 | Assert.IsTrue(response.Content.Headers.ContentEncoding.Contains("gzip"));
88 |
89 | var content = await response.Content.ReadAsByteArrayAsync();
90 |
91 | Assert.AreEqual(749, response.Content.Headers.ContentLength);
92 | Assert.AreEqual(4596, content.Length);
93 | }
94 |
95 | [Test]
96 | public async void GetImage_WhenAttributeIsConfigured_ShouldReturnUncompressedContent()
97 | {
98 |
99 | var response = await this.Client.GetAsync("http://localhost:55399/api/file/uncompressedimage");
100 |
101 | Console.Write(await response.ToTestString());
102 |
103 | Assert.IsTrue(response.Content.Headers.ContentType.MediaType == "image/png");
104 | Assert.IsFalse(response.Content.Headers.ContentEncoding.Contains("gzip"));
105 |
106 | var content = await response.Content.ReadAsByteArrayAsync();
107 |
108 | Assert.AreEqual(4596, content.Length);
109 | }
110 |
111 | [Test]
112 | public async void GetPdf_WhenMessageHandlerIsConfigured_ShouldReturnCompressedContent()
113 | {
114 | var response = await this.Client.GetAsync("http://localhost:55399/api/file/pdf");
115 |
116 | Console.Write(await response.ToTestString());
117 |
118 | Assert.IsTrue(response.Content.Headers.ContentType.MediaType == "application/pdf");
119 | Assert.IsTrue(response.Content.Headers.ContentEncoding.Contains("gzip"));
120 |
121 | var content = await response.Content.ReadAsByteArrayAsync();
122 |
123 | Assert.AreEqual(16538, content.Length);
124 | }
125 |
126 | [TestCase("1")]
127 | [TestCase("10")]
128 | public async void GetSpecific_WhenMessageHandlerIsConfigured_ShouldReturnCompressedContent(string id)
129 | {
130 | var response = await this.Client.GetAsync("http://localhost:55399/api/test/" + id);
131 |
132 | Console.Write(await response.ToTestString());
133 |
134 | Assert.IsTrue(response.Content.Headers.ContentEncoding.Contains("gzip"));
135 |
136 | var content = await response.Content.ReadAsStringAsync();
137 |
138 | var result = JsonConvert.DeserializeObject(content);
139 |
140 | Assert.AreEqual("Get(" + id + ")", result.Data);
141 | }
142 |
143 | [TestCase("Content1")]
144 | [TestCase("Content10")]
145 | [TestCase("Content10Content10Content10Content10Content10Content10Content10Content10Content10Content10Content10Content10")]
146 | public async void Post_WhenMessageHandlerIsConfigured_ShouldReturnCompressedContent(string body)
147 | {
148 | var response = await this.Client.PostAsync("http://localhost:55399/api/test", new StringContent(JsonConvert.SerializeObject(new TestModel(body)), Encoding.UTF8, "application/json"));
149 |
150 | Console.Write(await response.ToTestString());
151 |
152 | Assert.IsTrue(response.Content.Headers.ContentEncoding.Contains("gzip"));
153 |
154 | var content = await response.Content.ReadAsStringAsync();
155 |
156 | var result = JsonConvert.DeserializeObject(content);
157 |
158 | Assert.AreEqual(body, result.Data);
159 | }
160 |
161 | [TestCase("Content1")]
162 | [TestCase("Content10")]
163 | [TestCase("Content10Content10Content10Content10Content10Content10Content10Content10Content10Content10Content10Content10")]
164 | public async void Post_WhenNestedMessageHandlerIsConfigured_ShouldReturnCompressedContent(string body)
165 | {
166 | var response = await this.Client.PostAsync("http://localhost:55399/api/test", new StringContent(JsonConvert.SerializeObject(new TestModel(body)), Encoding.UTF8, "application/json"));
167 |
168 | Console.Write(await response.ToTestString());
169 |
170 | Assert.IsTrue(response.Content.Headers.ContentEncoding.Contains("gzip"));
171 |
172 | var content = await response.Content.ReadAsStringAsync();
173 |
174 | var result = JsonConvert.DeserializeObject(content);
175 |
176 | Assert.AreEqual(body, result.Data);
177 | }
178 |
179 | [TestCase("1", "Content1")]
180 | [TestCase("2", "Content10")]
181 | public async void Put_WhenMessageHandlerIsConfigured_ShouldReturnCompressedContent(string id, string body)
182 | {
183 | var response = await this.Client.PutAsync("http://localhost:55399/api/test/" + id, new StringContent(JsonConvert.SerializeObject(new TestModel(body)), Encoding.UTF8, "application/json"));
184 |
185 | Console.Write(await response.ToTestString());
186 |
187 | Assert.IsTrue(response.Content.Headers.ContentEncoding.Contains("gzip"));
188 |
189 | var content = await response.Content.ReadAsStringAsync();
190 |
191 | var result = JsonConvert.DeserializeObject(content);
192 |
193 | Assert.AreEqual(body, result.Data);
194 | }
195 |
196 | [TestCase("1")]
197 | [TestCase("2")]
198 | public async void Delete_WhenMessageHandlerIsConfigured_ShouldReturnCompressedContent(string id)
199 | {
200 | var response = await this.Client.DeleteAsync("http://localhost:55399/api/test/" + id);
201 |
202 | Assert.That(response.Content == null || string.IsNullOrEmpty(await response.Content.ReadAsStringAsync()));
203 | Assert.IsTrue(response.IsSuccessStatusCode);
204 | }
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/src/Microsoft.AspNet.WebApi.MessageHandlers.Compression.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "Client\Client.csproj", "{56E19FF7-9AC7-48C5-9AC2-105F55AA16E1}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{7952E97C-2C7E-424B-A912-ED875576CA92}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{EE709C23-849D-43C5-9F47-0B8D8DDB43D8}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{B7534554-AB6C-44AC-BF34-424DBE596216}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server.Owin", "Server.Owin\Server.Owin.csproj", "{DAA0A504-7ED7-4906-9D6B-FB566AE47084}"
15 | EndProject
16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{977C3F06-2918-4747-8658-8B7C9B31E8C2}"
17 | ProjectSection(SolutionItems) = preProject
18 | StrongKey.snk = StrongKey.snk
19 | EndProjectSection
20 | EndProject
21 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client.StrongName", "Client\Client.StrongName.csproj", "{FF00D5E5-9581-4047-A5EE-CB968A567EE2}"
22 | EndProject
23 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StrongNamed", "StrongNamed", "{33FDEBCE-A3CE-473E-B246-D561355046ED}"
24 | EndProject
25 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.StrongName", "Core\Core.StrongName.csproj", "{2EF04E20-6CD8-420D-BAC4-192ECD3F9AD5}"
26 | EndProject
27 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server.StrongName", "Server\Server.StrongName.csproj", "{297AC86E-3B54-4E76-A4EA-A5BF1E730D6F}"
28 | EndProject
29 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server.Owin.StrongName", "Server.Owin\Server.Owin.StrongName.csproj", "{AA0CD548-E262-44AB-9AA2-A7ADA6998C99}"
30 | EndProject
31 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.StrongName", "Tests\Tests.StrongName.csproj", "{F390EA4F-93FD-4D14-9D24-DC3152537DD1}"
32 | EndProject
33 | Global
34 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
35 | Debug|Any CPU = Debug|Any CPU
36 | Release|Any CPU = Release|Any CPU
37 | Staging|Any CPU = Staging|Any CPU
38 | Test|Any CPU = Test|Any CPU
39 | EndGlobalSection
40 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
41 | {56E19FF7-9AC7-48C5-9AC2-105F55AA16E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
42 | {56E19FF7-9AC7-48C5-9AC2-105F55AA16E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
43 | {56E19FF7-9AC7-48C5-9AC2-105F55AA16E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
44 | {56E19FF7-9AC7-48C5-9AC2-105F55AA16E1}.Release|Any CPU.Build.0 = Release|Any CPU
45 | {56E19FF7-9AC7-48C5-9AC2-105F55AA16E1}.Staging|Any CPU.ActiveCfg = Staging|Any CPU
46 | {56E19FF7-9AC7-48C5-9AC2-105F55AA16E1}.Staging|Any CPU.Build.0 = Staging|Any CPU
47 | {56E19FF7-9AC7-48C5-9AC2-105F55AA16E1}.Test|Any CPU.ActiveCfg = Test|Any CPU
48 | {56E19FF7-9AC7-48C5-9AC2-105F55AA16E1}.Test|Any CPU.Build.0 = Test|Any CPU
49 | {7952E97C-2C7E-424B-A912-ED875576CA92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
50 | {7952E97C-2C7E-424B-A912-ED875576CA92}.Debug|Any CPU.Build.0 = Debug|Any CPU
51 | {7952E97C-2C7E-424B-A912-ED875576CA92}.Release|Any CPU.ActiveCfg = Release|Any CPU
52 | {7952E97C-2C7E-424B-A912-ED875576CA92}.Release|Any CPU.Build.0 = Release|Any CPU
53 | {7952E97C-2C7E-424B-A912-ED875576CA92}.Staging|Any CPU.ActiveCfg = Staging|Any CPU
54 | {7952E97C-2C7E-424B-A912-ED875576CA92}.Staging|Any CPU.Build.0 = Staging|Any CPU
55 | {7952E97C-2C7E-424B-A912-ED875576CA92}.Test|Any CPU.ActiveCfg = Test|Any CPU
56 | {7952E97C-2C7E-424B-A912-ED875576CA92}.Test|Any CPU.Build.0 = Test|Any CPU
57 | {EE709C23-849D-43C5-9F47-0B8D8DDB43D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
58 | {EE709C23-849D-43C5-9F47-0B8D8DDB43D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
59 | {EE709C23-849D-43C5-9F47-0B8D8DDB43D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
60 | {EE709C23-849D-43C5-9F47-0B8D8DDB43D8}.Release|Any CPU.Build.0 = Release|Any CPU
61 | {EE709C23-849D-43C5-9F47-0B8D8DDB43D8}.Staging|Any CPU.ActiveCfg = Staging|Any CPU
62 | {EE709C23-849D-43C5-9F47-0B8D8DDB43D8}.Staging|Any CPU.Build.0 = Staging|Any CPU
63 | {EE709C23-849D-43C5-9F47-0B8D8DDB43D8}.Test|Any CPU.ActiveCfg = Test|Any CPU
64 | {EE709C23-849D-43C5-9F47-0B8D8DDB43D8}.Test|Any CPU.Build.0 = Test|Any CPU
65 | {B7534554-AB6C-44AC-BF34-424DBE596216}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
66 | {B7534554-AB6C-44AC-BF34-424DBE596216}.Debug|Any CPU.Build.0 = Debug|Any CPU
67 | {B7534554-AB6C-44AC-BF34-424DBE596216}.Release|Any CPU.ActiveCfg = Release|Any CPU
68 | {B7534554-AB6C-44AC-BF34-424DBE596216}.Release|Any CPU.Build.0 = Release|Any CPU
69 | {B7534554-AB6C-44AC-BF34-424DBE596216}.Staging|Any CPU.ActiveCfg = Staging|Any CPU
70 | {B7534554-AB6C-44AC-BF34-424DBE596216}.Staging|Any CPU.Build.0 = Staging|Any CPU
71 | {B7534554-AB6C-44AC-BF34-424DBE596216}.Test|Any CPU.ActiveCfg = Test|Any CPU
72 | {B7534554-AB6C-44AC-BF34-424DBE596216}.Test|Any CPU.Build.0 = Test|Any CPU
73 | {DAA0A504-7ED7-4906-9D6B-FB566AE47084}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
74 | {DAA0A504-7ED7-4906-9D6B-FB566AE47084}.Debug|Any CPU.Build.0 = Debug|Any CPU
75 | {DAA0A504-7ED7-4906-9D6B-FB566AE47084}.Release|Any CPU.ActiveCfg = Release|Any CPU
76 | {DAA0A504-7ED7-4906-9D6B-FB566AE47084}.Release|Any CPU.Build.0 = Release|Any CPU
77 | {DAA0A504-7ED7-4906-9D6B-FB566AE47084}.Staging|Any CPU.ActiveCfg = Staging|Any CPU
78 | {DAA0A504-7ED7-4906-9D6B-FB566AE47084}.Staging|Any CPU.Build.0 = Staging|Any CPU
79 | {DAA0A504-7ED7-4906-9D6B-FB566AE47084}.Test|Any CPU.ActiveCfg = Test|Any CPU
80 | {DAA0A504-7ED7-4906-9D6B-FB566AE47084}.Test|Any CPU.Build.0 = Test|Any CPU
81 | {FF00D5E5-9581-4047-A5EE-CB968A567EE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
82 | {FF00D5E5-9581-4047-A5EE-CB968A567EE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
83 | {FF00D5E5-9581-4047-A5EE-CB968A567EE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
84 | {FF00D5E5-9581-4047-A5EE-CB968A567EE2}.Release|Any CPU.Build.0 = Release|Any CPU
85 | {FF00D5E5-9581-4047-A5EE-CB968A567EE2}.Staging|Any CPU.ActiveCfg = Staging|Any CPU
86 | {FF00D5E5-9581-4047-A5EE-CB968A567EE2}.Staging|Any CPU.Build.0 = Staging|Any CPU
87 | {FF00D5E5-9581-4047-A5EE-CB968A567EE2}.Test|Any CPU.ActiveCfg = Test|Any CPU
88 | {FF00D5E5-9581-4047-A5EE-CB968A567EE2}.Test|Any CPU.Build.0 = Test|Any CPU
89 | {2EF04E20-6CD8-420D-BAC4-192ECD3F9AD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
90 | {2EF04E20-6CD8-420D-BAC4-192ECD3F9AD5}.Debug|Any CPU.Build.0 = Debug|Any CPU
91 | {2EF04E20-6CD8-420D-BAC4-192ECD3F9AD5}.Release|Any CPU.ActiveCfg = Release|Any CPU
92 | {2EF04E20-6CD8-420D-BAC4-192ECD3F9AD5}.Release|Any CPU.Build.0 = Release|Any CPU
93 | {2EF04E20-6CD8-420D-BAC4-192ECD3F9AD5}.Staging|Any CPU.ActiveCfg = Staging|Any CPU
94 | {2EF04E20-6CD8-420D-BAC4-192ECD3F9AD5}.Staging|Any CPU.Build.0 = Staging|Any CPU
95 | {2EF04E20-6CD8-420D-BAC4-192ECD3F9AD5}.Test|Any CPU.ActiveCfg = Test|Any CPU
96 | {2EF04E20-6CD8-420D-BAC4-192ECD3F9AD5}.Test|Any CPU.Build.0 = Test|Any CPU
97 | {297AC86E-3B54-4E76-A4EA-A5BF1E730D6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
98 | {297AC86E-3B54-4E76-A4EA-A5BF1E730D6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
99 | {297AC86E-3B54-4E76-A4EA-A5BF1E730D6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
100 | {297AC86E-3B54-4E76-A4EA-A5BF1E730D6F}.Release|Any CPU.Build.0 = Release|Any CPU
101 | {297AC86E-3B54-4E76-A4EA-A5BF1E730D6F}.Staging|Any CPU.ActiveCfg = Staging|Any CPU
102 | {297AC86E-3B54-4E76-A4EA-A5BF1E730D6F}.Staging|Any CPU.Build.0 = Staging|Any CPU
103 | {297AC86E-3B54-4E76-A4EA-A5BF1E730D6F}.Test|Any CPU.ActiveCfg = Test|Any CPU
104 | {297AC86E-3B54-4E76-A4EA-A5BF1E730D6F}.Test|Any CPU.Build.0 = Test|Any CPU
105 | {AA0CD548-E262-44AB-9AA2-A7ADA6998C99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
106 | {AA0CD548-E262-44AB-9AA2-A7ADA6998C99}.Debug|Any CPU.Build.0 = Debug|Any CPU
107 | {AA0CD548-E262-44AB-9AA2-A7ADA6998C99}.Release|Any CPU.ActiveCfg = Release|Any CPU
108 | {AA0CD548-E262-44AB-9AA2-A7ADA6998C99}.Release|Any CPU.Build.0 = Release|Any CPU
109 | {AA0CD548-E262-44AB-9AA2-A7ADA6998C99}.Staging|Any CPU.ActiveCfg = Staging|Any CPU
110 | {AA0CD548-E262-44AB-9AA2-A7ADA6998C99}.Staging|Any CPU.Build.0 = Staging|Any CPU
111 | {AA0CD548-E262-44AB-9AA2-A7ADA6998C99}.Test|Any CPU.ActiveCfg = Test|Any CPU
112 | {AA0CD548-E262-44AB-9AA2-A7ADA6998C99}.Test|Any CPU.Build.0 = Test|Any CPU
113 | {F390EA4F-93FD-4D14-9D24-DC3152537DD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
114 | {F390EA4F-93FD-4D14-9D24-DC3152537DD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
115 | {F390EA4F-93FD-4D14-9D24-DC3152537DD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
116 | {F390EA4F-93FD-4D14-9D24-DC3152537DD1}.Release|Any CPU.Build.0 = Release|Any CPU
117 | {F390EA4F-93FD-4D14-9D24-DC3152537DD1}.Staging|Any CPU.ActiveCfg = Staging|Any CPU
118 | {F390EA4F-93FD-4D14-9D24-DC3152537DD1}.Staging|Any CPU.Build.0 = Staging|Any CPU
119 | {F390EA4F-93FD-4D14-9D24-DC3152537DD1}.Test|Any CPU.ActiveCfg = Test|Any CPU
120 | {F390EA4F-93FD-4D14-9D24-DC3152537DD1}.Test|Any CPU.Build.0 = Test|Any CPU
121 | EndGlobalSection
122 | GlobalSection(SolutionProperties) = preSolution
123 | HideSolutionNode = FALSE
124 | EndGlobalSection
125 | GlobalSection(NestedProjects) = preSolution
126 | {977C3F06-2918-4747-8658-8B7C9B31E8C2} = {33FDEBCE-A3CE-473E-B246-D561355046ED}
127 | {FF00D5E5-9581-4047-A5EE-CB968A567EE2} = {33FDEBCE-A3CE-473E-B246-D561355046ED}
128 | {2EF04E20-6CD8-420D-BAC4-192ECD3F9AD5} = {33FDEBCE-A3CE-473E-B246-D561355046ED}
129 | {297AC86E-3B54-4E76-A4EA-A5BF1E730D6F} = {33FDEBCE-A3CE-473E-B246-D561355046ED}
130 | {AA0CD548-E262-44AB-9AA2-A7ADA6998C99} = {33FDEBCE-A3CE-473E-B246-D561355046ED}
131 | {F390EA4F-93FD-4D14-9D24-DC3152537DD1} = {33FDEBCE-A3CE-473E-B246-D561355046ED}
132 | EndGlobalSection
133 | EndGlobal
134 |
--------------------------------------------------------------------------------
/src/Tests/Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {7952E97C-2C7E-424B-A912-ED875576CA92}
8 | Library
9 | Properties
10 | Tests
11 | Tests
12 | v4.5.2
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 | true
35 | bin\Test\
36 | DEBUG;TRACE
37 | full
38 | AnyCPU
39 | prompt
40 | MinimumRecommendedRules.ruleset
41 |
42 |
43 | true
44 | bin\Staging\
45 | DEBUG;TRACE
46 | full
47 | AnyCPU
48 | prompt
49 | MinimumRecommendedRules.ruleset
50 |
51 |
52 |
53 | ..\packages\iTextSharp-LGPL.4.1.6\lib\iTextSharp.dll
54 |
55 |
56 | ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll
57 | True
58 |
59 |
60 | ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll
61 | True
62 |
63 |
64 | ..\packages\Microsoft.Owin.Host.HttpListener.3.0.1\lib\net45\Microsoft.Owin.Host.HttpListener.dll
65 | True
66 |
67 |
68 | ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll
69 | True
70 |
71 |
72 | ..\packages\Microsoft.Owin.Hosting.3.0.1\lib\net45\Microsoft.Owin.Hosting.dll
73 | True
74 |
75 |
76 | ..\packages\Microsoft.Owin.Security.3.0.1\lib\net45\Microsoft.Owin.Security.dll
77 | True
78 |
79 |
80 | ..\packages\Microsoft.Owin.Security.Cookies.3.0.1\lib\net45\Microsoft.Owin.Security.Cookies.dll
81 | True
82 |
83 |
84 | ..\packages\Microsoft.Owin.Testing.3.0.1\lib\net45\Microsoft.Owin.Testing.dll
85 | True
86 |
87 |
88 | False
89 | ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll
90 |
91 |
92 | ..\packages\NUnit.2.6.3\lib\nunit.framework.dll
93 |
94 |
95 | ..\packages\Owin.1.0\lib\net40\Owin.dll
96 |
97 |
98 |
99 |
100 |
101 |
102 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
103 | True
104 |
105 |
106 |
107 |
108 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll
109 | True
110 |
111 |
112 | ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll
113 | True
114 |
115 |
116 | ..\packages\Microsoft.AspNet.WebApi.SelfHost.5.2.3\lib\net45\System.Web.Http.SelfHost.dll
117 | True
118 |
119 |
120 | ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll
121 | True
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 | Global.asax
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 | Designer
156 |
157 |
158 |
159 |
160 |
161 | {56e19ff7-9ac7-48c5-9ac2-105f55aa16e1}
162 | Client
163 |
164 |
165 | {b7534554-ab6c-44ac-bf34-424dbe596216}
166 | Core
167 |
168 |
169 | {daa0a504-7ed7-4906-9d6b-fb566ae47084}
170 | Server.Owin
171 |
172 |
173 | {ee709c23-849d-43c5-9f47-0b8d8ddb43d8}
174 | Server
175 |
176 |
177 |
178 |
179 | PreserveNewest
180 |
181 |
182 |
183 |
184 |
191 |
--------------------------------------------------------------------------------
/src/Tests/Tests.StrongName.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {F390EA4F-93FD-4D14-9D24-DC3152537DD1}
8 | Library
9 | Properties
10 | Tests
11 | Tests
12 | v4.5.2
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug.StrongName\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release.StrongName\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 | true
35 | bin\Test.StrongName\
36 | DEBUG;TRACE
37 | full
38 | AnyCPU
39 | prompt
40 | MinimumRecommendedRules.ruleset
41 |
42 |
43 | true
44 | bin\Staging.StrongName\
45 | DEBUG;TRACE
46 | full
47 | AnyCPU
48 | prompt
49 | MinimumRecommendedRules.ruleset
50 |
51 |
52 | true
53 |
54 |
55 | ..\StrongKey.snk
56 |
57 |
58 |
59 | ..\packages\iTextSharp-LGPL.4.1.6\lib\iTextSharp.dll
60 |
61 |
62 | ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll
63 | True
64 |
65 |
66 | ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll
67 | True
68 |
69 |
70 | ..\packages\Microsoft.Owin.Host.HttpListener.3.0.1\lib\net45\Microsoft.Owin.Host.HttpListener.dll
71 | True
72 |
73 |
74 | ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll
75 | True
76 |
77 |
78 | ..\packages\Microsoft.Owin.Hosting.3.0.1\lib\net45\Microsoft.Owin.Hosting.dll
79 | True
80 |
81 |
82 | ..\packages\Microsoft.Owin.Security.3.0.1\lib\net45\Microsoft.Owin.Security.dll
83 | True
84 |
85 |
86 | ..\packages\Microsoft.Owin.Security.Cookies.3.0.1\lib\net45\Microsoft.Owin.Security.Cookies.dll
87 | True
88 |
89 |
90 | ..\packages\Microsoft.Owin.Testing.3.0.1\lib\net45\Microsoft.Owin.Testing.dll
91 | True
92 |
93 |
94 | False
95 | ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll
96 |
97 |
98 | ..\packages\NUnit.2.6.3\lib\nunit.framework.dll
99 |
100 |
101 | ..\packages\Owin.1.0\lib\net40\Owin.dll
102 |
103 |
104 |
105 |
106 |
107 |
108 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
109 | True
110 |
111 |
112 |
113 |
114 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll
115 | True
116 |
117 |
118 | ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll
119 | True
120 |
121 |
122 | ..\packages\Microsoft.AspNet.WebApi.SelfHost.5.2.3\lib\net45\System.Web.Http.SelfHost.dll
123 | True
124 |
125 |
126 | ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll
127 | True
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 | Global.asax
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 | StrongKey.snk
160 |
161 |
162 |
163 | Designer
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 | {ff00d5e5-9581-4047-a5ee-cb968a567ee2}
174 | Client.StrongName
175 |
176 |
177 | {2ef04e20-6cd8-420d-bac4-192ecd3f9ad5}
178 | Core.StrongName
179 |
180 |
181 | {aa0cd548-e262-44ab-9aa2-a7ada6998c99}
182 | Server.Owin.StrongName
183 |
184 |
185 | {297ac86e-3b54-4e76-a4ea-a5bf1e730d6f}
186 | Server.StrongName
187 |
188 |
189 |
190 |
197 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------