Roll your own gzip-encoded HTTP handler

While I’m sure we’ll have “out of the box” support for gzip-compressed HTTP responses pretty soon, it’s quite easy to do it yourself.

package main

import (
    "compress/gzip"
    "http"
    "io"
    "os"
    "strings"
)

type gzipResponseWriter struct {
    io.Writer
    http.ResponseWriter
}

func (w gzipResponseWriter) Write(b []byte) (int, os.Error) {
    return w.Writer.Write(b)
}

func makeGzipHandler(fn http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
            fn(w, r)
            return
        }
        w.Header().Set("Content-Encoding", "gzip")
        gz, err := gzip.NewWriter(w)
        if err != nil {
            http.Error(w, err.String(), http.StatusInternalServerError)
            return
        }
        defer gz.Close()
        fn(gzipResponseWriter{Writer: gz, ResponseWriter: w}, r)
    }
}

func handler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("This is a test."))
}

func main() {
    http.ListenAndServe(":8081", makeGzipHandler(handler))
}

One nicety this demonstrates is how easy it is to substitute a subset of one interface’s methods with those of another. The gzipResponseWriter has two embedded values. The methods from http.ReponseWriter that don’t conflict with the io.Writer are simply inherited. But because the http.ResponseWriter and io.Writer both have a Write method, we must write a shim Write method to pass through to the io.Writer.

16509 views and 3 responses

  • Apr 4 2011, 7:22 AM
    rogpeppe (Twitter) responded:
    But because the http.ResponseWriter and io.Writer both have a Write method, we must write a shim Write method to pass through to the io.Writer.

    Strictly speaking it's not necessary to write a shim method (although here there's only one method that they have in common, so it is the easiest approach).

    You could use the shallowest-first rule to get the same effect without writing any shim methods:


    type responseWriter struct {
    http.ResponseWriter
    }

    type gzipResponseWriter struct {
    io.Writer
    responseWriter
    }

    [...]

    fn(gzipResponseWriter{gz, responseWriter{w}}, r)

  • Mar 30 2012, 11:48 AM
    real estate developer responded:
    Hi, I am busy surfing the net for ideas for my blog. I love the subject on here and would love to use it. Thanks for the useful information, I will definately check back here soon.
  • Jul 8 2012, 12:15 PM
    Gregory Nicholas liked this post.