|
|
package static
import ( "bytes" "compress/gzip" "crypto/md5" "fmt" "mime" "path" "net/http" "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]) } }
|