refractor OSS url parser

This commit is contained in:
tickstep studio team
2026-06-29 10:27:00 +08:00
parent acc408f0a0
commit e62bdbb9f1
3 changed files with 73 additions and 27 deletions
+4 -19
View File
@@ -23,6 +23,7 @@ import (
"strconv"
"time"
"github.com/tickstep/aliyunpan/internal/utils"
"github.com/tickstep/library-go/logger"
"github.com/tickstep/library-go/requester"
)
@@ -103,31 +104,15 @@ func fixCacheSize(size *int) {
// IsUrlExpired 下载链接是否已过期。过期返回True
func IsUrlExpired(urlStr string) bool {
u, err := url.Parse(urlStr)
expiredTimeSec, err := utils.GetExpiredTimeSecFromOSSUrl(urlStr)
if err != nil {
// 解析错误,默认过期
return true
}
// OSS V4签名:x-oss-date=20260629T010316Z&x-oss-expires=900
expiredDateStr := u.Query().Get("x-oss-date") // 该请求/签名生成的时间
expiredTimeSecStr := u.Query().Get("x-oss-expires") // Presigned URL 的过期时间(单位:秒)
// 解析 x-oss-date(ISO8601,UTC)
expiredDate, err := time.Parse("20060102T150405Z", expiredDateStr)
if err != nil {
// 非法时间格式
return true
}
// 解析 x-oss-expires(秒)
expireSec, err := strconv.ParseInt(expiredTimeSecStr, 10, 64)
if err != nil || expireSec <= 0 {
// 非法过期时间
return true
}
// 计算过期时间戳(Unix seconds)
expiredTimeSec := expiredDate.Unix() + expireSec
if (expiredTimeSec - time.Now().Unix()) <= 5 { // 小于5秒钟
// expired
return true
}
// 返回未过期
return false
}
+8 -8
View File
@@ -16,15 +16,15 @@ package panupload
import (
"crypto/sha1"
"encoding/hex"
"github.com/tickstep/aliyunpan/internal/config"
"github.com/tickstep/library-go/converter"
"github.com/tickstep/library-go/logger"
"net/url"
"os"
"path"
"strconv"
"strings"
"time"
"github.com/tickstep/aliyunpan/internal/config"
"github.com/tickstep/aliyunpan/internal/utils"
"github.com/tickstep/library-go/converter"
"github.com/tickstep/library-go/logger"
)
const (
@@ -55,16 +55,16 @@ func getBlockSize(fileSize int64) int64 {
// IsUrlExpired 上传链接是否已过期。过期返回True
func IsUrlExpired(urlStr string) bool {
u, err := url.Parse(urlStr)
expiredTimeSec, err := utils.GetExpiredTimeSecFromOSSUrl(urlStr)
if err != nil {
// 解析错误,默认过期
return true
}
expiredTimeSecStr := u.Query().Get("x-oss-expires")
expiredTimeSec, _ := strconv.ParseInt(expiredTimeSecStr, 10, 64)
if (expiredTimeSec - time.Now().Unix()) <= 300 { // 小于5分钟
// expired
return true
}
// 返回未过期
return false
}
+61
View File
@@ -383,3 +383,64 @@ func GetPublicIP() (string, error) {
ip := strings.TrimSpace(strings.Split(ipResp.Origin, ",")[0])
return ip, nil
}
// GetExpiredTimeSecFromOSSUrl 从OSS URL中解析出统一的过期时间戳(秒)
func GetExpiredTimeSecFromOSSUrl(rawURL string) (int64, error) {
parsedURL, err := url.Parse(rawURL)
if err != nil {
return 0, fmt.Errorf("failed to parse URL: %w", err)
}
query := parsedURL.Query()
sigVersion := query.Get("x-oss-signature-version")
var expires int64 = 0
// 检测版本标识(不区分大小写)
if strings.Contains(sigVersion, "OSS4") {
// V4 签名:x-oss-expires 为相对秒数,需要结合 x-oss-date
expiresStr := query.Get("x-oss-expires")
if expiresStr == "" {
return 0, fmt.Errorf("V4 signature: 'x-oss-expires' parameter not found")
}
relSec, err := strconv.ParseInt(expiresStr, 10, 64)
if err != nil {
return 0, fmt.Errorf("V4 signature: invalid 'x-oss-expires' value: %w", err)
}
dateStr := query.Get("x-oss-date")
if dateStr == "" {
return 0, fmt.Errorf("V4 signature: 'x-oss-date' parameter not found")
}
// 解析 ISO8601 UTC 时间,例如 "20231220T083018Z"
t, err := time.Parse("20060102T150405Z", dateStr)
if err != nil {
return 0, fmt.Errorf("V4 signature: failed to parse 'x-oss-date': %w", err)
}
expires = t.Unix() + relSec
} else if strings.Contains(sigVersion, "OSS3") || strings.Contains(sigVersion, "OSS2") {
// V2 / V3:x-oss-expires 为绝对时间戳
expiresStr := query.Get("x-oss-expires")
if expiresStr == "" {
return 0, fmt.Errorf("V2/V3 signature: 'x-oss-expires' parameter not found")
}
expires, err = strconv.ParseInt(expiresStr, 10, 64)
if err != nil {
return 0, fmt.Errorf("V2/V3 signature: invalid 'x-oss-expires' value: %w", err)
}
} else {
// 默认为 V1 签名(没有 x-oss-signature-version 或为空)
expiresStr := query.Get("Expires")
if expiresStr == "" {
return 0, fmt.Errorf("V1 signature: 'Expires' parameter not found")
}
expires, err = strconv.ParseInt(expiresStr, 10, 64)
if err != nil {
return 0, fmt.Errorf("V1 signature: invalid 'Expires' value: %w", err)
}
}
return expires, nil
}