How to return a compressed response?

Dec 23, 2010 at 2:26 PM

My base is the simple HttpListener tutorial. I'm try to respond to request with gzip compression with the handler below. It works fine when my request declare it doesn't accept gzip or deflate compression. When I use a gzip or deflate compatible browser, it returns an empty string.

private static void OnRequest(object sender, HttpServer.RequestEventArgs e)
        {
            IHttpClientContext context = (IHttpClientContext)sender;
            IHttpRequest request = e.Request;

            string acceptEncoding = request.Headers["Accept-Encoding"];
            string responseBody = "This is some random text";

            IHttpResponse response = request.CreateResponse(context);

            if (acceptEncoding != null && acceptEncoding.Contains("gzip"))
            {
                byte[] bytes = ASCIIEncoding.ASCII.GetBytes(responseBody);
                response.AddHeader("Content-Encoding", "gzip");

                using (GZipStream writer = new GZipStream(response.Body, CompressionMode.Compress))
                {
                    writer.Write(bytes, 0, bytes.Length);
                    writer.Flush();
                    response.Send();
                }
            }
            else if (acceptEncoding != null && acceptEncoding.Contains("deflate"))
            {
                byte[] bytes = ASCIIEncoding.ASCII.GetBytes(responseBody);
                response.AddHeader("Content-Encoding", "gzip");

                using (DeflateStream writer = new DeflateStream(response.Body, CompressionMode.Compress))
                {
                    writer.Write(bytes, 0, bytes.Length);
                    writer.Flush();
                    response.Send();
                }
            }
            else
            {
                using (StreamWriter writer = new StreamWriter(response.Body))
                {
                    writer.WriteLine(responseBody);
                    writer.Flush();
                    response.Send();
                }
            }
        }

Coordinator
Dec 29, 2010 at 3:16 PM

Which library do you use to compress the streams? I might add the support to the web server directly.

Dec 29, 2010 at 3:25 PM

I found the answer.

GZipStream must be closed before you read from the underlying stream. BecauseGZipStream write the mandatory gzip footer in GZipStream.Dispose.

The following code will work:

using (MemoryStream stream = new MemoryStream())
{
     using (GZipStream gZipStream = new GZipStream(stream, CompressionMode.Compress))
     gZipStream.Write(bytes, 0, bytes.Length);

     byte[] compressed = stream.ToArray();
     response.Body.Write(compressed, 0, compressed.Length);

     response.Send();
}