webp_server_go/router.go
Benny 428192275b
choose webp or png feature (#70)
* support webp_bigger header, add test cases

* fix test case
2021-02-12 16:13:13 +08:00

162 lines
4.5 KiB
Go

package main
import (
"errors"
"fmt"
"github.com/gofiber/fiber/v2"
log "github.com/sirupsen/logrus"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"strconv"
"strings"
)
func convert(c *fiber.Ctx) error {
//basic vars
var reqURI, _ = url.QueryUnescape(c.Path()) // /mypic/123.jpg
var rawImageAbs string
if proxyMode {
rawImageAbs = config.ImgPath + reqURI
} else {
rawImageAbs = path.Join(config.ImgPath, reqURI) // /home/xxx/mypic/123.jpg
}
var imgFilename = path.Base(reqURI) // pure filename, 123.jpg
var finalFile string // We'll only need one c.sendFile()
var ua = c.Get("User-Agent")
var accept = c.Get("accept")
log.Debugf("Incoming connection from %s@%s with %s", ua, c.IP(), imgFilename)
needOrigin := goOrigin(accept, ua)
if needOrigin {
log.Debugf("A Safari/IE/whatever user has arrived...%s", ua)
c.Set("ETag", genEtag(rawImageAbs))
if proxyMode {
localRemoteTmpPath := remoteRaw + reqURI
_ = fetchRemoteImage(localRemoteTmpPath, rawImageAbs)
return c.SendFile(localRemoteTmpPath)
} else {
return c.SendFile(rawImageAbs)
}
}
// check ext
var allowed = false
for _, ext := range config.AllowedTypes {
haystack := strings.ToLower(imgFilename)
needle := strings.ToLower("." + ext)
if strings.HasSuffix(haystack, needle) {
allowed = true
break
} else {
allowed = false
}
}
if !allowed {
msg := "File extension not allowed! " + imgFilename
log.Warn(msg)
if imageExists(rawImageAbs) {
c.Set("ETag", genEtag(rawImageAbs))
return c.SendFile(rawImageAbs)
} else {
c.Status(http.StatusBadRequest)
_ = c.Send([]byte(msg))
return nil
}
}
if proxyMode {
return proxyHandler(c, reqURI)
}
// Check the original image for existence,
if !imageExists(rawImageAbs) {
msg := "image not found"
_ = c.Send([]byte(msg))
log.Warn(msg)
_ = c.SendStatus(404)
return errors.New(msg)
}
_, webpAbsPath := genWebpAbs(rawImageAbs, config.ExhaustPath, imgFilename, reqURI)
if imageExists(webpAbsPath) {
finalFile = webpAbsPath
} else {
// we don't have abc.jpg.png1582558990.webp
// delete the old pic and convert a new one.
// /home/webp_server/exhaust/path/to/tsuki.jpg.1582558990.webp
destHalfFile := path.Clean(path.Join(webpAbsPath, path.Dir(reqURI), imgFilename))
matches, err := filepath.Glob(destHalfFile + "*")
if err != nil {
log.Error(err.Error())
} else {
// /home/webp_server/exhaust/path/to/tsuki.jpg.1582558100.webp <- older ones will be removed
// /home/webp_server/exhaust/path/to/tsuki.jpg.1582558990.webp <- keep the latest one
for _, p := range matches {
if strings.Compare(destHalfFile, p) != 0 {
_ = os.Remove(p)
}
}
}
//for webp, we need to create dir first
err = os.MkdirAll(path.Dir(webpAbsPath), 0755)
q, _ := strconv.ParseFloat(config.Quality, 32)
err = webpEncoder(rawImageAbs, webpAbsPath, float32(q), true, nil)
if err != nil {
log.Error(err)
_ = c.SendStatus(400)
_ = c.Send([]byte("Bad file. " + err.Error()))
return err
}
finalFile = webpAbsPath
}
etag := genEtag(finalFile)
c.Set("ETag", etag)
c.Set("X-Compression-Rate", getCompressionRate(rawImageAbs, webpAbsPath))
finalFile = chooseLocalSmallerFile(rawImageAbs, webpAbsPath)
return c.SendFile(finalFile)
}
func proxyHandler(c *fiber.Ctx, reqURI string) error {
// https://test.webp.sh/node.png
realRemoteAddr := config.ImgPath + reqURI
// Ping Remote for status code and etag info
log.Infof("Remote Addr is %s fetching", realRemoteAddr)
statusCode, etagValue, remoteLength := getRemoteImageInfo(realRemoteAddr)
if statusCode == 200 {
// Check local path: /node.png-etag-<etagValue>
localEtagWebPPath := config.ExhaustPath + reqURI + "-etag-" + etagValue
if imageExists(localEtagWebPPath) {
chooseProxy(remoteLength, localEtagWebPPath)
return c.SendFile(localEtagWebPPath)
} else {
// Temporary store of remote file.
cleanProxyCache(config.ExhaustPath + reqURI + "*")
localRawImagePath := remoteRaw + reqURI
_ = fetchRemoteImage(localRawImagePath, realRemoteAddr)
q, _ := strconv.ParseFloat(config.Quality, 32)
_ = os.MkdirAll(path.Dir(localEtagWebPPath), 0755)
err := webpEncoder(localRawImagePath, localEtagWebPPath, float32(q), true, nil)
if err != nil {
log.Warning(err)
}
chooseProxy(remoteLength, localEtagWebPPath)
return c.SendFile(localEtagWebPPath)
}
} else {
msg := fmt.Sprintf("Remote returned %d status code!", statusCode)
_ = c.Send([]byte(msg))
log.Warn(msg)
_ = c.SendStatus(statusCode)
cleanProxyCache(config.ExhaustPath + reqURI + "*")
return errors.New(msg)
}
}