Compression
It is obvious that we need to compress our response while passing it to the client. Compressed requests and responses always increase the performance of sites. Nowadays, almost 99 percent of browsers support either Gzip or Deflate compression or both. So, if we can check if the accept-encoding header is present and return a compressed response to the client, then we have just improved our site performance. Just take a look at the code below:
public static void doCompression()
{
HttpContext context = HttpContext.Current;
HttpRequest request = context.Request;
string acceptEncoding = request.Headers["Accept-Encoding"];
HttpResponse response = context.Response;
if (!string.IsNullOrEmpty(acceptEncoding))
{
acceptEncoding = acceptEncoding.ToUpperInvariant();
if (acceptEncoding.Contains("GZIP"))
{
response.Filter = new GZipStream(context.Response.Filter,
CompressionMode.Compress);
response.AppendHeader("Content-encoding", "gzip");
}
else if (acceptEncoding.Contains("DEFLATE"))
{
response.Filter = new DeflateStream(context.Response.Filter,
CompressionMode.Compress);
response.AppendHeader("Content-encoding", "deflate");
}
}
response.Cache.VaryByHeaders["Accept-Encoding"] = true;
}
Here, we are checking if the Request header contains [“Accept-Encoding”]. Based on the encoding it supports, we filter the response using GZipStream
/ DeflateStream
which are available in the System.IO.Compression
namespace. Thus the response will be compressed. Only, this will not help the client to render your page properly. You need to add the Content-Encoding header to the response, so it can decompress the response in the client properly. We add a Response header “Accept-Encoding” so that the request is also made using the same encoding it is sending the data in.
You can also remove whitespaces from your HTML to shrink the response. Use this class:
public enum CompressOptions
{
GZip,
Deflate,
None
}
public class WhitespaceFilter : Stream
{
private GZipStream _contentGZip;
private DeflateStream _content_Deflate;
private Stream _content;
private CompressOptions _options;
public WhitespaceFilter(Stream content, CompressOptions options)
{
if (options == CompressOptions.GZip)
{
this._contentGZip = new GZipStream(content, CompressionMode.Compress);
this._content = this._contentGZip;
}
else if (options == CompressOptions.Deflate)
{
this._content_Deflate = new DeflateStream(content,
CompressionMode.Compress);
this._content = this._content_Deflate;
}
else
{
this._content = content;
}
this._options = options;
}
public override bool CanRead
{
get { return this._content.CanRead; }
}
public override bool CanSeek
{
get { return this._content.CanSeek; }
}
public override bool CanWrite
{
get { return this._content.CanWrite; }
}
public override void Flush()
{
this._content.Flush();
}
public override long Length
{
get { return this._content.Length; }
}
public override long Position
{
get
{
return this._content.Position;
}
set
{
this._content.Position = value;
}
}
public override int Read(byte[] buffer, int offset, int count)
{
return this._content.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return this._content.Seek(offset, origin);
}
public override void SetLength(long value)
{
this._content.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
byte[] data = new byte[count + 1];
Buffer.BlockCopy(buffer, offset, data, 0, count);
string s = System.Text.Encoding.UTF8.GetString(data);
s = Regex.Replace(s, "^\\s*",string.Empty, RegexOptions.Compiled |
RegexOptions.Multiline);
s = Regex.Replace(s, "\\r\\n", string.Empty, RegexOptions.Compiled |
RegexOptions.Multiline);
s = Regex.Replace(s, "<!--*.*?-->", string.Empty, RegexOptions.Compiled |
RegexOptions.Multiline);
byte[] outdata = System.Text.Encoding.UTF8.GetBytes(s);
this._content.Write(outdata, 0, outdata.GetLength(0));
}
}
To use it, just write:
internal void Compress()
{
HttpContext context = HttpContext.Current;
HttpRequest request = context.Request;
string acceptEncoding = request.Headers["Accept-Encoding"];
HttpResponse response = context.Response;
if (!string.IsNullOrEmpty(acceptEncoding))
{
acceptEncoding = acceptEncoding.ToUpperInvariant();
if (acceptEncoding.Contains("GZIP"))
{
response.Filter = new WhitespaceFilter(context.Response.Filter,
CompressOptions.GZip);
response.AppendHeader("Content-encoding", "gzip");
}
else if (acceptEncoding.Contains("DEFLATE"))
{
response.Filter = new WhitespaceFilter(context.Response.Filter,
CompressOptions.Deflate);
response.AppendHeader("Content-encoding", "deflate");
}
}
response.Cache.VaryByHeaders["Accept-Encoding"] = true;
}
Note: The Regular Expressions that I have used will remove extra spaces, newlines, and comments from the HTML. Thus, it will reduce the size of the HTML. Also, before using it in production, check how it is working, because you need to change the Regular Expressions according to your needs.