fix: Modify getURL method to correctly support special characters

fixes https://github.com/rhnvrm/simples3/issues/7
This commit is contained in:
Jack Henschel
2021-02-03 17:47:51 +02:00
parent c97ddac6df
commit ce1c250422
+58 -7
View File
@@ -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()
}