-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
David Murdoch
committed
May 9, 2011
1 parent
a3c399d
commit c88a77c
Showing
9 changed files
with
520 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
using System; | ||
using System.Configuration; | ||
using System.Linq; | ||
using System.Web; | ||
using System.Web.Configuration; | ||
|
||
namespace Compression | ||
{ | ||
public class CompressionConfiguration : ConfigurationSection | ||
{ | ||
#region Constructors | ||
static CompressionConfiguration() | ||
{ | ||
PFormat = new ConfigurationProperty( | ||
"format", | ||
typeof(CompressionFormat), | ||
CompressionFormat.deflate, // deflate is preferred | ||
ConfigurationPropertyOptions.None | ||
); | ||
|
||
PStaticTypes = new ConfigurationProperty( | ||
"staticTypes", | ||
typeof(StaticTypesElementCollection), | ||
null, | ||
ConfigurationPropertyOptions.IsRequired | ||
); | ||
|
||
PProperties = new ConfigurationPropertyCollection { | ||
PFormat, | ||
PStaticTypes | ||
}; | ||
} | ||
#endregion | ||
|
||
#region Enums | ||
|
||
public enum CompressionFormat | ||
{ | ||
// ReSharper disable InconsistentNaming | ||
deflate, | ||
gzip | ||
// ReSharper restore InconsistentNaming | ||
} | ||
|
||
#endregion | ||
|
||
#region Static Fields | ||
|
||
private static readonly ConfigurationProperty PFormat; | ||
private static readonly ConfigurationProperty PStaticTypes; | ||
|
||
private static readonly ConfigurationPropertyCollection PProperties; | ||
|
||
#endregion | ||
|
||
#region Properties | ||
|
||
/// <summary> | ||
/// Gets the BooleanValue setting. | ||
/// </summary> | ||
[ConfigurationProperty("format", IsRequired = false)] | ||
public CompressionFormat Format | ||
{ | ||
get { return (CompressionFormat)base[PFormat]; } | ||
} | ||
|
||
/// <summary> | ||
/// Override the Properties collection and return our custom one. | ||
/// </summary> | ||
protected override ConfigurationPropertyCollection Properties | ||
{ | ||
get { return PProperties; } | ||
} | ||
|
||
/// <summary> | ||
/// Gets the NestedElement element. | ||
/// </summary> | ||
[ConfigurationProperty("staticTypes")] | ||
public StaticTypesElementCollection StaticTypes | ||
{ | ||
get { return (StaticTypesElementCollection)base[PStaticTypes]; } | ||
} | ||
#endregion | ||
|
||
#region GetSection Pattern | ||
private static CompressionConfiguration _section; | ||
|
||
/// <summary> | ||
/// Gets the configuration section using the default element name. | ||
/// </summary> | ||
/// <remarks> | ||
/// If an HttpContext exists, uses the WebConfigurationManager | ||
/// to get the configuration section from web.config. | ||
/// </remarks> | ||
public static CompressionConfiguration GetSection() | ||
{ | ||
return GetSection("httpCompression"); | ||
} | ||
|
||
/// <summary> | ||
/// Gets the configuration section using the specified element name. | ||
/// </summary> | ||
/// <exception cref="ConfigurationException"></exception> | ||
/// <remarks> | ||
/// If an HttpContext exists, uses the WebConfigurationManager | ||
/// to get the configuration section from web.config. | ||
/// </remarks> | ||
public static CompressionConfiguration GetSection(string definedName) | ||
{ | ||
if (_section == null) | ||
{ | ||
string cfgFileName = ".config"; | ||
if (HttpContext.Current == null) | ||
{ | ||
_section = ConfigurationManager.GetSection(definedName) as CompressionConfiguration; | ||
} | ||
else | ||
{ | ||
_section = WebConfigurationManager.GetSection(definedName) as CompressionConfiguration; | ||
cfgFileName = "web.config"; | ||
} | ||
|
||
if (_section == null) | ||
{ | ||
throw new ConfigurationErrorsException("The <" + definedName + "> section is not defined in your " + cfgFileName + " file!"); | ||
} | ||
} | ||
|
||
return _section; | ||
} | ||
#endregion | ||
|
||
#region Methods | ||
|
||
public bool IsContentTypeCompressed(string contentTypeStr) | ||
{ | ||
try | ||
{ | ||
foreach (var staticType in from sType in StaticTypes.OfType<MimeFormatElement>() let mimeFormat = sType.MimeFormat where mimeFormat.Matches(contentTypeStr) select sType) | ||
{ | ||
return staticType.Enabled; | ||
} | ||
} | ||
catch | ||
{ | ||
return false; | ||
} | ||
return false; | ||
} | ||
|
||
public string GetCompressionType(string acceptEncoding) | ||
{ | ||
bool foundDeflate = false; | ||
bool foundGZip = false; | ||
|
||
string[] formats = acceptEncoding.Split(','); | ||
|
||
foreach (string acceptEncodingValue in formats.Select(t => t.Trim().ToLower())) | ||
{ | ||
if (acceptEncodingValue.Contains("deflate") && CanAcceptQuality(acceptEncodingValue)) | ||
{ | ||
foundDeflate = true; | ||
} | ||
else if ((acceptEncodingValue.Contains("gzip") || acceptEncodingValue.StartsWith("x-gzip")) && CanAcceptQuality(acceptEncodingValue)) | ||
{ | ||
foundGZip = true; | ||
} | ||
else if (acceptEncodingValue.StartsWith("*") && CanAcceptQuality(acceptEncodingValue)) | ||
{ | ||
foundGZip = true; | ||
foundDeflate = true; | ||
} | ||
} | ||
|
||
if (Format == CompressionFormat.deflate && foundDeflate) | ||
{ | ||
return "deflate"; | ||
} | ||
if (Format == CompressionFormat.gzip && foundGZip) | ||
{ | ||
return "gzip"; | ||
} | ||
|
||
return foundDeflate ? "deflate" : (foundGZip ? "gzip" : null); | ||
} | ||
|
||
static bool CanAcceptQuality(string acceptEncodingValue) | ||
{ | ||
int qParam = acceptEncodingValue.IndexOf("q="); | ||
|
||
float val = 1.0f; | ||
|
||
if (qParam >= 0) | ||
{ | ||
try | ||
{ | ||
val = float.Parse(acceptEncodingValue.Substring(qParam + 2, | ||
acceptEncodingValue.Length - (qParam + 2))); | ||
} | ||
catch (FormatException) | ||
{ | ||
|
||
} | ||
} | ||
return (val > 0.0f); | ||
} | ||
|
||
#endregion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using System; | ||
using System.ComponentModel; | ||
|
||
namespace Compression | ||
{ | ||
[TypeConverter(typeof(MimeFormatConverter))] | ||
public struct MimeFormat | ||
{ | ||
public string Format | ||
{ | ||
get | ||
{ | ||
return Type + "/" + SubType; | ||
} | ||
} | ||
public string Type; | ||
public string SubType; | ||
|
||
public MimeFormat(string mimeFormatStr) | ||
{ | ||
var parts = mimeFormatStr.Split('/'); | ||
if (parts.Length != 2) | ||
{ | ||
throw new Exception("Invalid MimeFormat"); | ||
} | ||
|
||
Type = parts[0]; | ||
SubType = parts[1]; | ||
} | ||
public MimeFormat(string mimeType, string mimeSubType) | ||
{ | ||
Type = mimeType; | ||
SubType = mimeSubType; | ||
} | ||
public bool Matches(string mimeFormatStr) | ||
{ | ||
try | ||
{ | ||
var mimeFormat = new MimeFormat(mimeFormatStr); | ||
return (Type == "*" || Type.Equals(mimeFormat.Type, StringComparison.CurrentCultureIgnoreCase)) && (SubType == "*" || SubType.Equals(mimeFormat.SubType, StringComparison.CurrentCultureIgnoreCase)); | ||
} | ||
catch | ||
{ | ||
return false; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
using System; | ||
using System.ComponentModel; | ||
using System.Globalization; | ||
|
||
namespace Compression | ||
{ | ||
public class MimeFormatConverter : TypeConverter | ||
{ | ||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) | ||
{ | ||
return sourceType == typeof(string); | ||
} | ||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) | ||
{ | ||
return new MimeFormat((string)value); | ||
} | ||
|
||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) | ||
{ | ||
return destinationType == typeof(string); | ||
} | ||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) | ||
{ | ||
var val = (MimeFormat)value; | ||
return val.Type + "/" + val.SubType; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
using System; | ||
using System.ComponentModel; | ||
using System.Configuration; | ||
using System.Web; | ||
|
||
namespace Compression | ||
{ | ||
public class MimeFormatElement: ConfigurationElement | ||
{ | ||
#region Constructors | ||
/// <summary> | ||
/// Predefines the valid properties and prepares | ||
/// the property collection. | ||
/// </summary> | ||
static MimeFormatElement() | ||
{ | ||
// Predefine properties here | ||
var mimeFormatType = typeof(MimeFormat); | ||
PMimeFormat = new ConfigurationProperty( | ||
"mimeFormat", | ||
mimeFormatType, | ||
"*/*", | ||
ConfigurationPropertyOptions.IsRequired | ||
); | ||
PEnabled = new ConfigurationProperty( | ||
"enabled", | ||
typeof(bool), | ||
false, | ||
ConfigurationPropertyOptions.IsRequired | ||
); | ||
|
||
PProperties = new ConfigurationPropertyCollection { | ||
PMimeFormat, PEnabled | ||
}; | ||
} | ||
#endregion | ||
|
||
#region Static Fields | ||
|
||
private static readonly ConfigurationProperty PMimeFormat; | ||
private static readonly ConfigurationProperty PEnabled; | ||
private static readonly ConfigurationPropertyCollection PProperties; | ||
|
||
#endregion | ||
|
||
#region Properties | ||
/// <summary> | ||
/// Gets the MimeFormat setting. | ||
/// </summary> | ||
[ConfigurationProperty("mimeFormat", IsRequired = true)] | ||
public MimeFormat MimeFormat | ||
{ | ||
get { return (MimeFormat)base[PMimeFormat]; } | ||
} | ||
|
||
/// <summary> | ||
/// Gets the Enabled setting. | ||
/// </summary> | ||
[ConfigurationProperty("enabled")] | ||
public bool Enabled | ||
{ | ||
get { return (bool)base[PEnabled]; } | ||
} | ||
|
||
/// <summary> | ||
/// Override the Properties collection and return our custom one. | ||
/// </summary> | ||
protected override ConfigurationPropertyCollection Properties | ||
{ | ||
get { return PProperties; } | ||
} | ||
#endregion | ||
} | ||
} |
Oops, something went wrong.