Skip to content

Instantly share code, notes, and snippets.

@blixt
Created May 5, 2017 16:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save blixt/f54f31f0b4437dca1f22a52b1996a931 to your computer and use it in GitHub Desktop.
Save blixt/f54f31f0b4437dca1f22a52b1996a931 to your computer and use it in GitHub Desktop.
A couple of middleware http.Handler functions for Go
// A couple of middleware http.Handler functions (scroll down).
// EXAMPLE USAGE:
http.HandleFunc("/", RequestHome)
http.Handle("/s/", Cacher(168*time.Hour, http.StripPrefix("/s/", http.FileServer(http.Dir("static")))))
http.Handle("/favicon.ico", FileWithCache("static/favicon.ico", 168*time.Hour))
if err := http.ListenAndServe(":8080", Logger(http.DefaultServeMux)); err != nil {
log.Fatalf("http.ListenAndServe: %v", err)
}
// IMPLEMENTATION:
// Cacher returns a public Cache-Control header for all requests.
func Cacher(duration time.Duration, h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
header := w.Header()
header.Set("Cache-Control", fmt.Sprintf("public, max-age=%d", int(duration.Seconds())))
header.Set("Vary", "Accept-Encoding")
h.ServeHTTP(w, r)
})
}
func FileWithCache(path string, duration time.Duration) http.Handler {
return Cacher(duration, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, path)
}))
}
// Logger logs incoming requests, including response status.
func Logger(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
info := fmt.Sprintf("%s %s %s", r.Method, r.URL, r.Proto)
o := &responseObserver{ResponseWriter: w}
h.ServeHTTP(o, r)
log.Printf("%s %q %d %d %q %q",
r.RemoteAddr,
info,
o.status,
o.written,
r.Referer(),
r.UserAgent())
})
}
// Spies on http.ResponseWriter (used by Logger).
type responseObserver struct {
http.ResponseWriter
status int
written int64
wroteHeader bool
}
func (o *responseObserver) Write(p []byte) (n int, err error) {
if !o.wroteHeader {
o.WriteHeader(http.StatusOK)
}
n, err = o.ResponseWriter.Write(p)
o.written += int64(n)
return
}
func (o *responseObserver) WriteHeader(code int) {
o.ResponseWriter.WriteHeader(code)
if o.wroteHeader {
return
}
o.wroteHeader = true
o.status = code
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment