qurl/static/static.go
2018-11-17 16:47:39 +00:00

105 lines
2.5 KiB
Go

package static
import (
"bytes"
"compress/gzip"
"crypto/md5"
"fmt"
"mime"
"net/http"
"path"
"strings"
)
type StaticContent struct {
ContentType string
Content string
ETag string
GZIPContent []byte
GZIPETag string
DisableGZIP bool
}
func (ctx *StaticContent) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// By default, don't use gzip
useGZIP := false
// If gzip isn't explicitly disabled, test for it
if !ctx.DisableGZIP {
useGZIP = strings.Contains(r.Header.Get("Accept-Encoding"), "gzip")
}
// If gzip is enabled, and there's no gzip etag,
// generate the gzip'd content plus the etag
if useGZIP && len(ctx.GZIPETag) == 0 {
var buf bytes.Buffer
gz, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression)
defer gz.Close()
if _, err := gz.Write(Assets[ctx.Content]); err != nil {
http.Error(w, fmt.Sprintf("GZIP write error: %s", err.Error()),
http.StatusInternalServerError)
return
}
if err := gz.Flush(); err != nil {
http.Error(w, fmt.Sprintf("GZIP flush error: %s", err.Error()),
http.StatusInternalServerError)
return
}
// Check if GZIP actually resulted in a smaller file
if buf.Len() < len(Assets[ctx.Content]) {
ctx.GZIPContent = buf.Bytes()
ctx.GZIPETag = fmt.Sprintf("%x", md5.Sum(Assets[ctx.Content]))
} else {
// If gzip turns out to be ineffective, disable it
ctx.DisableGZIP = true
useGZIP = false
}
}
var localETag string
if useGZIP {
localETag = ctx.GZIPETag
} else {
// Generate an ETag for content if necessary
if ctx.ETag == "" {
ctx.ETag = fmt.Sprintf("%x", md5.Sum(Assets[ctx.Content]))
}
localETag = ctx.ETag
}
// Check the etag, maybe we don't need to send content
remoteETag := r.Header.Get("If-None-Match")
if localETag == remoteETag {
w.WriteHeader(http.StatusNotModified)
return
}
w.Header().Set("ETag", localETag)
// Check the content type, if we don't already
// have one, make one
if ctx.ContentType == "" {
ext := path.Ext(ctx.Content)
ctx.ContentType = mime.TypeByExtension(ext)
// Fallback to default mime type
if ctx.ContentType == "" {
ctx.ContentType = "application/octet-stream"
}
}
w.Header().Set("Content-Type", ctx.ContentType)
// Finally, write our content
if useGZIP {
w.Header().Set("Content-Encoding", "gzip")
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(ctx.GZIPContent)))
w.Write(ctx.GZIPContent)
} else {
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(Assets[ctx.Content])))
w.Write(Assets[ctx.Content])
}
}