Compressão HTTP no .NET Framework 2.0

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (0)  (0)

Veja neste artigo, como realizar compressão HTTP na versão 2.0 do .NET Framework.

Compressão HTTP no .NET  Framework 2.0

 

Este artigo descreve a implementação de classes utilitárias que permitirão às requisições de HTTP informar ao Server (ou a qualquer aplicação na rede entre o cliente e o Server), que tipos de compressão poderão manipular, e descompactar a resposta do Server (caso exista), sem alterar a aplicação cliente. A compressão HTTP é muito útil quando o custo da conexão for alto.  O factory pattern de criar instâncias WebRequest. O WebRequest provê dois métodos para criar instâncias:

 

CreateDefault - Inicializa uma nova instância WebRequest para o esquema de URI especificado.

Create - Inicializa nova instância WebRequest para o esquema de URI especificado.

 

A classe WebRequest usa instâncias de classes que implementam a conexão IWebRequestCreate e são registradas na seção webRequestModules dos arquivos de configuração. O método Create (chamado por CreateDefault e Create) retorna uma instância inicializada de uma classe WebRequest descendente, capaz de executar uma transação request/response padrão para o protocolo, sem que qualquer campo específico do mesmo seja modificado.

 

Por outro lado, as instâncias derivadas do WebRequest previamente criado, retornarão instâncias derivadas WebResponse que tratarão a resposta de HTTP.

Por causa do modo como é implementado o factory pattern, podemos mudar o comportamento das aplicações já existentes (nossas aplicações ou mesmo as do .NET  Framework), para solicitar e manipular a compressão HTTP, alterando apenas os arquivos de configuração.

O código

Como mostrado antes, para acrescentar compressão HTTP às nossas aplicações, temos apenas que construir três classes:

 

CompressibleHttpRequestCreator – que implementa a interface IWebRequestCreate.

CompressibleHttpWebRequest - derivada de WebRequest.

CompressibleHttpWebResponse - derivada de WebResponse.

 

Para que as aplicações que usam o HttpWebRequest e o HttpWebResponse possam funcionar sem qualquer alteração, o CompressibleHttpWebRequest tem que derivar de HttpWebRequest e o CompressibleHttpWebResponse tem que derivar de HttpWebResponse.

Felizmente, HttpWebRequest e HttpWebResponse não são “sealed” (NotInheritable em VB.NET). Infelizmente, estas classes não têm nenhum constructor público e o único constructor protected (Protected em VB.NET) que tem, é o único requerido pela implementação da interface ISerializable. Devido a esta desvantagem, devemos utilizar reflexão.

CompressibleHttpRequestCreator

Esta é a classe que implementará a interface  do IWebRequestCreate e é utilizada para criar instâncias descendentes de WebRequest.

Como mencionado antes, o único modo de criarmos uma instância de uma classe HttpWebRequest derivada, é via deserialização. Para tanto, criaremos uma instância de HttpWebRequest, a qual será serializada e desserializeda em uma isntância de CompressibleHttpWebRequest. Para garantir consistência, serão copiados todos os valores de campos da instância HttpWebRequest anteriormente criada, para a nova instância CompressibleHttpWebRequest.

 

public class CompressibleHttpRequestCreator: IWebRequestCreate

{

    public CompressibleHttpRequestCreator()

    {

    }

 

    WebRequest IWebRequestCreate.Create(Uri uri)

    {

        ISerializable httpWebRequest =

            Activator.CreateInstance(typeof(HttpWebRequest),

            BindingFlags.CreateInstance | BindingFlags.Public |

            BindingFlags.NonPublic | BindingFlags.Instance,

            null, new object[] { uri, null }, 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 compressibleHttpRequest = new

            CompressibleHttpWebRequest(serializationInfo, streamingContext);

        Utils.FieldCopy(httpWebRequest, compressibleHttpRequest);

 

        return compressibleHttpRequest;

    }

}

 

CompressibleHttpWebRequest

Esta classe manipulará a preparação (setup) da requisição de HTTP e a criação da Instância derivada HttpWebResponse para manipular a resposta. Para especificar quais tipos de compressão serão aceitos na resposta, será utilizado o AcceptEncodings. Seu valor será também utilizado para configurar o cabeçalho accept-encoding (accept-encoding header) de HTTP na requisição (antes da chamada de HttpWebRequest.BeginGetResponse e de HttpWebRequest.GetResponse). Os possíveis valores para AcceptEncodings são:

 

Identity - a codificação padrão (identity); não necessita de nenhuma transformação.

GZip - um formato de codificação produzido pelo programa de compressão de arquivos “gzip" (GNU zip) como descrito em RFC 1952 [25]. Este formato é um código Lempel-Ziv (LZ77) com um CRC de 32 bits.

Deflate – o formato "zlib" definido em RFC 1950 [31] em combinação com o mecanismo de compressão “deflate" descrito em RFC 1951 [29].

 

Como acontece com o CompressibleHttpWebRequest, ao criarmos a instância CompressibleHttpWebResponse, uma instância HttpWebResponse será criada, serializada e deserializada em uma instância CompressibleHttpWebResponse (depois da chamada para HttpWebRequest.EndGetResponse e HttpWebRequest.GetResponse).

 

[ISerializable]

public class CompressibleHttpWebRequest : HttpWebRequest

{

    private AcceptEncodings acceptEncodings = AcceptEncodings.GZip |

                 AcceptEncodings.Deflate | AcceptEncodings.Identity;

 

    protected internal CompressibleHttpWebRequest(SerializationInfo

        serializationInfo, StreamingContext streamingContext)

        : base(serializationInfo, streamingContext)

    {

    }

 

    public AcceptEncodings AcceptEncodings

    {

        get

        {

            return this.acceptEncodings;

        }

        set

        {

            this.acceptEncodings = value;

        }

    }

 

    public override IAsyncResult

           BeginGetResponse(AsyncCallback callback, object state)

    {

        BeforeGetResponse();

        return base.BeginGetResponse(callback, state);

    }

 

    public override WebResponse GetResponse()

    {

        BeforeGetResponse();

        return AfterGetResponse(base.GetResponse() as ISerializable);

    }

 

    public override WebResponse EndGetResponse(IAsyncResult asyncResult)

    {

        return AfterGetResponse(base.EndGetResponse(asyncResult)

                                              as ISerializable);

    }

 

    private void BeforeGetResponse()

    {

        if (this.acceptEncodings != AcceptEncodings.Identity)

        {

            this.Headers.Add("Accept-Encoding",

                 (this.acceptEncodings &

                 ~AcceptEncodings.Identity).ToString().ToLower());

        }

    }

 

    private WebResponse AfterGetResponse(ISerializable httpWebResponse)

    {

        if (httpWebResponse == null)

        {

            return null;

        }

 

        SerializationInfo serializationInfo = new

           SerializationInfo(typeof(CompressibleHttpWebResponse),

           new FormatterConverter());

        StreamingContext streamingContext = new

           StreamingContext(StreamingContextStates.All);

        httpWebResponse.GetObjectData(serializationInfo, streamingContext);

 

        CompressibleHttpWebResponse compressibleHttpWebResponse = new

           CompressibleHttpWebResponse(serializationInfo, streamingContext);

        Utils.FieldCopy(httpWebResponse, compressibleHttpWebResponse);

 

        return compressibleHttpWebResponse;

    }

}

CompressibleHttpWebResponse

Esta é a mais fácil. Tudo que é preciso fazer, é manipular o fluxo de resposta de acordo com o cabeçalho de resposta  content-encoding http (content-encoding HTTP response header). Felizmente, o .NET  Framework 2.0 provê classes para manipular streams Deflate e GZip, no System.IO.Compression, namespace.

GZip - System.IO.Compression.GZipStream.

Deflate - System.IO.Compression.DeflateStream.

Qualquer outro - nenhuma descompressão será realizada.

 

[ISerializable]

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 System.IO.Compression.GZipStream(stream,

                                   CompressionMode.Decompress);

        }

        else if (string.Compare(ContentEncoding,

                          "deflate", true) == 0)

        {

            return new System.IO.Compression.DeflateStream(stream,

                                      CompressionMode.Decompress);

        }

        else

        {

            return stream;

        }

    }

}

Configuração

Agora, para acrescentar suporte de compressão HTTP a qualquer aplicação, tudo que é necessário fazer é acrescentar as entradas correspondentes à seção webRequestModules d derivadas do arquivo configuração.

 

 

   

     

     

            type="Pajocomo.Net.CompressibleHttpRequestCreator, Pajocomo" />

   

 

 

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?