fix: Modify getURL method to correctly support special characters
fixes https://github.com/rhnvrm/simples3/issues/7
This commit is contained in:
+58
-7
@@ -7,6 +7,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
@@ -15,8 +16,10 @@ import (
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -159,17 +162,23 @@ func (s3 *S3) getClient() *http.Client {
|
||||
return s3.Client
|
||||
}
|
||||
|
||||
func (s3 *S3) getURL(bucket string, args ...string) (uri string) {
|
||||
// getURL constructs a URL for a given path, with multiple optional
|
||||
// arguments as individual subfolders, based on the endpoint
|
||||
// specified in s3 struct.
|
||||
func (s3 *S3) getURL(path string, args ...string) (uri string) {
|
||||
if len(args) > 0 {
|
||||
path += "/" + strings.Join(args, "/")
|
||||
}
|
||||
// need to encode special characters in the path part of the URL
|
||||
encodedPath := encodePath(path)
|
||||
|
||||
if len(s3.Endpoint) > 0 {
|
||||
uri = s3.Endpoint + "/" + bucket
|
||||
uri = s3.Endpoint + "/" + encodedPath
|
||||
} else {
|
||||
uri = fmt.Sprintf(s3.URIFormat, s3.Region, bucket)
|
||||
uri = fmt.Sprintf(s3.URIFormat, s3.Region, encodedPath)
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
uri = uri + "/" + strings.Join(args, "/")
|
||||
}
|
||||
return
|
||||
return uri
|
||||
}
|
||||
|
||||
// SetEndpoint can be used to the set a custom endpoint for
|
||||
@@ -391,3 +400,45 @@ func (s3 *S3) FileDelete(u DeleteInput) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// if object matches reserved string, no need to encode them
|
||||
var reservedObjectNames = regexp.MustCompile("^[a-zA-Z0-9-_.~/]+$")
|
||||
|
||||
// encodePath encode the strings from UTF-8 byte representations to HTML hex escape sequences
|
||||
//
|
||||
// This is necessary since regular url.Parse() and url.Encode() functions do not support UTF-8
|
||||
// non english characters cannot be parsed due to the nature in which url.Encode() is written
|
||||
//
|
||||
// This function on the other hand is a direct replacement for url.Encode() technique to support
|
||||
// pretty much every UTF-8 character.
|
||||
// adapted from https://github.com/minio/minio-go/blob/fe1f3855b146c1b6ce4199740d317e44cf9e85c2/pkg/s3utils/utils.go#L285
|
||||
func encodePath(pathName string) string {
|
||||
if reservedObjectNames.MatchString(pathName) {
|
||||
return pathName
|
||||
}
|
||||
var encodedPathname strings.Builder
|
||||
for _, s := range pathName {
|
||||
if 'A' <= s && s <= 'Z' || 'a' <= s && s <= 'z' || '0' <= s && s <= '9' { // §2.3 Unreserved characters (mark)
|
||||
encodedPathname.WriteRune(s)
|
||||
continue
|
||||
}
|
||||
switch s {
|
||||
case '-', '_', '.', '~', '/': // §2.3 Unreserved characters (mark)
|
||||
encodedPathname.WriteRune(s)
|
||||
continue
|
||||
default:
|
||||
len := utf8.RuneLen(s)
|
||||
if len < 0 {
|
||||
// if utf8 cannot convert, return the same string as is
|
||||
return pathName
|
||||
}
|
||||
u := make([]byte, len)
|
||||
utf8.EncodeRune(u, s)
|
||||
for _, r := range u {
|
||||
hex := hex.EncodeToString([]byte{r})
|
||||
encodedPathname.WriteString("%" + strings.ToUpper(hex))
|
||||
}
|
||||
}
|
||||
}
|
||||
return encodedPathname.String()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user