Skip to content

Commit

Permalink
Merge pull request #20 from qiniu/features/make-url-with-escaped-key
Browse files Browse the repository at this point in the history
增加 MakePrivateURLv2*() & MakePublicURLv2*() 系列方法来生成 escape 过的 key 的 url
  • Loading branch information
Mei-Zhao authored Apr 22, 2021
2 parents 53d6a8a + ee1dfbb commit bb7e742
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 2 deletions.
73 changes: 71 additions & 2 deletions storage/bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ func EncodedEntryWithoutKey(bucket string) string {
return base64.URLEncoding.EncodeToString([]byte(bucket))
}

// MakePublicURL 用来生成公开空间资源下载链接
// MakePublicURL 用来生成公开空间资源下载链接,注意该方法并不会对 key 进行 escape
func MakePublicURL(domain, key string) (finalUrl string) {
domain = strings.TrimRight(domain, "/")
srcUrl := fmt.Sprintf("%s/%s", domain, key)
Expand All @@ -734,7 +734,36 @@ func MakePublicURL(domain, key string) (finalUrl string) {
return
}

// MakePrivateURL 用来生成私有空间资源下载链接
// MakePublicURLv2 用来生成公开空间资源下载链接,并且该方法确保 key 将会被 escape
func MakePublicURLv2(domain, key string) string {
return MakePublicURLv2WithQuery(domain, key, nil)
}

// MakePublicURLv2WithQuery 用来生成公开空间资源下载链接,并且该方法确保 key 将会被 escape,并在 URL 后追加经过编码的查询参数
func MakePublicURLv2WithQuery(domain, key string, query url.Values) string {
var rawQuery string
if query != nil {
rawQuery = query.Encode()
}
return makePublicURLv2WithRawQuery(domain, key, rawQuery)
}

// MakePublicURLv2WithQueryString 用来生成公开空间资源下载链接,并且该方法确保 key 将会被 escape,并在 URL 后直接追加查询参数
func makePublicURLv2WithQueryString(domain, key, query string) string {
return makePublicURLv2WithRawQuery(domain, key, urlEncodeQuery(query))
}

func makePublicURLv2WithRawQuery(domain, key, rawQuery string) string {
domain = strings.TrimRight(domain, "/")
srcUrl := fmt.Sprintf("%s/%s", domain, urlEncodeQuery(key))
if rawQuery != "" {
srcUrl += "?" + rawQuery
}
srcUri, _ := url.Parse(srcUrl)
return srcUri.String()
}

// MakePrivateURL 用来生成私有空间资源下载链接,注意该方法并不会对 key 进行 escape
func MakePrivateURL(mac *auth.Credentials, domain, key string, deadline int64) (privateURL string) {
publicURL := MakePublicURL(domain, key)
urlToSign := publicURL
Expand All @@ -748,6 +777,46 @@ func MakePrivateURL(mac *auth.Credentials, domain, key string, deadline int64) (
return
}

// MakePrivateURLv2 用来生成私有空间资源下载链接,并且该方法确保 key 将会被 escape
func MakePrivateURLv2(mac *auth.Credentials, domain, key string, deadline int64) (privateURL string) {
return MakePrivateURLv2WithQuery(mac, domain, key, nil, deadline)
}

// MakePrivateURLv2WithQuery 用来生成私有空间资源下载链接,并且该方法确保 key 将会被 escape,并在 URL 后追加经过编码的查询参数
func MakePrivateURLv2WithQuery(mac *auth.Credentials, domain, key string, query url.Values, deadline int64) (privateURL string) {
var rawQuery string
if query != nil {
rawQuery = query.Encode()
}
return makePrivateURLv2WithRawQuery(mac, domain, key, rawQuery, deadline)
}

// MakePrivateURLv2WithQueryString 用来生成私有空间资源下载链接,并且该方法确保 key 将会被 escape,并在 URL 后直接追加查询参数
func MakePrivateURLv2WithQueryString(mac *auth.Credentials, domain, key, query string, deadline int64) (privateURL string) {
return makePrivateURLv2WithRawQuery(mac, domain, key, urlEncodeQuery(query), deadline)
}

func makePrivateURLv2WithRawQuery(mac *auth.Credentials, domain, key, rawQuery string, deadline int64) (privateURL string) {
publicURL := makePublicURLv2WithRawQuery(domain, key, rawQuery)
urlToSign := publicURL
if strings.Contains(publicURL, "?") {
urlToSign = fmt.Sprintf("%s&e=%d", urlToSign, deadline)
} else {
urlToSign = fmt.Sprintf("%s?e=%d", urlToSign, deadline)
}
token := mac.Sign([]byte(urlToSign))
privateURL = fmt.Sprintf("%s&token=%s", urlToSign, token)
return
}

func urlEncodeQuery(str string) (ret string) {
str = url.QueryEscape(str)
str = strings.Replace(str, "%2F", "/", -1)
str = strings.Replace(str, "%7C", "|", -1)
str = strings.Replace(str, "+", "%20", -1)
return str
}

type listFilesRet2 struct {
Marker string `json:"marker"`
Item ListItem `json:"item"`
Expand Down
53 changes: 53 additions & 0 deletions storage/bucket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"math/rand"
"net/http"
"net/url"
"os"
"strings"
"testing"
Expand Down Expand Up @@ -583,3 +584,55 @@ func TestSetBucketAccessMode(t *testing.T) {
t.Fatalf("TestSetBucketAccessMode: %q\n", err)
}
}

func TestMakeURL(t *testing.T) {
keys := map[string]string{ //rawKey => encodeKey,
"": "",
"abc_def.mp4": "abc_def.mp4",
"/ab/cd": "/ab/cd",
"ab/中文/de": "ab/%E4%B8%AD%E6%96%87/de",
// "ab+-*de f": "ab%2B-%2Ade%20f",
"ab:cd": "ab%3Acd",
// "ab@cd": "ab%40cd",
"ab?cd=ef": "ab%3Fcd%3Def",
"ab#e~f": "ab%23e~f",
"ab//cd": "ab//cd",
"abc%2F%2B": "abc%252F%252B",
"ab cd": "ab%20cd",
// "ab/c:d?e#f//gh汉子": "ab/c%3Ad%3Fe%23f//gh%E6%B1%89%E5%AD%90",
}
s := MakePublicURL("https://abc.com:123/", "123/def?@#")
if s != "https://abc.com:123/123/def?@" {
t.Fatalf("TestMakeURL: %q\n", s)
}

s = MakePublicURL("abc.com:123/", "123/def?@#")
if s != "abc.com:123/123/def?@" {
t.Fatalf("TestMakeURL: %q\n", s)
}

q := make(url.Values)
q.Add("?", "#")
s = MakePublicURLv2WithQuery("https://abc.com:123/", "123/def?@#", q)
if s != "https://abc.com:123/123/def%3F%40%23?%3F=%23" {
t.Fatalf("TestMakeURL: %q\n", s)
}

s = makePublicURLv2WithQueryString("http://abc.com:123/", "123/def?@#|", "123/def?@#|")
if s != "http://abc.com:123/123/def%3F@%23%7C?123/def%3F%40%23|" {
t.Fatalf("TestMakeURL: %q\n", s)
}

s = MakePublicURLv2("http://abc.com:123/", "123/def?@#")
if s != "http://abc.com:123/123/def%3F%40%23" {
t.Fatalf("TestMakeURL: %q\n", s)
}

for rawKey, encodedKey := range keys {
s = MakePublicURLv2("http://abc.com:123/", rawKey)
e := "http://abc.com:123/" + encodedKey
if s != e {
t.Fatalf("TestMakeURL: %q %q\n", s, e)
}
}
}

0 comments on commit bb7e742

Please sign in to comment.