caddy-webp/caddywebp.go

108 lines
2.4 KiB
Go
Raw Normal View History

2020-03-23 03:18:20 +00:00
package github
import (
"bytes"
2020-03-25 00:55:57 +00:00
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
2020-03-23 03:18:20 +00:00
"github.com/chai2010/webp"
"golang.org/x/image/bmp"
"image"
"image/jpeg"
"image/png"
"io"
2020-03-25 00:55:57 +00:00
"log"
2020-03-23 03:18:20 +00:00
"net/http"
"strings"
)
const Quality = 80
func init() {
2020-03-25 00:55:57 +00:00
log.Println("webp plugin")
err := caddy.RegisterModule(Webp{})
if err != nil {
log.Fatal(err)
}
httpcaddyfile.RegisterHandlerDirective("webp", parseCaddyfile)
2020-03-23 03:18:20 +00:00
}
2020-03-25 00:55:57 +00:00
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
return Webp{}, nil
2020-03-23 03:18:20 +00:00
}
2020-03-25 00:55:57 +00:00
type Webp struct {
2020-03-23 03:18:20 +00:00
}
2020-03-25 00:55:57 +00:00
func (Webp) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
Name: "http.handlers.webp",
New: func() caddy.Module { return new(Webp) },
}
}
func (s Webp) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
2020-03-23 03:18:20 +00:00
ua := r.Header.Get("User-Agent")
if strings.Contains(ua, "Safari") && !strings.Contains(ua, "Chrome") && !strings.Contains(ua, "Firefox") {
2020-03-25 00:55:57 +00:00
return next.ServeHTTP(w, r) // 对Safari禁用webp
2020-03-23 03:18:20 +00:00
}
resp := &response{}
2020-03-25 00:55:57 +00:00
err := next.ServeHTTP(resp, r)
2020-03-23 03:18:20 +00:00
if err != nil {
2020-03-25 00:55:57 +00:00
return err
2020-03-23 03:18:20 +00:00
}
ct := http.DetectContentType(resp.Body.Bytes())
//fmt.Println("file len", resp.Body.Len(), "file type", ct)
var decoder func(io.Reader) (image.Image, error)
if strings.Contains(ct, "jpeg") {
decoder = jpeg.Decode
2020-03-25 00:55:57 +00:00
} else if strings.Contains(ct, "png") {
2020-03-23 03:18:20 +00:00
decoder = png.Decode
2020-03-25 00:55:57 +00:00
} else if strings.Contains(ct, "bmp") {
2020-03-23 03:18:20 +00:00
decoder = bmp.Decode
// } else if strings.HasSuffix(r.URL.String(), ".gif") { TODO need to support animated webp
// decoder = gif.Decode
} else {
2020-03-25 00:55:57 +00:00
return next.ServeHTTP(w, r)
2020-03-23 03:18:20 +00:00
}
img, err := decoder(bytes.NewReader(resp.Body.Bytes()))
if err != nil || img == nil {
2020-03-25 00:55:57 +00:00
log.Println(err)
return next.ServeHTTP(w, r)
2020-03-23 03:18:20 +00:00
}
var buf bytes.Buffer
err = webp.Encode(&buf, img, &webp.Options{Lossless: false, Quality: Quality})
if err != nil {
2020-03-25 00:55:57 +00:00
log.Println(err)
return next.ServeHTTP(w, r)
2020-03-23 03:18:20 +00:00
}
w.Header().Set("Content-Type", "image/webp")
w.WriteHeader(http.StatusOK)
_, err = w.Write(buf.Bytes())
if err != nil {
2020-03-25 00:55:57 +00:00
log.Println(err)
return err
2020-03-23 03:18:20 +00:00
}
2020-03-25 00:55:57 +00:00
return nil
2020-03-23 03:18:20 +00:00
}
type response struct {
header http.Header
Body bytes.Buffer
}
func (s *response) Header() http.Header {
return http.Header{}
}
func (s *response) Write(data []byte) (int, error) {
s.Body.Write(data)
return len(data), nil
}
func (s *response) WriteHeader(i int) {
return
}