Created
May 5, 2017 16:36
-
-
Save blixt/f54f31f0b4437dca1f22a52b1996a931 to your computer and use it in GitHub Desktop.
A couple of middleware http.Handler functions for Go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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