Click here to Skip to main content
5,790,650 members and growing! (18,940 online)
Email Password   helpLost your password?
Web Development » ASP.NET » General     Intermediate License: The Code Project Open License (CPOL)

HTTP compression in the .NET Framework 1.1

By Paulo Morgado

An article on HTTP compression in the .NET Framework 1.1.
C#, XML, Windows, .NET 1.1, .NET, ASP.NET, Visual Studio, VS.NET2003, Dev

Posted: 6 Jan 2006
Updated: 6 Jan 2006
Views: 45,864
Bookmarked: 50 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
16 votes for this Article.
Popularity: 5.09 Rating: 4.23 out of 5
1 vote, 6.3%
1
1 vote, 6.3%
2
0 votes, 0.0%
3
2 votes, 12.5%
4
12 votes, 75.0%
5

Introduction

This article will show how to request for HTTP compression and handle a compressed response from a web server (or any appliance connected to the server) without changing the client application.

The factory pattern of creating WebRequest instances

The WebRequest supplies two methods to create instances:

The WebRequest class uses instances of classes that implement the IWebRequestCreate interface and are registered in the webRequestModules section in the configuration files. The Create method (called by both CreateDefault and Create) returns an initialized instance of a WebRequest descendent class capable of performing a standard request/response transaction for the protocol without needing any protocol-specific fields modified.

Because we can control the WebRequest factory using the configuration files, we can change the behavior of already built applications (our applications, or even the .NET Framework) to request and handle HTTP compression without changing them.

The WebRequest descendent instances will be responsible to create the WebResponse descendent instance that will handle the response from the web server.

The code

As shown before, to add HTTP compression to our applications, we just have to build three classes:

  • CompressibleHttpRequestCreator - implementing the IWebRequestCreate interface.
  • CompressibleHttpWebRequest - derived from WebRequest.
  • CompressibleHttpWebResponse - derived from WebResponse.

    In order for the applications that use HttpWebRequest and HttpWebResponse to work without any changes, CompressibleHttpWebRequest has to derive from HttpWebRequest, and CompressibleHttpWebResponse has to derive from HttpWebResponse.

    Fortunately, HttpWebRequest and HttpWebResponse are not sealed (NotInheritable in VB.NET). Unfortunately, these classes don't have any public constructor, and the only protected constructor each one has is the one required by the implementation of the ISerializable interface. Due to this drawback, reflection must be used.

    CompressibleHttpRequestCreator

    This is the class that will be implementing the IWebRequestCreate interface and is used to create HttpWebRequest descendant instances.

    As mentioned before, the only way to create an instance of a HttpWebRequest derived class, is by deserialization. To accomplish this, an instance of HttpWebRequest will be created, serialized, and deserialized into an instance of CompressibleHttpWebRequest.

    public class CompressibleHttpRequestCreator : IWebRequestCreate
    {
        WebRequest IWebRequestCreate.Create(Uri uri)
        {
            ISerializable httpWebRequest = Activator.CreateInstance(
                typeof(HttpWebRequest),
                BindingFlags.CreateInstance | BindingFlags.Public | 
                BindingFlags.NonPublic | BindingFlags.Instance,
                null,
                new object[] { uri },
                null) as ISerializable;
    
            if (httpWebRequest == null)
            {
                return null;
            }
    
            SerializationInfo serializationInfo = new SerializationInfo(
                typeof(CompressibleHttpWebRequest), new FormatterConverter());
            StreamingContext streamingContext = 
                new StreamingContext(StreamingContextStates.All);
            httpWebRequest.GetObjectData(serializationInfo, streamingContext);
    
            CompressibleHttpWebRequest webRequest = new 
                CompressibleHttpWebRequest(serializationInfo, streamingContext);
            webRequest.Method = serializationInfo.GetString("_OriginVerb");
    
            return webRequest;
        }
    }

    CompressibleHttpWebRequest

    This class will handle the setup of the HTTP request and the creation of the HttpWebResponse derived instance to handle the response.

    As with CompressibleHttpWebRequest, when creating the HttpWebResponse, an instance of HttpWebResponse will be created, serialized, and deserialized into an instance of CompressibleHttpWebResponse.

    To specify what types of compression will be accepted in the response, the AcceptEncodings will be used. Its value will, also, be used to set the accept-encoding HTTP header in the request (in the BeginGetResponse). The possible values for AcceptEncodings are:

    • Identity - The default (identity) encoding; the use of no transformation whatsoever.
    • GZip - An encoding format produced by the file compression program "gzip" (GNU zip) as described in RFC 1952 [25]. This format is a Lempel-Ziv coding (LZ77) with a 32 bit CRC.
    • Deflate - The "zlib" format defined in RFC 1950 [31] in combination with the "deflate" compression mechanism described in RFC 1951 [29].
    [Serializable]
    public class CompressibleHttpWebRequest : HttpWebRequest
    {
        private static FieldInfo m_UsesProxySemanticsFieldInfo = 
            typeof(HttpWebResponse).GetField("m_UsesProxySemantics", 
            BindingFlags.NonPublic | BindingFlags.Instance);
        private static FieldInfo m_ConnectStreamFieldInfo = 
            typeof(HttpWebResponse).GetField("m_ConnectStream", 
            BindingFlags.NonPublic | BindingFlags.Instance);
        private AcceptEncodings acceptEncodings = AcceptEncodings.GZip | 
            AcceptEncodings.Deflate | AcceptEncodings.Identity;
    
        public AcceptEncodings AcceptEncodings
        {
            get
            {
                return this.acceptEncodings;
            }
            set
            {
                this.acceptEncodings = value;
            }
        }
    
        protected internal CompressibleHttpWebRequest(SerializationInfo 
                  serializationInfo, StreamingContext 
                  streamingContext) : base(serializationInfo, 
                                           streamingContext)
        {
        }
    
        public override IAsyncResult 
            BeginGetResponse(AsyncCallback callback, object state)
        {
            if (this.acceptEncodings != AcceptEncodings.Identity)
            {
                this.Headers.Add("Accept-Encoding",
                    (this.acceptEncodings & 
                       ~AcceptEncodings.Identity).ToString().ToLower());
            }
            return base.BeginGetResponse(callback, state);
        }
    
        public override WebResponse EndGetResponse(IAsyncResult asyncResult)
        {
            ISerializable httpWebResponse = 
               base.EndGetResponse(asyncResult) as ISerializable;
            if (httpWebResponse == null)
            {
                return null;
            }
    
            SerializationInfo serializationInfo = new 
                SerializationInfo(typeof(CompressibleHttpWebResponse),
                new FormatterConverter());
            StreamingContext streamingContext = new 
                StreamingContext(StreamingContextStates.All);
            httpWebResponse.GetObjectData(serializationInfo, streamingContext);
            CompressibleHttpWebResponse webResponse = new 
                CompressibleHttpWebResponse(serializationInfo,
                streamingContext);
            m_UsesProxySemanticsFieldInfo.SetValue(webResponse, 
                m_UsesProxySemanticsFieldInfo.GetValue(httpWebResponse));
            m_ConnectStreamFieldInfo.SetValue(webResponse, 
                m_ConnectStreamFieldInfo.GetValue(httpWebResponse));
    
            return webResponse;
        }
    }

    CompressibleHttpWebResponse

    This is the easiest one. All that's needed is to handle the response stream accordingly to the content-encoding HTTP response header. Unfortunately, the .NET Framework 1.1 base classes don't provide any class for handling Deflate and GZip streams. For that, the SharpZipLib will be used.

    [Serializable]
    public class CompressibleHttpWebResponse : HttpWebResponse
    {
        public CompressibleHttpWebResponse(SerializationInfo 
            serializationInfo, StreamingContext streamingContext)
            : base(serializationInfo, streamingContext)
        {
        }
    
        public override Stream GetResponseStream()
        {
            Stream stream = base.GetResponseStream();
    
            if (stream == null)
            {
                return Stream.Null;
            }
    
            if (string.Compare(ContentEncoding, "gzip", true) == 0)
            {
                return new GZipInputStream(stream);
            }
            else if (string.Compare(ContentEncoding, "deflate", true) == 0)
            {
                return new InflaterInputStream(stream);
            }
            else
            {
                return stream;
            }
        }
    }

    Configuration

    Now, to add HTTP compression support to any application, all that's needed is to add the corresponding entry to the webRequestModules section in the configuration file.

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <system.net>
            <webRequestModules>
                  <add prefix="http" 
                    type="PaJoCoMo.Net.CompressibleHttpRequestCreator, PaJoCoMo" />
              </webRequestModules>
        </system.net>
    </configuration>
  • License

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

    About the Author

    Paulo Morgado


    Paulo has a bachelor degree in Electronics and Telecommunications (Digital Systems) by the Instituto Superior de Engenharia de Lisboa and a degree of licentiate in Informatics by the Faculdade de Ciências da Universidade Nova de Lisboa and na MCSD for Microsoft .NET certification.


    Paulo has also a MCSD for the .NET Framework certification.


    Paulo works at Espírito Santo Informática, ACE as a developer/software architect.


    Paulo contributes in the Microsoft Portuguese newsgroups and the PontoNetPT community answering questions about software development posted in the (with special focus on the .NET framework).


    His growing interest in software architecture drives his participation in the Portuguese Group of Software Architecture – GASP.


    His contributions to the community has earned him Microsoft's Most Valuable Professional award.


    Blog: http://www.PauloMorgado.NET/


    Occupation: Software Developer (Senior)
    Company: Paulo Morgado
    Location: Portugal Portugal

    Other popular ASP.NET articles:

    Article Top
    Sign Up to vote for this article
    You must Sign In to use this message board.
    FAQ FAQ Noise ToleranceSearch Search Messages 
     Layout  Per page   
     Msgs 1 to 25 of 64 (Total in Forum: 64) (Refresh)FirstPrevNext
    GeneralBinaries?memberalandraper16:29 23 Oct '08  
    GeneralRe: Binaries?memberPaulo Morgado23:18 23 Oct '08  
    GeneralRe: Binaries?memberalandraper6:26 24 Oct '08  
    GeneralWeb Services?memberalandraper16:28 23 Oct '08  
    GeneralRe: Web Services?memberPaulo Morgado23:01 23 Oct '08  
    GeneralRe: Web Services?memberalandraper6:24 24 Oct '08  
    QuestionRe: Web Services?memberalandraper15:00 25 Oct '08  
    AnswerRe: Web Services?memberPaulo Morgado15:23 2 Nov '08  
    GeneralRe: Web Services?memberalandraper18:24 2 Nov '08  
    GeneralRe: Web Services?memberPaulo Morgado19:25 2 Nov '08  
    GeneralHttp Compressionmemberattalurisubbu4:43 9 Oct '08  
    GeneralRe: Http CompressionmemberPaulo Morgado12:40 9 Oct '08  
    GeneralRe: Http Compressionmemberattalurisubbu21:05 9 Oct '08  
    GeneralRe: Http CompressionmemberPaulo Morgado23:04 9 Oct '08  
    GeneralRe: Http Compressionmemberattalurisubbu2:48 13 Oct '08  
    GeneralRe: Http CompressionmemberPaulo Morgado13:30 13 Oct '08  
    GeneralRe: Http Compressionmemberpooja mehta2:04 13 Dec '08  
    GeneralRe: Http CompressionmemberPaulo Morgado8:20 13 Dec '08  
    GeneralRegard Http Compressionmemberattalurisubbu3:56 9 Oct '08  
    Questionhey dude, I need some help with this as it didnt work for mememberskilledguru15:38 13 Aug '08  
    AnswerRe: hey dude, I need some help with this as it didnt work for mememberPaulo Morgado23:10 13 Aug '08  
    QuestionRe: hey dude, I need some help with this as it didnt work for mememberskilledguru7:11 14 Aug '08  
    AnswerRe: hey dude, I need some help with this as it didnt work for mememberPaulo Morgado12:45 17 Aug '08  
    GeneralAwsomememberEyal Itskovits6:13 19 May '08  
    GeneralRe: AwsomememberPaulo Morgado9:49 19 May '08  

    General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    PermaLink | Privacy | Terms of Use
    Last Updated: 6 Jan 2006
    Editor: Smitha Vijayan