diff --git a/.gitignore b/.gitignore index 1c592c6..c1af1fc 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ exhaust/ /.idea/modules.xml /.idea/vcs.xml /.idea/webp_server_go.iml +remote-raw/ +coverage.txt \ No newline at end of file diff --git a/config.go b/config.go new file mode 100644 index 0000000..2e7dc55 --- /dev/null +++ b/config.go @@ -0,0 +1,59 @@ +// webp_server_go - config +// 2020-11-27 13:05 +// Benny + +package main + +type Config struct { + Host string `json:"HOST"` + Port string `json:"PORT"` + ImgPath string `json:"IMG_PATH"` + Quality string `json:"QUALITY"` + AllowedTypes []string `json:"ALLOWED_TYPES"` + ExhaustPath string `json:"EXHAUST_PATH"` +} + +var ( + configPath string + jobs int + dumpConfig, dumpSystemd bool + verboseMode, showVersion bool + prefetch, proxyMode bool + + config Config + version = "0.2.2" +) + +const ( + NotCompressed = "not_compressed" + WebpBigger = "webp_bigger" +) + +const ( + sampleConfig = ` +{ + "HOST": "127.0.0.1", + "PORT": "3333", + "QUALITY": "80", + "IMG_PATH": "./pics", + "EXHAUST_PATH": "./exhaust", + "ALLOWED_TYPES": ["jpg","png","jpeg","bmp"] +}` + + sampleSystemd = ` +[Unit] +Description=WebP Server Go +Documentation=https://github.com/webp-sh/webp_server_go +After=nginx.target + +[Service] +Type=simple +StandardError=journal +WorkingDirectory=/opt/webps +ExecStart=/opt/webps/webp-server --config /opt/webps/config.json +Restart=always +RestartSec=3s + +[Install] +WantedBy=multi-user.target` +) diff --git a/helper.go b/helper.go index ef65d90..001f40f 100644 --- a/helper.go +++ b/helper.go @@ -91,7 +91,7 @@ func cleanProxyCache(cacheImagePath string) { // Delete /node.png* files, err := filepath.Glob(cacheImagePath + "*") if err != nil { - fmt.Println(err) + log.Infoln(err) } for _, f := range files { if err := os.Remove(f); err != nil { @@ -108,7 +108,7 @@ func genWebpAbs(RawImagePath string, ExhaustPath string, ImgFilename string, req return "", "" } ModifiedTime := STAT.ModTime().Unix() - // webpFilename: abc.jpg.png -> abc.jpg.png1582558990.webp + // webpFilename: abc.jpg.png -> abc.jpg.png.1582558990.webp WebpFilename := fmt.Sprintf("%s.%d.webp", ImgFilename, ModifiedTime) cwd, _ := os.Getwd() @@ -127,6 +127,22 @@ func genEtag(ImgAbsPath string) string { return fmt.Sprintf(`W/"%d-%08X"`, len(data), crc) } +func getCompressionRate(RawImagePath string, webpAbsPath string) string { + originFileInfo, err := os.Stat(RawImagePath) + if err != nil { + log.Warnf("fail to get raw image %v", err) + return "" + } + webpFileInfo, err := os.Stat(webpAbsPath) + if err != nil { + log.Warnf("fail to get webp image %v", err) + return "" + } + compressionRate := float64(webpFileInfo.Size()) / float64(originFileInfo.Size()) + log.Debugf("The compress rate is %d/%d=%.2f", originFileInfo.Size(), webpFileInfo.Size(), compressionRate) + return fmt.Sprintf(`%.2f`, compressionRate) +} + func goOrigin(UA string) bool { // for more information, please check test case if strings.Contains(UA, "Firefox") || strings.Contains(UA, "Chrome") { diff --git a/helper_test.go b/helper_test.go index db67f58..ff05846 100644 --- a/helper_test.go +++ b/helper_test.go @@ -157,3 +157,18 @@ func TestCleanProxyCache(t *testing.T) { // test bad dir cleanProxyCache("/aasdyg/dhj2/dagh") } + +func TestGetCompressionRate(t *testing.T) { + pic1 := "pics/webp_server.bmp" + pic2 := "pics/webp_server.jpg" + var ratio string + + ratio = getCompressionRate(pic1, pic2) + assert.Equal(t, "0.16", ratio) + + ratio = getCompressionRate(pic1, "pic2") + assert.Equal(t, "", ratio) + + ratio = getCompressionRate("pic1", pic2) + assert.Equal(t, "", ratio) +} diff --git a/router.go b/router.go index 3ad2055..49d0123 100644 --- a/router.go +++ b/router.go @@ -20,16 +20,17 @@ func convert(c *fiber.Ctx) error { 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") - done := goOrigin(UA) - if done { + log.Debugf("Incoming connection from %s@%s with %s", UA, c.IP(), imgFilename) + + needOrigin := goOrigin(UA) + if needOrigin { log.Infof("A Safari/IE/whatever user has arrived...%s", UA) // Check for Safari users. If they're Safari, just simply ignore everything. - etag := genEtag(rawImageAbs) c.Set("ETag", etag) + c.Set("X-Compression-Rate", NotCompressed) return c.SendFile(rawImageAbs) } - log.Debugf("Incoming connection from %s@%s with %s", UA, c.IP(), imgFilename) // check ext var allowed = false @@ -43,6 +44,7 @@ func convert(c *fiber.Ctx) error { allowed = false } } + if !allowed { msg := "File extension not allowed! " + imgFilename log.Warn(msg) @@ -60,7 +62,7 @@ func convert(c *fiber.Ctx) error { // https://test.webp.sh/node.png realRemoteAddr := config.ImgPath + reqURI // Ping Remote for status code and etag info - fmt.Println("Remote Addr is " + realRemoteAddr + ", fetching..") + log.Infof("Remote Addr is %s fetching", realRemoteAddr) statusCode, etagValue := getRemoteImageInfo(realRemoteAddr) if statusCode == 200 { // Check local path: /node.png-etag- @@ -77,7 +79,7 @@ func convert(c *fiber.Ctx) error { _ = os.MkdirAll(path.Dir(localEtagImagePath), 0755) err := webpEncoder(localRemoteTmpPath, localEtagImagePath, float32(q), true, nil) if err != nil { - fmt.Println(err) + log.Warning(err) } return c.SendFile(localEtagImagePath) } @@ -130,13 +132,14 @@ func convert(c *fiber.Ctx) error { if err != nil { log.Error(err) _ = c.SendStatus(400) - _ = c.Send([]byte("Bad file!")) + _ = 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)) return c.SendFile(finalFile) } } diff --git a/router_test.go b/router_test.go index 5cb1923..31fa4ea 100644 --- a/router_test.go +++ b/router_test.go @@ -18,6 +18,44 @@ var ( SafariUA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15" ) +func setupParam() { + // setup parameters here... + config.ImgPath = "./pics" + config.ExhaustPath = "./exhaust" + config.AllowedTypes = []string{"jpg", "png", "jpeg", "bmp"} +} + +func requestToServer(url string, app *fiber.App, ua string) (*http.Response, []byte) { + req := httptest.NewRequest("GET", url, nil) + req.Header.Set("User-Agent", ua) + resp, _ := app.Test(req, 60000) + data, _ := ioutil.ReadAll(resp.Body) + return resp, data +} + +func TestServerHeaders(t *testing.T) { + setupParam() + var app = fiber.New() + app.Get("/*", convert) + url := "http://127.0.0.1:3333/webp_server.bmp" + + // test for chrome + response, _ := requestToServer(url, app, chromeUA) + ratio := response.Header.Get("X-Compression-Rate") + etag := response.Header.Get("Etag") + + assert.NotEqual(t, "", ratio) + assert.NotEqual(t, "", etag) + + // test for safari + response, _ = requestToServer(url, app, SafariUA) + ratio = response.Header.Get("X-Compression-Rate") + etag = response.Header.Get("Etag") + + assert.Equal(t, NotCompressed, ratio) + assert.NotEqual(t, "", etag) +} + func TestConvert(t *testing.T) { setupParam() var testChromeLink = map[string]string{ @@ -108,20 +146,4 @@ func TestConvertProxyModeWork(t *testing.T) { resp, data := requestToServer(url, app, chromeUA) assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, "image/webp", getFileContentType(data)) - -} - -func setupParam() { - // setup parameters here... - config.ImgPath = "./pics" - config.ExhaustPath = "./exhaust" - config.AllowedTypes = []string{"jpg", "png", "jpeg", "bmp"} -} - -func requestToServer(url string, app *fiber.App, ua string) (*http.Response, []byte) { - req := httptest.NewRequest("GET", url, nil) - req.Header.Set("User-Agent", ua) - resp, _ := app.Test(req, 60000) - data, _ := ioutil.ReadAll(resp.Body) - return resp, data } diff --git a/webp-server.go b/webp-server.go index 161115c..2e895d4 100644 --- a/webp-server.go +++ b/webp-server.go @@ -12,54 +12,6 @@ import ( log "github.com/sirupsen/logrus" ) -type Config struct { - Host string `json:"HOST"` - Port string `json:"PORT"` - ImgPath string `json:"IMG_PATH"` - Quality string `json:"QUALITY"` - AllowedTypes []string `json:"ALLOWED_TYPES"` - ExhaustPath string `json:"EXHAUST_PATH"` -} - -var ( - configPath string - jobs int - dumpConfig, dumpSystemd, verboseMode, prefetch, showVersion bool - - proxyMode bool - config Config - version = "0.2.2" -) - -const ( - sampleConfig = ` -{ - "HOST": "127.0.0.1", - "PORT": "3333", - "QUALITY": "80", - "IMG_PATH": "./pics", - "EXHAUST_PATH": "./exhaust", - "ALLOWED_TYPES": ["jpg","png","jpeg","bmp"] -}` - - sampleSystemd = ` -[Unit] -Description=WebP Server Go -Documentation=https://github.com/webp-sh/webp_server_go -After=nginx.target - -[Service] -Type=simple -StandardError=journal -WorkingDirectory=/opt/webps -ExecStart=/opt/webps/webp-server --config /opt/webps/config.json -Restart=always -RestartSec=3s - -[Install] -WantedBy=multi-user.target` -) - func loadConfig(path string) Config { jsonObject, err := os.Open(path) if err != nil {