diff options
Diffstat (limited to 'pipkin.go')
-rw-r--r-- | pipkin.go | 56 |
1 files changed, 21 insertions, 35 deletions
@@ -14,12 +14,13 @@ import ( "io" "log" "net/http" - "net/url" "os" "path" "strings" "syscall" "time" + + "pipkin/url" ) type Pipkin struct { @@ -305,15 +306,8 @@ func (pk *Pipkin) presignQuery(method string, host Host, key string) (string, er amzBucket := pk.config.Buckets[host.Bucket] amzDateShort := time.Now().UTC().Format("20060102") + amzDateLong := time.Now().UTC().Format("20060102T150405Z") // ISO 8601 - // The date needs to follow the ISO 8601 standard and must be formatted with - // the "yyyyMMddTHHmmssZ" format. - amzDateLong := time.Now().UTC().Format("20060102T150405Z") - - // amzAlgorithm identifies the version of AWS Signature and the algorithm - // that you used to calculate the signature; for AWS Signature Version 4, - // this value is AWS4-HMAC-SHA256--AWS Signature Version 4 (AWS4) and the - // HMAC-SHA256 algorithm (HMAC-SHA256). amzAlgorithm := "AWS4-HMAC-SHA256" amzService := "s3" @@ -321,22 +315,20 @@ func (pk *Pipkin) presignQuery(method string, host Host, key string) (string, er amzCred := fmt.Sprintf("%s/%s/%s/%s/aws4_request", amzBucket.KeyID, amzDateShort, amzBucket.Region, amzService) - // Prefix current key with path value from pipkin.json; we support virtual - // hosts, e.g. /example.com/index.html - // - // url.JoinPath() encodes the path, so we have to call url.PathUnescape() - // on amzResource when we create our Prefix and the final signed URL. - amzResource, err := url.JoinPath(host.Path, key) - if err != nil { - return "", err - } - var amzPrefix string - if strings.HasSuffix(amzResource, "/") { - if len(amzResource) > 1 { - amzPrefix = strings.TrimPrefix(amzResource, "/") - amzPrefix, _ = url.PathUnescape(amzPrefix) + var amzKey, amzPrefix string + amzKey = path.Join(host.Path, key) + if strings.HasSuffix(key, "/") { + + // path.Join() strips trailing slash, but we need one for prefix + if !strings.HasSuffix(amzKey, "/") { + amzKey += "/" } - amzResource = "/" + + // Request for non-root directory + if len(amzKey) > 1 { + amzPrefix = strings.TrimPrefix(amzKey, "/") + } + amzKey = "/" } // Seconds for which the generated presigned URL is valid; for example, @@ -359,7 +351,7 @@ func (pk *Pipkin) presignQuery(method string, host Host, key string) (string, er uri.Add("X-Amz-Date", amzDateLong) uri.Add("X-Amz-Expires", amzExpires) uri.Add("X-Amz-SignedHeaders", amzSignedHeaders) - if strings.HasSuffix(amzResource, "/") { + if strings.HasSuffix(amzKey, "/") { uri.Add("list-type", "2") uri.Add("max-keys", "50000") uri.Add("prefix", amzPrefix) @@ -373,10 +365,9 @@ func (pk *Pipkin) presignQuery(method string, host Host, key string) (string, er // // host // UNSIGNED-PAYLOAD - uriEncoded := strings.Replace(uri.Encode(), "+", "%20", -1) canonicalRequest := fmt.Sprintf("%s\n%s\n%s\nhost:%s\n\n%s\n%s", method, - amzResource, uriEncoded, amzBucket.Host, amzSignedHeaders, - "UNSIGNED-PAYLOAD") + strings.Replace(url.PathEscape(amzKey), "%2F", "/", -1), uri.Encode(), + amzBucket.Host, amzSignedHeaders, "UNSIGNED-PAYLOAD") // <yyyymmdd>/<AWS Region>/s3/aws4_request amzScope := fmt.Sprintf("%s/%s/%s/aws4_request", amzDateShort, @@ -407,19 +398,14 @@ func (pk *Pipkin) presignQuery(method string, host Host, key string) (string, er amzSignatureSha256 := hmac.New(sha256.New, signingKey.Sum(nil)) amzSignatureSha256.Write([]byte(strToSign)) - // Provides the signature to authenticate our request. This signature must - // match the signature S3 calculates; otherwise, S3 denies the request. amzSignatureSha256Hex := hex.EncodeToString(amzSignatureSha256.Sum(nil)) signedURL, err := url.Parse(amzBucket.Endpoint) if err != nil { return "", err } - - // Build & encode signed URL! We've calculated everything we need, now. uri.Add("X-Amz-Signature", amzSignatureSha256Hex) - signedURL.Path, _ = url.PathUnescape(amzResource) - uriEncoded = strings.Replace(uri.Encode(), "+", "%20", -1) - signedURL.RawQuery = uriEncoded + signedURL.Path = amzKey + signedURL.RawQuery = uri.Encode() return signedURL.String(), nil } |