Scott
Scott

Reputation: 904

How to compress a HttpWebRequest POST

I am trying to post data to server that accepts compressed data. The code below works just fine, but it is uncompressed. I have not worked with compression or Gzip beofre, so any help is appriciated.

HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
  request.Timeout = 600000;
  request.Method = verb;  // POST    
  request.Accept = "text/xml";

  if (!string.IsNullOrEmpty(data))
  {
    request.ContentType = "text/xml";        

    byte[] byteData = UTF8Encoding.UTF8.GetBytes(data);
    request.ContentLength = byteData.Length;       

    // Here is where I need to compress the above byte array using GZipStream

    using (Stream postStream = request.GetRequestStream())
    {
      postStream.Write(byteData, 0, byteData.Length);         
    }
  }      

  XmlDocument xmlDoc = new XmlDocument();
  HttpWebResponse response = null;
  StreamReader reader = null;
  try
  {
    response = request.GetResponse() as HttpWebResponse;
    reader = new StreamReader(response.GetResponseStream());
    xmlDoc.LoadXml(reader.ReadToEnd());
  }

Do I gzip the entire byte array? Do I need to add other headers or remove the one that is already there?

Thanks!

-Scott

Upvotes: 14

Views: 18712

Answers (4)

filipov
filipov

Reputation: 471

I also received the "Cannot close stream until all bytes are written" error using code similar to tnyfst's. The problem was that I had:

request.ContentLength = binData.Length;

where binData is my raw data before the compression. Obviously the length of the compressed content would be different, so I just removed this line and ended up with this code:

using (GZipStream zipStream = new GZipStream(request.GetRequestStream(), CompressionMode.Compress))
{
    zipStream.Write(binData, 0, binData.Length);
}

Upvotes: 5

Oscar Fraxedas
Oscar Fraxedas

Reputation: 4657

Try this extension method. The stream will be left open (see the GZipStream constructor). The stream position is set to 0 after the compression is done.

public static void GZip(this Stream stream, byte[] data)
{
    using (var zipStream = new GZipStream(stream, CompressionMode.Compress, true))
    {
        zipStream.Write(data, 0, data.Length);
    }
    stream.Position = 0;
}

You can use the following test:

[Test]
public void Test_gzip_data_is_restored_to_the_original_value()
{
    var stream = new MemoryStream();
    var data = new byte[]{1,2,3,4,5,6,7,8,9,10};

    stream.GZip(data);

    var decompressed = new GZipStream(stream, CompressionMode.Decompress);

    var data2 = new byte[10];
    decompressed.Read(data2,0,10);

    Assert.That(data, Is.EqualTo(data2));
}

For more information see: http://msdn.microsoft.com/en-us/library/hh158301(v=vs.110).aspx

Upvotes: 0

Ramiz Uddin
Ramiz Uddin

Reputation: 4259

In Page_Load event:

        Response.AddHeader("Content-Encoding", "gzip");

And for making compressed requests:

HttpWebRequest and GZip Http Responses by Rick Strahl

Upvotes: 1

tnyfst
tnyfst

Reputation: 1601

To answer the question you asked, to POST compressed data, all you need to do is wrap the request stream with a gzip stream

 using (Stream postStream = request.GetRequestStream())
 {
    using(var zipStream = new GZipStream(postStream, CompressionMode.Compress))
    {
        zipStream.Write(byteData, 0, byteData.Length);         
    }
 }

This is completely different than requesting a gzip response, which is a much more common thing to do.

Upvotes: 13

Related Questions