transfer.sh/vendor/github.com/PuerkitoBio/ghost/handlers/favicon.go
Remco cb6e5cb0c7 Major rewrite
* use dep for vendoring
* lets encrypt
* moved web to transfer.sh-web repo
* single command install
* added first tests
2017-03-22 18:09:21 +01:00

71 lines
2 KiB
Go

package handlers
import (
"crypto/md5"
"io/ioutil"
"net/http"
"strconv"
"time"
"github.com/PuerkitoBio/ghost"
)
// FaviconHandlerFunc is the same as FaviconHandler, it is just a convenience
// signature that accepts a func(http.ResponseWriter, *http.Request) instead of
// a http.Handler interface. It saves the boilerplate http.HandlerFunc() cast.
func FaviconHandlerFunc(h http.HandlerFunc, path string, maxAge time.Duration) http.HandlerFunc {
return FaviconHandler(h, path, maxAge)
}
// Efficient favicon handler, mostly a port of node's Connect library implementation
// of the favicon middleware.
// https://github.com/senchalabs/connect
func FaviconHandler(h http.Handler, path string, maxAge time.Duration) http.HandlerFunc {
var buf []byte
var hash string
return func(w http.ResponseWriter, r *http.Request) {
var err error
if r.URL.Path == "/favicon.ico" {
if buf == nil {
// Read from file and cache
ghost.LogFn("ghost.favicon : serving from %s", path)
buf, err = ioutil.ReadFile(path)
if err != nil {
ghost.LogFn("ghost.favicon : error reading file : %s", err)
http.NotFound(w, r)
return
}
hash = hashContent(buf)
}
writeHeaders(w.Header(), buf, maxAge, hash)
writeBody(w, r, buf)
} else {
h.ServeHTTP(w, r)
}
}
}
// Write the content of the favicon, or respond with a 404 not found
// in case of error (hardly a critical error).
func writeBody(w http.ResponseWriter, r *http.Request, buf []byte) {
_, err := w.Write(buf)
if err != nil {
ghost.LogFn("ghost.favicon : error writing response : %s", err)
http.NotFound(w, r)
}
}
// Correctly set the http headers.
func writeHeaders(hdr http.Header, buf []byte, maxAge time.Duration, hash string) {
hdr.Set("Content-Type", "image/x-icon")
hdr.Set("Content-Length", strconv.Itoa(len(buf)))
hdr.Set("Etag", hash)
hdr.Set("Cache-Control", "public, max-age="+strconv.Itoa(int(maxAge.Seconds())))
}
// Get the MD5 hash of the content.
func hashContent(buf []byte) string {
h := md5.New()
return string(h.Sum(buf))
}