54 lines
1.8 KiB
Go
54 lines
1.8 KiB
Go
package s3
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
|
|
"git.yuntuo.hk/k2safe/go-omni/storage"
|
|
)
|
|
|
|
func (s *Store) PresignGetWithOptions(ctx context.Context, key string, ttl time.Duration, options storage.ReadOptions) (storage.ReadLink, error) {
|
|
if err := storage.Check(ctx, key); err != nil {
|
|
return storage.ReadLink{}, err
|
|
}
|
|
if ttl < time.Second || ttl > time.Hour {
|
|
return storage.ReadLink{}, errors.New("storage/s3: TTL must be 1s..1h")
|
|
}
|
|
headers, err := options.ResponseHeaders()
|
|
if err != nil {
|
|
return storage.ReadLink{}, err
|
|
}
|
|
query := url.Values{"response-content-disposition": {headers.Get("Content-Disposition")}, "response-cache-control": {headers.Get("Cache-Control")}}
|
|
if contentType := headers.Get("Content-Type"); contentType != "" {
|
|
query.Set("response-content-type", contentType)
|
|
}
|
|
u, err := s.client.PresignedGetObject(ctx, s.bucket, key, ttl, query)
|
|
if err != nil {
|
|
return storage.ReadLink{}, err
|
|
}
|
|
// Derive the exact expiry from the SDK's signed URL, not a second clock read
|
|
// around credential discovery or bucket-region lookup.
|
|
q := u.Query()
|
|
var expires time.Time
|
|
if q.Get("X-Amz-Signature") != "" {
|
|
start, e := time.Parse("20060102T150405Z", q.Get("X-Amz-Date"))
|
|
seconds, e2 := strconv.ParseInt(q.Get("X-Amz-Expires"), 10, 64)
|
|
if e != nil || e2 != nil || seconds < 1 || seconds > 3600 {
|
|
return storage.ReadLink{}, errors.New("storage/s3: invalid signed expiry")
|
|
}
|
|
expires = start.Add(time.Duration(seconds) * time.Second)
|
|
} else {
|
|
seconds, e := strconv.ParseInt(q.Get("Expires"), 10, 64)
|
|
if e != nil || q.Get("Signature") == "" {
|
|
return storage.ReadLink{}, errors.New("storage/s3: missing signed expiry")
|
|
}
|
|
expires = time.Unix(seconds, 0).UTC()
|
|
}
|
|
return storage.ReadLink{URL: u.String(), ExpiresAt: expires}, nil
|
|
}
|
|
|
|
var _ storage.ReadPresigner = (*Store)(nil)
|