choose webp or png feature (#70)

* support webp_bigger header, add test cases

* fix test case
This commit is contained in:
Benny 2021-02-12 16:13:13 +08:00 committed by GitHub
parent 878a2ddd0c
commit 428192275b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 171 additions and 108 deletions

View File

@ -22,11 +22,7 @@ var (
remoteRaw = "remote-raw" remoteRaw = "remote-raw"
config Config config Config
version = "0.3.2" version = "0.3.2"
) releaseUrl = "https://github.com/webp-sh/webp_server_go/releases/latest/download/"
const (
NotCompressed = "not_compressed"
WebpBigger = "webp_bigger"
) )
const ( const (

View File

@ -8,7 +8,17 @@ import (
"testing" "testing"
) )
//go test -v -cover . func walker() []string {
var list []string
_ = filepath.Walk("./pics", func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
list = append(list, path)
}
return nil
})
return list
}
func TestWebpEncoder(t *testing.T) { func TestWebpEncoder(t *testing.T) {
var webp = "/tmp/test-result.webp" var webp = "/tmp/test-result.webp"
var target = walker() var target = walker()
@ -25,24 +35,18 @@ func TestWebpEncoder(t *testing.T) {
_ = os.Remove(webp) _ = os.Remove(webp)
} }
func TestNonImage(t *testing.T) { func TestNonExistImage(t *testing.T) {
var webp = "/tmp/test-result.webp" var webp = "/tmp/test-result.webp"
// test error // test error
var err = webpEncoder("./pics/empty.jpg", webp, 80, true, nil) var err = webpEncoder("./pics/empty.jpg", webp, 80, true, nil)
assert.NotNil(t, err) assert.NotNil(t, err)
_ = os.Remove(webp) _ = os.Remove(webp)
} }
func walker() []string { func TestConvertFail(t *testing.T) {
var list []string var webp = "/tmp/test-result.webp"
_ = filepath.Walk("./pics", func(path string, info os.FileInfo, err error) error { var err = webpEncoder("./pics/webp_server.jpg", webp, -1, true, nil)
if !info.IsDir() { assert.NotNil(t, t, err)
list = append(list, path)
}
return nil
})
return list
} }
func runEncoder(t *testing.T, file string, webp string) { func runEncoder(t *testing.T, file string, webp string) {

View File

@ -9,6 +9,7 @@ import (
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
@ -32,6 +33,9 @@ func fileCount(dir string) int {
count := 0 count := 0
_ = filepath.Walk(dir, _ = filepath.Walk(dir,
func(path string, info os.FileInfo, err error) error { func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() { if !info.IsDir() {
count += 1 count += 1
} }
@ -50,22 +54,24 @@ func imageExists(filename string) bool {
} }
// Check for remote filepath, e.g: https://test.webp.sh/node.png // Check for remote filepath, e.g: https://test.webp.sh/node.png
// return StatusCode, etagValue // return StatusCode, etagValue and length
func getRemoteImageInfo(fileUrl string) (int, string) { func getRemoteImageInfo(fileUrl string) (int, string, string) {
res, err := http.Head(fileUrl) res, err := http.Head(fileUrl)
if err != nil { if err != nil {
log.Errorln("Connection to remote error!") log.Errorln("Connection to remote error!")
return http.StatusInternalServerError, "" return http.StatusInternalServerError, "", ""
} }
if res.StatusCode != 404 { if res.StatusCode != 404 {
etagValue := res.Header.Get("etag") etagValue := res.Header.Get("etag")
if etagValue == "" { if etagValue == "" {
log.Info("Remote didn't return etag in header, please check.") log.Info("Remote didn't return etag in header, please check.")
} else { } else {
return 200, etagValue return 200, etagValue, res.Header.Get("content-length")
} }
} }
return res.StatusCode, ""
return res.StatusCode, "", res.Header.Get("content-length")
} }
func fetchRemoteImage(filepath string, url string) error { func fetchRemoteImage(filepath string, url string) error {
@ -184,3 +190,23 @@ func headerOrigin(header string) bool {
return true return true
} }
} }
func chooseProxy(proxyRawSize string, webpAbsPath string) bool {
var proxyRaw, _ = strconv.Atoi(proxyRawSize)
webp, _ := ioutil.ReadFile(webpAbsPath)
if len(webp) > proxyRaw {
return true
} else {
return false
}
}
func chooseLocalSmallerFile(rawImageAbs, webpAbsPath string) string {
raw, _ := ioutil.ReadFile(rawImageAbs)
webp, _ := ioutil.ReadFile(webpAbsPath)
if len(webp) > len(raw) {
return rawImageAbs
} else {
return webpAbsPath
}
}

View File

@ -177,14 +177,16 @@ func TestChanErr(t *testing.T) {
func TestGetRemoteImageInfo(t *testing.T) { func TestGetRemoteImageInfo(t *testing.T) {
url := "https://github.com/favicon.ico" url := "https://github.com/favicon.ico"
statusCode, etag := getRemoteImageInfo(url) statusCode, etag, length := getRemoteImageInfo(url)
assert.NotEqual(t, "", etag) assert.NotEqual(t, "", etag)
assert.NotEqual(t, "0", length)
assert.Equal(t, statusCode, http.StatusOK) assert.Equal(t, statusCode, http.StatusOK)
// test non-exist url // test non-exist url
url = "http://sdahjajda.com" url = "http://sdahjajda.com"
statusCode, etag = getRemoteImageInfo(url) statusCode, etag, length = getRemoteImageInfo(url)
assert.Equal(t, "", etag) assert.Equal(t, "", etag)
assert.Equal(t, "", length)
assert.Equal(t, statusCode, http.StatusInternalServerError) assert.Equal(t, statusCode, http.StatusInternalServerError)
} }

BIN
pics/big.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View File

@ -16,7 +16,7 @@ func TestPrefetchImages(t *testing.T) {
_ = os.Mkdir(fp, 0755) _ = os.Mkdir(fp, 0755)
prefetchImages("./pics", "./prefetch", "80") prefetchImages("./pics", "./prefetch", "80")
count := fileCount("./prefetch") count := fileCount("./prefetch")
assert.Equal(t, 7, count) assert.Equal(t, 8, count)
_ = os.RemoveAll(fp) _ = os.RemoveAll(fp)
// concurrency // concurrency
@ -24,6 +24,11 @@ func TestPrefetchImages(t *testing.T) {
_ = os.Mkdir(fp, 0755) _ = os.Mkdir(fp, 0755)
prefetchImages("./pics", "./prefetch", "80") prefetchImages("./pics", "./prefetch", "80")
count = fileCount("./prefetch") count = fileCount("./prefetch")
assert.Equal(t, 5, count) assert.Equal(t, 6, count)
_ = os.RemoveAll(fp) _ = os.RemoveAll(fp)
} }
func TestBadPrefetch(t *testing.T) {
jobs = 1
prefetchImages("./pics2", "./prefetch", "80")
}

View File

@ -33,7 +33,6 @@ func convert(c *fiber.Ctx) error {
if needOrigin { if needOrigin {
log.Debugf("A Safari/IE/whatever user has arrived...%s", ua) log.Debugf("A Safari/IE/whatever user has arrived...%s", ua)
c.Set("ETag", genEtag(rawImageAbs)) c.Set("ETag", genEtag(rawImageAbs))
c.Set("X-Compression-Rate", NotCompressed)
if proxyMode { if proxyMode {
localRemoteTmpPath := remoteRaw + reqURI localRemoteTmpPath := remoteRaw + reqURI
_ = fetchRemoteImage(localRemoteTmpPath, rawImageAbs) _ = fetchRemoteImage(localRemoteTmpPath, rawImageAbs)
@ -69,41 +68,10 @@ func convert(c *fiber.Ctx) error {
} }
} }
// Start Proxy Mode
if proxyMode { if proxyMode {
// https://test.webp.sh/node.png return proxyHandler(c, reqURI)
realRemoteAddr := config.ImgPath + reqURI
// Ping Remote for status code and etag info
log.Infof("Remote Addr is %s fetching", realRemoteAddr)
statusCode, etagValue := getRemoteImageInfo(realRemoteAddr)
if statusCode == 200 {
// Check local path: /node.png-etag-<etagValue>
localEtagImagePath := config.ExhaustPath + reqURI + "-etag-" + etagValue
if imageExists(localEtagImagePath) {
return c.SendFile(localEtagImagePath)
} else {
// Temporary store of remote file.
cleanProxyCache(config.ExhaustPath + reqURI + "*")
localRemoteTmpPath := remoteRaw + reqURI
_ = fetchRemoteImage(localRemoteTmpPath, realRemoteAddr)
q, _ := strconv.ParseFloat(config.Quality, 32)
_ = os.MkdirAll(path.Dir(localEtagImagePath), 0755)
err := webpEncoder(localRemoteTmpPath, localEtagImagePath, float32(q), true, nil)
if err != nil {
log.Warning(err)
} }
return c.SendFile(localEtagImagePath)
}
} 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)
}
// End Proxy Mode
} else {
// Check the original image for existence, // Check the original image for existence,
if !imageExists(rawImageAbs) { if !imageExists(rawImageAbs) {
msg := "image not found" msg := "image not found"
@ -151,6 +119,43 @@ func convert(c *fiber.Ctx) error {
etag := genEtag(finalFile) etag := genEtag(finalFile)
c.Set("ETag", etag) c.Set("ETag", etag)
c.Set("X-Compression-Rate", getCompressionRate(rawImageAbs, webpAbsPath)) c.Set("X-Compression-Rate", getCompressionRate(rawImageAbs, webpAbsPath))
finalFile = chooseLocalSmallerFile(rawImageAbs, webpAbsPath)
return c.SendFile(finalFile) 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)
} }
} }

View File

@ -10,6 +10,7 @@ import (
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"os"
"testing" "testing"
) )
@ -21,7 +22,7 @@ var (
func setupParam() { func setupParam() {
// setup parameters here... // setup parameters here...
config.ImgPath = "./pics" config.ImgPath = "./pics"
config.ExhaustPath = "./exhaust" config.ExhaustPath = "./exhaust_test"
config.AllowedTypes = []string{"jpg", "png", "jpeg", "bmp"} config.AllowedTypes = []string{"jpg", "png", "jpeg", "bmp"}
proxyMode = false proxyMode = false
@ -55,7 +56,6 @@ func TestServerHeaders(t *testing.T) {
ratio = response.Header.Get("X-Compression-Rate") ratio = response.Header.Get("X-Compression-Rate")
etag = response.Header.Get("Etag") etag = response.Header.Get("Etag")
assert.Equal(t, NotCompressed, ratio)
assert.NotEqual(t, "", etag) assert.NotEqual(t, "", etag)
} }
@ -156,3 +156,20 @@ func TestConvertProxyModeWork(t *testing.T) {
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
assert.Equal(t, "image/jpeg", getFileContentType(data)) assert.Equal(t, "image/jpeg", getFileContentType(data))
} }
func TestConvertBigger(t *testing.T) {
setupParam()
config.Quality = "100"
jpg, _ := ioutil.ReadFile("pics/big.jpg")
var app = fiber.New()
app.Get("/*", convert)
url := "http://127.0.0.1:3333/big.jpg"
response, data := requestToServer(url, app, chromeUA)
assert.Equal(t, "image/jpeg", response.Header.Get("content-type"))
assert.True(t, len(data) == len(jpg))
_ = os.RemoveAll(config.ExhaustPath)
}

View File

@ -41,9 +41,8 @@ func autoUpdate() {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
filename += ".exe" filename += ".exe"
} }
var releaseUrl = "https://github.com/webp-sh/webp_server_go/releases/latest/download/" + filename
log.Info("Downloading binary to update...") log.Info("Downloading binary to update...")
resp, _ := http.Get(releaseUrl) resp, _ := http.Get(releaseUrl + filename)
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
log.Debugf("%s-%s not found on release.", runtime.GOOS, runtime.GOARCH) log.Debugf("%s-%s not found on release.", runtime.GOOS, runtime.GOARCH)
return return

View File

@ -18,6 +18,15 @@ func TestNormalAutoUpdate(t *testing.T) {
_ = os.RemoveAll(dir) _ = os.RemoveAll(dir)
} }
func Test404AutoUpdate(t *testing.T) {
version = "0.0.1"
dir := "./update"
releaseUrl = releaseUrl + "a"
autoUpdate()
assert.Equal(t, 0, fileCount(dir))
_ = os.RemoveAll(dir)
}
func TestNoNeedAutoUpdate(t *testing.T) { func TestNoNeedAutoUpdate(t *testing.T) {
version = "99.99" version = "99.99"
dir := "./update" dir := "./update"