Click here to Skip to main content
15,892,746 members
Articles / Web Development / ASP.NET

HTTP Compression Module

Rate me:
Please Sign up or sign in to vote.
4.81/5 (39 votes)
19 Mar 2008CPOL6 min read 368.1K   4.8K   153  
A compression module for ASP.NET that works with WebResource.axd, JavaScript, and CSS
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.IO;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Net;
using System.Configuration;

namespace DC.Web.HttpCompress
{
    public abstract class Compress
    {
        protected bool gzip, deflate;
        protected string cachedir, cachefile, encoding, hash;
        protected FileType type;
        protected MemoryStream dataStream;
        protected HttpContext context;
        private Configuration settings;

        // get the settings
        protected Configuration Settings
        {
            get 
            {
                if (settings == null)
                {
                    if (context.Cache["DCCompressModuleConfig"] == null)
                    {
                        settings = (Configuration)ConfigurationManager.GetSection("DCWeb/HttpCompress");
                        context.Cache["DCCompressModuleConfig"] = settings;
                    }
                    else
                        settings = (Configuration)context.Cache["DCCompressModuleConfig"];
                    if (settings != null)
                    {
                        context.Cache.Insert("DCCompressModuleConfig", settings);
                    }
                }
                return settings; 
            }
        }
        // get the cache directory
        public string Cachedir
        {
            get
            {
                if (cachedir == null)
                {
                    cachedir = GetDirectory(Settings.CacheSettings.Path);
                }
                return cachedir;
            }
            set { cachedir = value; }
        }

        public void Init()
        {
            gzip = deflate = false;
            encoding = "none";
            dataStream = new MemoryStream();            
        }

        protected abstract void SetCachefile();

        // check if 'HTTP_IF_NONE_MATCH' is set. Denotes file is cached on browser.
        protected bool IsCachedOnBrowser()
        {
            
            if (!string.IsNullOrEmpty(context.Request.ServerVariables["HTTP_IF_NONE_MATCH"]) &&
                context.Request.ServerVariables["HTTP_IF_NONE_MATCH"].Equals(hash))
            {
                context.Response.ClearHeaders();
                context.Response.AppendHeader("Etag", hash);
                context.Response.Status = "304 Not Modified";
                context.Response.AppendHeader("Content-Length", "0");
                return true;
            }
            return false;
        }
        // Send a chached file
        protected void SendCachedFile()
        {
            context.Response.ClearHeaders();
            context.Response.AppendHeader("Etag", hash);
            FileInfo info = new FileInfo(cachefile);
            if (encoding != "none")
                context.Response.AppendHeader("Content-Encoding", encoding);
            context.Response.ContentType = "text/" + type;
            context.Response.AppendHeader("Content-Length", info.Length.ToString());
            context.Response.WriteFile(cachefile);
        }
        // Send the data
        protected void SendFile()
        {
            byte[] data;

            context.Response.ClearHeaders();
            context.Response.AppendHeader("Etag", hash);            
            // compress the data
            if (encoding != "none")
            {
                data = CompressData(dataStream.ToArray(), encoding);
                context.Response.AppendHeader("Content-Encoding", encoding);
            }
            else
            {
                data = dataStream.ToArray();
            }
            // write the data out
            context.Response.ContentType = "text/" + type;
            context.Response.AppendHeader("Content-Length", data.Length.ToString());
            context.Response.BinaryWrite(data);
            // cache the file
            if (Settings.CacheSettings.CacheFiles)
                File.WriteAllBytes(cachefile, data);

            dataStream.Dispose();
        }

        // get the encoding type, not sure if this is the best way, but I got if from somewhere else.
        // Also can be converted to use the enums
        protected void SetEncoding()
        {
            // get the type of compression to use
            if (!string.IsNullOrEmpty(context.Request.ServerVariables["HTTP_ACCEPT_ENCODING"]))
            {
                // get supported compression methods
                gzip = context.Request.ServerVariables["HTTP_ACCEPT_ENCODING"].ToLower().Contains("gzip");
                deflate = context.Request.ServerVariables["HTTP_ACCEPT_ENCODING"].ToLower().Contains("deflate");
            }

            //determin which to use
            encoding = gzip ? "gzip" : (deflate ? "deflate" : "none");

            // check for buggy versions of Internet Explorer
            if (context.Request.Browser.Browser == "IE")
            {
                if (context.Request.Browser.MajorVersion < 6)
                    encoding = "none";
                else if (context.Request.Browser.MajorVersion == 6 &&
                    !string.IsNullOrEmpty(context.Request.ServerVariables["HTTP_USER_AGENT"]) &&
                    context.Request.ServerVariables["HTTP_USER_AGENT"].Contains("EV1"))
                    encoding = "none";
            }
        }
        protected static byte[] StrToByteArray(string str)
        {
            ASCIIEncoding encoding = new ASCIIEncoding();
            return encoding.GetBytes(str);
        }
        // compress the data
        protected byte[] CompressData(byte[] data, string type)
        {
            byte[] returnData;
            MemoryStream memStream = new MemoryStream();
            Stream compress = null;

            if (type == "gzip")
                compress = new GZipStream(memStream, CompressionMode.Compress);
            else if (type == "deflate")
                compress = new DeflateStream(memStream, CompressionMode.Compress);
            else
                throw new ApplicationException("Invalid compression type");

            compress.Write(data, 0, data.Length);
            returnData = memStream.ToArray();
            compress.Dispose();
            memStream.Dispose();
            return returnData;
        }
        // gets the directory set in the config file and deals with '/', '~/'
        protected string GetDirectory(string path)
        {
            path = path.Replace("/", "\\");
            if (path.StartsWith("\\"))
                path = path.Substring(1);
            else if (path.StartsWith("~\\"))
                path = path.Substring(2);
            path = context.Request.PhysicalApplicationPath + path;
            if (!path.EndsWith("\\"))
                path += "\\";
            return path;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions