diff --git a/README.md b/README.md index 4a631a8..200bc75 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ * 使用流式JSON编码器 * 内存使用监控 6. 根目录设置打招呼 +7. 移除`IMG_PATH`的配置方式, 只保留`IMG_MAP`. +8. 当前缀与`IMG_MAP`不匹配时, 直接返回错误
diff --git a/config/config.go b/config/config.go
index d0c8975..114fb03 100644
--- a/config/config.go
+++ b/config/config.go
@@ -137,7 +137,7 @@ func LoadConfig() {
decoder := json.NewDecoder(jsonObject)
_ = decoder.Decode(&Config)
_ = jsonObject.Close()
- switchProxyMode()
+
Config.ImageMap = parseImgMap(Config.ImageMap)
if slices.Contains(Config.ConvertTypes, "webp") {
@@ -282,12 +282,12 @@ func parseImgMap(imgMap map[string]string) map[string]string {
var parsedImgMap = map[string]string{}
httpRegexpMatcher := regexp.MustCompile(HttpRegexp)
for uriMap, uriMapTarget := range imgMap {
- if httpRegexpMatcher.Match([]byte(uriMap)) || strings.HasPrefix(uriMap, "/") {
+ if httpRegexpMatcher.Match([]byte(uriMapTarget)) || strings.HasPrefix(uriMap, "/") {
// Valid
parsedImgMap[uriMap] = uriMapTarget
} else {
// Invalid
- log.Warnf("IMG_MAP key '%s' does matches '%s' or starts with '/' - skipped", uriMap, HttpRegexp)
+ log.Warnf("IMG_MAP 值'%s'与'%s'不匹配或键不以“/”开头 -已跳过", uriMapTarget, HttpRegexp)
}
}
return parsedImgMap
@@ -299,12 +299,3 @@ type ExtraParams struct {
MaxWidth int // in px
MaxHeight int // in px
}
-
-func switchProxyMode() {
- matched, _ := regexp.MatchString(HttpRegexp, Config.ImgPath)
- if matched {
- // Enable proxy based on ImgPath should be deprecated in future versions
- log.Warn("Enable proxy based on ImgPath will be deprecated in future versions. Use IMG_MAP config options instead")
- ProxyMode = true
- }
-}
diff --git a/handler/router.go b/handler/router.go
index b2cff92..086acdc 100644
--- a/handler/router.go
+++ b/handler/router.go
@@ -4,7 +4,6 @@ import (
"net/http"
"net/url"
"path"
- "regexp"
"strconv"
"strings"
"webp_server_go/config"
@@ -16,43 +15,29 @@ import (
)
func Convert(c *fiber.Ctx) error {
- // this function need to do:
- // 1. get request path, query string
- // 2. generate rawImagePath, could be local path or remote url(possible with query string)
- // 3. pass it to encoder, get the result, send it back
-
- // normal http request will start with /
- // 检查路径是否以 "/" 开头
- if !strings.HasPrefix(c.Path(), "/") {
- return c.SendStatus(http.StatusBadRequest)
- }
-
- // 处理根路径请求
+ // 检查是否为根路径
if c.Path() == "/" {
return c.SendString("Welcome to CZL WebP Server")
}
var (
reqHostname = c.Hostname()
- reqHost = c.Protocol() + "://" + reqHostname // http://www.example.com:8000
reqHeader = &c.Request().Header
- reqURIRaw, _ = url.QueryUnescape(c.Path()) // /mypic/123.jpg
- reqURIwithQueryRaw, _ = url.QueryUnescape(c.OriginalURL()) // /mypic/123.jpg?someother=200&somebugs=200
- reqURI = path.Clean(reqURIRaw) // delete ../ in reqURI to mitigate directory traversal
- reqURIwithQuery = path.Clean(reqURIwithQueryRaw) // Sometimes reqURIwithQuery can be https://example.tld/mypic/123.jpg?someother=200&somebugs=200, we need to extract it
+ reqURIRaw, _ = url.QueryUnescape(c.Path())
+ reqURIwithQueryRaw, _ = url.QueryUnescape(c.OriginalURL())
+ reqURI = path.Clean(reqURIRaw)
+ reqURIwithQuery = path.Clean(reqURIwithQueryRaw)
filename = path.Base(reqURI)
realRemoteAddr = ""
- targetHostName = config.LocalHostAlias
- targetHost = config.Config.ImgPath
- proxyMode = config.ProxyMode
- mapMode = false
+ targetHostName = ""
+ targetHost = ""
- width, _ = strconv.Atoi(c.Query("width")) // Extra Params
- height, _ = strconv.Atoi(c.Query("height")) // Extra Params
- maxHeight, _ = strconv.Atoi(c.Query("max_height")) // Extra Params
- maxWidth, _ = strconv.Atoi(c.Query("max_width")) // Extra Params
+ width, _ = strconv.Atoi(c.Query("width"))
+ height, _ = strconv.Atoi(c.Query("height"))
+ maxHeight, _ = strconv.Atoi(c.Query("max_height"))
+ maxWidth, _ = strconv.Atoi(c.Query("max_width"))
extraParams = config.ExtraParams{
Width: width,
Height: height,
@@ -63,155 +48,65 @@ func Convert(c *fiber.Ctx) error {
log.Debugf("Incoming connection from %s %s %s", c.IP(), reqHostname, reqURIwithQuery)
- var rawImageAbs string
- var metadata = config.MetaFile{}
-
- // 非图片清况下302到源文件
- if !helper.IsImageFile(filename) {
- log.Infof("Non-image file requested: %s", reqURI)
- var redirectURL string
-
- // 检查是否存在匹配的 IMG_MAP
- for prefix, target := range config.Config.ImageMap {
- if strings.HasPrefix(reqURI, prefix) {
- // 检查目标是否为远程资源
- if strings.HasPrefix(target, "http://") || strings.HasPrefix(target, "https://") {
- // 远程资源,构造重定向 URL
- redirectURL = target + strings.TrimPrefix(reqURI, prefix)
- } else {
- // 本地资源,按原逻辑处理
- return c.SendFile(path.Join(target, strings.TrimPrefix(reqURI, prefix)))
- }
- break
- }
- }
-
- // 如果没有找到匹配的 IMG_MAP,或者是本地资源,使用默认的处理方式
- if redirectURL == "" {
- if proxyMode {
- redirectURL = realRemoteAddr
- } else {
- // 本地资源,按原逻辑处理
- localPath := path.Join(config.Config.ImgPath, reqURI)
- if helper.FileExists(localPath) {
- return c.SendFile(localPath)
- } else {
- return c.SendStatus(fiber.StatusNotFound)
- }
- }
- }
-
- // 只有在确定需要重定向时才执行重定向
- if redirectURL != "" {
- log.Infof("Redirecting to: %s", redirectURL)
- return c.Redirect(redirectURL, fiber.StatusFound)
+ // 检查路径是否匹配 IMG_MAP 中的任何前缀
+ var matchedPrefix string
+ var matchedTarget string
+ for prefix, target := range config.Config.ImageMap {
+ if strings.HasPrefix(reqURI, prefix) {
+ matchedPrefix = prefix
+ matchedTarget = target
+ break
}
}
+ // 如果不匹配任何 IMG_MAP 前缀,直接返回 404
+ if matchedPrefix == "" {
+ log.Warnf("请求的路径不匹配任何配置的 IMG_MAP: %s", c.Path())
+ return c.SendStatus(fiber.StatusNotFound)
+ }
+
+ // 设置目标主机信息
+ targetUrl, _ := url.Parse(matchedTarget)
+ targetHostName = targetUrl.Host
+ targetHost = targetUrl.Scheme + "://" + targetUrl.Host
+
+ // 调整请求 URI
+ reqURI = strings.Replace(reqURI, matchedPrefix, targetUrl.Path, 1)
+ reqURIwithQuery = strings.Replace(reqURIwithQuery, matchedPrefix, targetUrl.Path, 1)
+
+ // 构造远程地址
+ realRemoteAddr = targetHost + reqURIwithQuery
+
+ // 处理非图片文件
+ if !helper.IsImageFile(filename) {
+ log.Infof("Non-image file requested: %s", reqURI)
+ log.Infof("Redirecting to: %s", realRemoteAddr)
+ return c.Redirect(realRemoteAddr, fiber.StatusFound)
+ }
+
+ // 检查允许的文件类型
if !helper.CheckAllowedType(filename) {
msg := "不允许的文件扩展名 " + filename
log.Warn(msg)
- c.Status(http.StatusBadRequest)
- _ = c.Send([]byte(msg))
- return nil
+ return c.Status(http.StatusBadRequest).SendString(msg)
}
- // Rewrite the target backend if a mapping rule matches the hostname
- if hostMap, hostMapFound := config.Config.ImageMap[reqHost]; hostMapFound {
- log.Debugf("找到host映射 %s -> %s", reqHostname, hostMap)
- targetHostUrl, _ := url.Parse(hostMap)
- targetHostName = targetHostUrl.Host
- targetHost = targetHostUrl.Scheme + "://" + targetHostUrl.Host
- proxyMode = true
- } else {
- // There's not matching host mapping, now check for any URI map that apply
- httpRegexpMatcher := regexp.MustCompile(config.HttpRegexp)
- for uriMap, uriMapTarget := range config.Config.ImageMap {
- if strings.HasPrefix(reqURI, uriMap) {
- log.Debugf("找到 URI 映射 %s -> %s", uriMap, uriMapTarget)
- mapMode = true
-
- // if uriMapTarget we use the proxy mode to fetch the remote
- if httpRegexpMatcher.Match([]byte(uriMapTarget)) {
- targetHostUrl, _ := url.Parse(uriMapTarget)
- targetHostName = targetHostUrl.Host
- targetHost = targetHostUrl.Scheme + "://" + targetHostUrl.Host
- reqURI = strings.Replace(reqURI, uriMap, targetHostUrl.Path, 1)
- reqURIwithQuery = strings.Replace(reqURIwithQuery, uriMap, targetHostUrl.Path, 1)
- proxyMode = true
- } else {
- reqURI = strings.Replace(reqURI, uriMap, uriMapTarget, 1)
- reqURIwithQuery = strings.Replace(reqURIwithQuery, uriMap, uriMapTarget, 1)
- }
- break
- }
- }
-
- }
-
- if proxyMode {
-
- if !mapMode {
- // Don't deal with the encoding to avoid upstream compatibilities
- reqURI = c.Path()
- reqURIwithQuery = c.OriginalURL()
- }
-
- log.Tracef("reqURIwithQuery is %s", reqURIwithQuery)
-
- // Replace host in the URL
- // realRemoteAddr = strings.Replace(reqURIwithQuery, reqHost, targetHost, 1)
- realRemoteAddr = targetHost + reqURIwithQuery
- log.Debugf("realRemoteAddr is %s", realRemoteAddr)
- }
-
- if proxyMode {
- // 这是 proxyMode,我们必须使用这个 url 来下载并将其保存到本地路径,这也为我们提供了 rawImageAbs
- // https://test.webp.sh/mypic/123.jpg?someother=200&somebugs=200
-
- metadata = fetchRemoteImg(realRemoteAddr, targetHostName)
- rawImageAbs = path.Join(config.Config.RemoteRawPath, targetHostName, metadata.Id)
- } else {
- // not proxyMode, we'll use local path
- metadata = helper.ReadMetadata(reqURIwithQuery, "", targetHostName)
- if !mapMode {
- // by default images are hosted in ImgPath
- rawImageAbs = path.Join(config.Config.ImgPath, reqURI)
- } else {
- rawImageAbs = reqURI
- }
- // detect if source file has changed
- if metadata.Checksum != helper.HashFile(rawImageAbs) {
- log.Info("源文件已更改,重新编码...")
- helper.WriteMetadata(reqURIwithQuery, "", targetHostName)
- cleanProxyCache(path.Join(config.Config.ExhaustPath, targetHostName, metadata.Id))
- }
- }
+ // 获取远程图像元数据
+ metadata := fetchRemoteImg(realRemoteAddr, targetHostName)
+ rawImageAbs := path.Join(config.Config.RemoteRawPath, targetHostName, metadata.Id)
+ // 后续的图像处理逻辑
supportedFormats := helper.GuessSupportedFormat(reqHeader)
- // resize itself and return if only raw(original format) is supported
- if supportedFormats["raw"] == true &&
- supportedFormats["webp"] == false &&
- supportedFormats["avif"] == false &&
- supportedFormats["jxl"] == false {
- dest := path.Join(config.Config.ExhaustPath, targetHostName, metadata.Id)
- if !helper.ImageExists(dest) {
- encoder.ResizeItself(rawImageAbs, dest, extraParams)
- }
- return c.SendFile(dest)
- }
- // 检查原始图像是否存在,
+ // 检查原始图像是否存在
if !helper.ImageExists(rawImageAbs) {
helper.DeleteMetadata(reqURIwithQuery, targetHostName)
msg := "Image not found!"
- _ = c.Send([]byte(msg))
log.Warn(msg)
- _ = c.SendStatus(404)
- return nil
+ return c.Status(404).SendString(msg)
}
- // 新增:检查文件大小
+ // 检查文件大小
isSmall, err := helper.IsFileSizeSmall(rawImageAbs, 100*1024) // 100KB
if err != nil {
log.Errorf("检查文件大小时出错: %v", err)
@@ -224,7 +119,7 @@ func Convert(c *fiber.Ctx) error {
}
avifAbs, webpAbs, jxlAbs := helper.GenOptimizedAbsPath(metadata, targetHostName)
- // Do the convertion based on supported formats and config
+ // 根据支持的格式和配置进行转换
encoder.ConvertFilter(rawImageAbs, jxlAbs, avifAbs, webpAbs, extraParams, supportedFormats, nil)
var availableFiles = []string{rawImageAbs}