mirror of
https://github.com/XTXMarkets/ternfs.git
synced 2026-01-06 02:49:45 -06:00
S3 gateway
No auth, no checksums. Integrated in the fstests.
This commit is contained in:
committed by
Francesco Mazzoli
parent
5b924fb272
commit
f9fd75b66f
@@ -41,6 +41,7 @@ else:
|
||||
# Otherwise go will try to create the cache in /.cache, which won't work
|
||||
# since we're not running as root.
|
||||
os.environ['GOCACHE'] = '/eggsfs/.cache'
|
||||
os.environ['GOMODCACHE'] = '/eggsfs/.go-cache'
|
||||
if args.generate:
|
||||
subprocess.run(['go', 'generate', './...'], cwd=go_dir, check=True)
|
||||
else:
|
||||
|
||||
@@ -177,6 +177,7 @@ type metadataProcessorRequest struct {
|
||||
type metadataProcessorResponse struct {
|
||||
requestId uint64
|
||||
resp any
|
||||
extra any
|
||||
err error
|
||||
}
|
||||
|
||||
@@ -308,6 +309,7 @@ func (cm *clientMetadata) processRequests(log *lib.Logger) {
|
||||
req.respCh <- &metadataProcessorResponse{
|
||||
requestId: req.requestId,
|
||||
err: err,
|
||||
extra: req.extra,
|
||||
resp: nil,
|
||||
}
|
||||
}
|
||||
@@ -341,6 +343,7 @@ func (cm *clientMetadata) processRequests(log *lib.Logger) {
|
||||
req.respCh <- &metadataProcessorResponse{
|
||||
requestId: req.requestId,
|
||||
err: err,
|
||||
extra: req.extra,
|
||||
resp: nil,
|
||||
}
|
||||
}
|
||||
@@ -398,6 +401,7 @@ func (cm *clientMetadata) parseResponse(log *lib.Logger, req *metadataProcessorR
|
||||
req.respCh <- &metadataProcessorResponse{
|
||||
requestId: req.requestId,
|
||||
err: err,
|
||||
extra: req.extra,
|
||||
resp: nil,
|
||||
}
|
||||
} else {
|
||||
@@ -409,6 +413,7 @@ func (cm *clientMetadata) parseResponse(log *lib.Logger, req *metadataProcessorR
|
||||
req.respCh <- &metadataProcessorResponse{
|
||||
requestId: req.requestId,
|
||||
err: msgs.MALFORMED_RESPONSE,
|
||||
extra: req.extra,
|
||||
resp: nil,
|
||||
}
|
||||
return
|
||||
@@ -420,6 +425,7 @@ func (cm *clientMetadata) parseResponse(log *lib.Logger, req *metadataProcessorR
|
||||
req.respCh <- &metadataProcessorResponse{
|
||||
requestId: req.requestId,
|
||||
err: msgs.MALFORMED_RESPONSE,
|
||||
extra: req.extra,
|
||||
resp: nil,
|
||||
}
|
||||
return
|
||||
@@ -431,6 +437,7 @@ func (cm *clientMetadata) parseResponse(log *lib.Logger, req *metadataProcessorR
|
||||
req.respCh <- &metadataProcessorResponse{
|
||||
requestId: req.requestId,
|
||||
err: err,
|
||||
extra: req.extra,
|
||||
resp: nil,
|
||||
}
|
||||
return
|
||||
@@ -440,6 +447,7 @@ func (cm *clientMetadata) parseResponse(log *lib.Logger, req *metadataProcessorR
|
||||
req.respCh <- &metadataProcessorResponse{
|
||||
requestId: req.requestId,
|
||||
err: nil,
|
||||
extra: req.extra,
|
||||
resp: req.resp,
|
||||
}
|
||||
}
|
||||
@@ -477,6 +485,7 @@ func (cm *clientMetadata) processRawResponse(log *lib.Logger, rawResp *rawMetada
|
||||
first.respCh <- &metadataProcessorResponse{
|
||||
requestId: first.requestId,
|
||||
err: msgs.TIMEOUT,
|
||||
extra: first.extra,
|
||||
resp: nil,
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -933,6 +933,7 @@ type fileReader struct {
|
||||
log *lib.Logger
|
||||
bufPool *lib.BufPool
|
||||
fileId msgs.InodeId
|
||||
fileSize int64 // if -1, we haven't initialized this yet
|
||||
blockServices []msgs.BlockService
|
||||
spans []msgs.FetchedSpan
|
||||
currentStripe *FetchedStripe
|
||||
@@ -963,11 +964,32 @@ func (f *fileReader) Read(p []byte) (int, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (f *fileReader) Seek(offset int64, whence int) (int64, error) {
|
||||
switch whence {
|
||||
case io.SeekStart:
|
||||
f.cursor = uint64(offset)
|
||||
case io.SeekCurrent:
|
||||
f.cursor = uint64(int64(f.cursor) + offset)
|
||||
case io.SeekEnd:
|
||||
if f.fileSize < 0 {
|
||||
resp := msgs.StatFileResp{}
|
||||
if err := f.client.ShardRequest(f.log, f.fileId.Shard(), &msgs.StatFileReq{Id: f.fileId}, &resp); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
f.fileSize = int64(resp.Size)
|
||||
}
|
||||
f.cursor = uint64(f.fileSize + offset)
|
||||
default:
|
||||
return 0, fmt.Errorf("bad whence %v", whence)
|
||||
}
|
||||
return int64(f.cursor), nil
|
||||
}
|
||||
|
||||
func (c *Client) ReadFile(
|
||||
log *lib.Logger,
|
||||
bufPool *lib.BufPool,
|
||||
id msgs.InodeId,
|
||||
) (io.ReadCloser, error) {
|
||||
) (io.ReadSeekCloser, error) {
|
||||
blockServices, spans, err := c.FetchSpans(log, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -977,6 +999,7 @@ func (c *Client) ReadFile(
|
||||
log: log,
|
||||
bufPool: bufPool,
|
||||
fileId: id,
|
||||
fileSize: -1,
|
||||
blockServices: blockServices,
|
||||
spans: spans,
|
||||
}
|
||||
|
||||
100
go/eggss3/eggss3.go
Normal file
100
go/eggss3/eggss3.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"xtx/eggsfs/client"
|
||||
"xtx/eggsfs/lib"
|
||||
"xtx/eggsfs/msgs"
|
||||
"xtx/eggsfs/s3"
|
||||
)
|
||||
|
||||
// bucketFlag is a custom flag type to handle multiple "-bucket" arguments.
|
||||
type bucketFlag []string
|
||||
|
||||
func (b *bucketFlag) String() string {
|
||||
return fmt.Sprintf("%v", *b)
|
||||
}
|
||||
|
||||
func (b *bucketFlag) Set(value string) error {
|
||||
*b = append(*b, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
var buckets bucketFlag
|
||||
flag.Var(&buckets, "bucket", "Bucket mapping in format <bucket-name>:<root-path>. Can be repeated.")
|
||||
virtualHost := flag.String("virtual", "", "Domain for virtual host-style requests, e.g., 's3.example.com'")
|
||||
addr := flag.String("addr", ":8080", "Address and port to listen on")
|
||||
eggsfsAddr := flag.String("eggsfs", "localhost:10001", "Address of the eggsfs metaserver")
|
||||
verbose := flag.Bool("verbose", false, "")
|
||||
trace := flag.Bool("trace", false, "")
|
||||
flag.Parse()
|
||||
|
||||
level := lib.INFO
|
||||
if *verbose {
|
||||
level = lib.DEBUG
|
||||
}
|
||||
if *trace {
|
||||
level = lib.TRACE
|
||||
}
|
||||
|
||||
log := lib.NewLogger(os.Stdout, &lib.LoggerOptions{
|
||||
Level: level,
|
||||
AppInstance: "eggss3",
|
||||
AppType: "restech_eggsfs.daytime",
|
||||
PrintQuietAlerts: true,
|
||||
})
|
||||
|
||||
if len(buckets) == 0 {
|
||||
fmt.Fprintf(os.Stderr, "At least one -bucket flag is required.")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
c, err := client.NewClient(
|
||||
log,
|
||||
nil,
|
||||
*eggsfsAddr,
|
||||
msgs.AddrsInfo{},
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to create eggsfs client: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
bucketPaths := make(map[string]string)
|
||||
for _, b := range buckets {
|
||||
parts := strings.SplitN(b, ":", 2)
|
||||
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
|
||||
fmt.Fprint(os.Stderr, "Invalid bucket format %q. Expected <bucket-name>:<root-path>", b)
|
||||
os.Exit(2)
|
||||
}
|
||||
bucketName, rootPath := parts[0], parts[1]
|
||||
log.Info("Mapping bucket %q to path %q", bucketName, rootPath)
|
||||
bucketPaths[bucketName] = rootPath
|
||||
}
|
||||
|
||||
s3Server := s3.NewS3Server(
|
||||
log,
|
||||
c,
|
||||
lib.NewBufPool(),
|
||||
client.NewDirInfoCache(),
|
||||
bucketPaths,
|
||||
*virtualHost,
|
||||
)
|
||||
|
||||
server := &http.Server{
|
||||
Addr: *addr,
|
||||
Handler: s3Server,
|
||||
}
|
||||
log.Info("Starting S3 gateway on %q", *addr)
|
||||
if *virtualHost != "" {
|
||||
log.Info("Virtual host routing enabled for domain: %q", *virtualHost)
|
||||
}
|
||||
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -319,7 +319,7 @@ func (r *RunTests) run(
|
||||
"direct fs",
|
||||
fmt.Sprintf("%v dirs, %v files, %v depth", fsTestOpts.numDirs, fsTestOpts.numFiles, fsTestOpts.depth),
|
||||
func(counters *client.ClientCounters) {
|
||||
fsTest(log, r.shuckleAddress(), &fsTestOpts, counters, "")
|
||||
fsTest(log, r.shuckleAddress(), &fsTestOpts, counters, apiHarness{})
|
||||
},
|
||||
)
|
||||
|
||||
@@ -328,7 +328,16 @@ func (r *RunTests) run(
|
||||
"mounted fs",
|
||||
fmt.Sprintf("%v dirs, %v files, %v depth", fsTestOpts.numDirs, fsTestOpts.numFiles, fsTestOpts.depth),
|
||||
func(counters *client.ClientCounters) {
|
||||
fsTest(log, r.shuckleAddress(), &fsTestOpts, counters, r.mountPoint)
|
||||
fsTest(log, r.shuckleAddress(), &fsTestOpts, counters, posixHarness{r.mountPoint})
|
||||
},
|
||||
)
|
||||
|
||||
r.test(
|
||||
log,
|
||||
"s3 fs",
|
||||
fmt.Sprintf("%v dirs, %v files, %v depth", fsTestOpts.numDirs, fsTestOpts.numFiles, fsTestOpts.depth),
|
||||
func(counters *client.ClientCounters) {
|
||||
fsTest(log, r.shuckleAddress(), &fsTestOpts, counters, s3Harness{})
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -3,11 +3,16 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -19,8 +24,12 @@ import (
|
||||
"xtx/eggsfs/client"
|
||||
"xtx/eggsfs/lib"
|
||||
"xtx/eggsfs/msgs"
|
||||
eggss3 "xtx/eggsfs/s3"
|
||||
"xtx/eggsfs/wyhash"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
s3config "github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
@@ -43,7 +52,7 @@ type fsTestOpts struct {
|
||||
|
||||
type fsTestHarness[Id comparable] interface {
|
||||
createDirectory(log *lib.Logger, owner Id, name string) (Id, msgs.EggsTime)
|
||||
rename(log *lib.Logger, targetId Id, oldOwner Id, oldCreationTime msgs.EggsTime, oldName string, newOwner Id, newName string) (Id, msgs.EggsTime)
|
||||
rename(log *lib.Logger, isDirectory bool, targetId Id, oldOwner Id, oldCreationTime msgs.EggsTime, oldName string, newOwner Id, newName string) (Id, msgs.EggsTime)
|
||||
createFile(log *lib.Logger, owner Id, spanSize uint32, name string, size uint64, dataSeed uint64) (Id, msgs.EggsTime)
|
||||
checkFileData(log *lib.Logger, id Id, size uint64, dataSeed uint64)
|
||||
// files, directories
|
||||
@@ -71,6 +80,7 @@ func (c *apiFsTestHarness) createDirectory(log *lib.Logger, owner msgs.InodeId,
|
||||
|
||||
func (c *apiFsTestHarness) rename(
|
||||
log *lib.Logger,
|
||||
isDirectory bool,
|
||||
targetId msgs.InodeId,
|
||||
oldOwner msgs.InodeId,
|
||||
oldCreationTime msgs.EggsTime,
|
||||
@@ -78,6 +88,9 @@ func (c *apiFsTestHarness) rename(
|
||||
newOwner msgs.InodeId,
|
||||
newName string,
|
||||
) (msgs.InodeId, msgs.EggsTime) {
|
||||
if isDirectory != (targetId.Type() == msgs.DIRECTORY) {
|
||||
panic("mismatching isDirectory")
|
||||
}
|
||||
if oldOwner == newOwner {
|
||||
req := msgs.SameDirectoryRenameReq{
|
||||
TargetId: targetId,
|
||||
@@ -199,6 +212,182 @@ func (c *apiFsTestHarness) removeDirectory(log *lib.Logger, ownerId msgs.InodeId
|
||||
|
||||
var _ = (fsTestHarness[msgs.InodeId])((*apiFsTestHarness)(nil))
|
||||
|
||||
type s3TestHarness struct {
|
||||
client *s3.Client
|
||||
bucket string
|
||||
bufPool *lib.BufPool
|
||||
}
|
||||
|
||||
func (c *s3TestHarness) createDirectory(log *lib.Logger, owner string, name string) (id string, creationTime msgs.EggsTime) {
|
||||
fullPath := path.Join(owner, name) + "/"
|
||||
_, err := c.client.PutObject(context.TODO(), &s3.PutObjectInput{
|
||||
Bucket: aws.String(c.bucket),
|
||||
Key: aws.String(fullPath),
|
||||
Body: bytes.NewReader([]byte{}),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return path.Join(owner, name), 0
|
||||
}
|
||||
|
||||
func (c *s3TestHarness) rename(log *lib.Logger, isDirectory bool, targetFullPath string, oldDir string, oldCreationTime msgs.EggsTime, oldName string, newDir string, newName string) (string, msgs.EggsTime) {
|
||||
if targetFullPath != path.Join(oldDir, oldName) {
|
||||
panic(fmt.Errorf("mismatching %v and %v", targetFullPath, path.Join(oldDir, oldName)))
|
||||
}
|
||||
sourcePath := targetFullPath
|
||||
if isDirectory {
|
||||
sourcePath += "/"
|
||||
}
|
||||
sinkPath := path.Join(newDir, newName)
|
||||
if isDirectory {
|
||||
sinkPath += "/"
|
||||
}
|
||||
output, err := c.client.GetObject(context.TODO(), &s3.GetObjectInput{
|
||||
Bucket: aws.String(c.bucket),
|
||||
Key: aws.String(sourcePath),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer output.Body.Close()
|
||||
outputSize := *output.ContentLength
|
||||
outputBuf := c.bufPool.Get(int(outputSize))
|
||||
defer c.bufPool.Put(outputBuf)
|
||||
if _, err := io.ReadFull(output.Body, outputBuf.Bytes()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = c.client.PutObject(context.TODO(), &s3.PutObjectInput{
|
||||
Bucket: aws.String(c.bucket),
|
||||
Key: aws.String(sinkPath),
|
||||
Body: bytes.NewReader(outputBuf.Bytes()),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = c.client.DeleteObject(context.TODO(), &s3.DeleteObjectInput{
|
||||
Bucket: aws.String(c.bucket),
|
||||
Key: aws.String(sourcePath),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return path.Join(newDir, newName), 0
|
||||
}
|
||||
|
||||
func (c *s3TestHarness) createFile(log *lib.Logger, owner string, spanSize uint32, name string, size uint64, dataSeed uint64) (string, msgs.EggsTime) {
|
||||
fullPath := path.Join(owner, name)
|
||||
rand := wyhash.New(dataSeed)
|
||||
bodyBuf := c.bufPool.Get(int(size))
|
||||
defer c.bufPool.Put(bodyBuf)
|
||||
body := bodyBuf.Bytes()
|
||||
rand.Read(body)
|
||||
_, err := c.client.PutObject(context.TODO(), &s3.PutObjectInput{
|
||||
Bucket: aws.String(c.bucket),
|
||||
Key: aws.String(fullPath),
|
||||
Body: bytes.NewReader(body),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return fullPath, 0
|
||||
}
|
||||
|
||||
func (c *s3TestHarness) checkFileData(log *lib.Logger, filePath string, size uint64, dataSeed uint64) {
|
||||
fullSize := int(size)
|
||||
expectedData := c.bufPool.Get(fullSize)
|
||||
defer c.bufPool.Put(expectedData)
|
||||
rand := wyhash.New(dataSeed)
|
||||
rand.Read(expectedData.Bytes())
|
||||
actualData := c.bufPool.Get(fullSize)
|
||||
defer c.bufPool.Put(actualData)
|
||||
|
||||
// First do some random reads, hopefully stimulating span caches in some interesting way
|
||||
if fullSize > 1 {
|
||||
for i := 0; i < 10; i++ {
|
||||
func() {
|
||||
offset := int(rand.Uint64() % uint64(fullSize-1))
|
||||
size := 1 + int(rand.Uint64()%uint64(fullSize-offset-1))
|
||||
log.Debug("reading from %v to %v in file of size %v", offset, offset+size, fullSize)
|
||||
expectedPartialData := expectedData.Bytes()[offset : offset+size]
|
||||
actualPartialData := actualData.Bytes()[offset : offset+size]
|
||||
output, err := c.client.GetObject(context.TODO(), &s3.GetObjectInput{
|
||||
Bucket: aws.String(c.bucket),
|
||||
Key: aws.String(filePath),
|
||||
Range: aws.String(fmt.Sprintf("bytes=%v-%v", offset, offset+size-1)),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if _, err := io.ReadFull(output.Body, actualPartialData); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
checkFileData(filePath, offset, offset+size, actualPartialData, expectedPartialData)
|
||||
}()
|
||||
}
|
||||
}
|
||||
// Then we check the whole thing
|
||||
output, err := c.client.GetObject(context.TODO(), &s3.GetObjectInput{
|
||||
Bucket: aws.String(c.bucket),
|
||||
Key: aws.String(filePath),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer output.Body.Close()
|
||||
if _, err := io.ReadFull(output.Body, actualData.Bytes()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
checkFileData(filePath, 0, fullSize, actualData.Bytes(), expectedData.Bytes())
|
||||
}
|
||||
|
||||
func (c *s3TestHarness) readDirectory(log *lib.Logger, dir string) (files []string, directories []string) {
|
||||
files = []string{}
|
||||
directories = []string{}
|
||||
|
||||
paginator := s3.NewListObjectsV2Paginator(c.client, &s3.ListObjectsV2Input{
|
||||
Bucket: aws.String(c.bucket),
|
||||
Prefix: aws.String(dir + "/"),
|
||||
})
|
||||
|
||||
for paginator.HasMorePages() {
|
||||
page, err := paginator.NextPage(context.TODO())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for i := range page.Contents {
|
||||
files = append(files, filepath.Base(*page.Contents[i].Key))
|
||||
}
|
||||
for i := range page.CommonPrefixes {
|
||||
directories = append(directories, filepath.Base(*page.CommonPrefixes[i].Prefix))
|
||||
}
|
||||
}
|
||||
|
||||
return files, directories
|
||||
}
|
||||
|
||||
func (c *s3TestHarness) removeFile(log *lib.Logger, dir string, name string) {
|
||||
_, err := c.client.DeleteObject(context.TODO(), &s3.DeleteObjectInput{
|
||||
Bucket: aws.String(c.bucket),
|
||||
Key: aws.String(path.Join(dir, name)),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *s3TestHarness) removeDirectory(log *lib.Logger, dir string, name string) {
|
||||
_, err := c.client.DeleteObject(context.TODO(), &s3.DeleteObjectInput{
|
||||
Bucket: aws.String(c.bucket),
|
||||
Key: aws.String(path.Join(dir, name) + "/"),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
var _ = (fsTestHarness[string])((*s3TestHarness)(nil))
|
||||
|
||||
type posixFsTestHarness struct {
|
||||
bufPool *lib.BufPool
|
||||
readWithMmap bool
|
||||
@@ -215,6 +404,7 @@ func (*posixFsTestHarness) createDirectory(log *lib.Logger, owner string, name s
|
||||
|
||||
func (*posixFsTestHarness) rename(
|
||||
log *lib.Logger,
|
||||
isDirectory bool,
|
||||
targetFullPath string,
|
||||
oldDir string,
|
||||
oldCreationTime msgs.EggsTime,
|
||||
@@ -489,7 +679,7 @@ func (state *fsTestState[Id]) makeDirFromTemp(log *lib.Logger, harness fsTestHar
|
||||
}
|
||||
state.incrementDirs(log, opts)
|
||||
id, tmpCreationTime = harness.createDirectory(log, tmpParentId, "tmp")
|
||||
newId, creationTime := harness.rename(log, id, tmpParentId, tmpCreationTime, "tmp", dir.id, strconv.Itoa(name))
|
||||
newId, creationTime := harness.rename(log, true, id, tmpParentId, tmpCreationTime, "tmp", dir.id, strconv.Itoa(name))
|
||||
dir.children.directories[name] = fsTestChild[fsTestDir[Id]]{
|
||||
body: *newFsTestDir(newId),
|
||||
creationTime: creationTime,
|
||||
@@ -565,7 +755,7 @@ func (state *fsTestState[Id]) makeFileFromTemp(log *lib.Logger, harness fsTestHa
|
||||
id, creationTime := harness.createFile(
|
||||
log, tmpParentId, uint32(opts.spanSize), "tmp", size, dataSeed,
|
||||
)
|
||||
newId, creationTime := harness.rename(log, id, tmpParentId, creationTime, "tmp", dir.id, strconv.Itoa(name))
|
||||
newId, creationTime := harness.rename(log, false, id, tmpParentId, creationTime, "tmp", dir.id, strconv.Itoa(name))
|
||||
dir.children.files[name] = fsTestChild[fsTestFile[Id]]{
|
||||
body: fsTestFile[Id]{
|
||||
id: newId,
|
||||
@@ -1016,12 +1206,64 @@ func fsTestInternal[Id comparable](
|
||||
log.Info("cleaned files in %s", time.Since(t0))
|
||||
}
|
||||
|
||||
// createS3ClientFromURL parses a path-style S3 URL and returns an S3 client.
|
||||
// The client is configured for anonymous access and uses the URL's host as the endpoint.
|
||||
func createS3ClientFromURL(s3URL string) (client *s3.Client, bucket string) {
|
||||
// Parse the provided URL string.
|
||||
parsedURL, err := url.Parse(s3URL)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// The first segment of the path is the bucket name.
|
||||
// We need to trim the leading slash.
|
||||
bucket = strings.Split(strings.TrimPrefix(parsedURL.Path, "/"), "/")[0]
|
||||
if bucket == "" {
|
||||
panic(fmt.Errorf("could not determine bucket from URL path"))
|
||||
}
|
||||
|
||||
// The endpoint is the scheme and host from the URL.
|
||||
endpoint := fmt.Sprintf("%s://%s", parsedURL.Scheme, parsedURL.Host)
|
||||
|
||||
// Load AWS configuration, specifying no credentials for anonymous access.
|
||||
cfg, err := s3config.LoadDefaultConfig(context.TODO(),
|
||||
s3config.WithCredentialsProvider(aws.AnonymousCredentials{}),
|
||||
s3config.WithRegion("us-east-1"), // A region is required, but not used for path-style requests.
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create the S3 client.
|
||||
s3Client := s3.NewFromConfig(cfg, func(o *s3.Options) {
|
||||
// Set the endpoint resolver to our custom endpoint.
|
||||
o.BaseEndpoint = aws.String(endpoint)
|
||||
// Force path-style addressing, which is crucial.
|
||||
o.UsePathStyle = true
|
||||
})
|
||||
|
||||
return s3Client, bucket
|
||||
}
|
||||
|
||||
type posixHarness struct {
|
||||
mountPoint string
|
||||
}
|
||||
type s3Harness struct {}
|
||||
type apiHarness struct {}
|
||||
|
||||
type WhichHarness interface {
|
||||
isHarness()
|
||||
}
|
||||
func (posixHarness) isHarness() {}
|
||||
func (s3Harness) isHarness() {}
|
||||
func (apiHarness) isHarness() {}
|
||||
|
||||
func fsTest(
|
||||
log *lib.Logger,
|
||||
shuckleAddress string,
|
||||
opts *fsTestOpts,
|
||||
counters *client.ClientCounters,
|
||||
realFs string, // if non-empty, will run the tests using this mountpoint
|
||||
harnessType WhichHarness,
|
||||
) {
|
||||
c, err := client.NewClient(log, nil, shuckleAddress, msgs.AddrsInfo{})
|
||||
if err != nil {
|
||||
@@ -1030,7 +1272,18 @@ func fsTest(
|
||||
c.SetFetchBlockServices()
|
||||
defer c.Close()
|
||||
c.SetCounters(counters)
|
||||
if realFs == "" {
|
||||
switch h := harnessType.(type) {
|
||||
case posixHarness:
|
||||
harness := &posixFsTestHarness{
|
||||
bufPool: lib.NewBufPool(),
|
||||
readWithMmap: opts.readWithMmap,
|
||||
}
|
||||
state := fsTestState[string]{
|
||||
totalDirs: 1, // root dir
|
||||
rootDir: *newFsTestDir(h.mountPoint),
|
||||
}
|
||||
fsTestInternal[string](log, c, &state, shuckleAddress, opts, counters, harness, h.mountPoint)
|
||||
case apiHarness:
|
||||
harness := &apiFsTestHarness{
|
||||
client: c,
|
||||
dirInfoCache: client.NewDirInfoCache(),
|
||||
@@ -1041,15 +1294,37 @@ func fsTest(
|
||||
rootDir: *newFsTestDir(msgs.ROOT_DIR_INODE_ID),
|
||||
}
|
||||
fsTestInternal[msgs.InodeId](log, c, &state, shuckleAddress, opts, counters, harness, msgs.ROOT_DIR_INODE_ID)
|
||||
} else {
|
||||
harness := &posixFsTestHarness{
|
||||
bufPool: lib.NewBufPool(),
|
||||
readWithMmap: opts.readWithMmap,
|
||||
case s3Harness:
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
port := listener.Addr().(*net.TCPAddr).Port
|
||||
bufPool := lib.NewBufPool()
|
||||
server := eggss3.NewS3Server(log, c, bufPool, client.NewDirInfoCache(), map[string]string{"bucket": "/"}, "")
|
||||
go http.Serve(listener, server)
|
||||
cfg, err := s3config.LoadDefaultConfig(context.TODO(),
|
||||
s3config.WithCredentialsProvider(aws.AnonymousCredentials{}),
|
||||
s3config.WithRegion("us-east-1"), // A region is required, but not used for path-style requests.
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s3Client := s3.NewFromConfig(cfg, func(o *s3.Options) {
|
||||
o.BaseEndpoint = aws.String(fmt.Sprintf("http://127.0.0.1:%v", port))
|
||||
o.UsePathStyle = true
|
||||
})
|
||||
harness := &s3TestHarness{
|
||||
bucket: "bucket",
|
||||
client: s3Client,
|
||||
bufPool: bufPool,
|
||||
}
|
||||
state := fsTestState[string]{
|
||||
totalDirs: 1, // root dir
|
||||
rootDir: *newFsTestDir(realFs),
|
||||
rootDir: *newFsTestDir("/"),
|
||||
}
|
||||
fsTestInternal[string](log, c, &state, shuckleAddress, opts, counters, harness, realFs)
|
||||
fsTestInternal[string](log, c, &state, shuckleAddress, opts, counters, harness, "/")
|
||||
default:
|
||||
panic(fmt.Errorf("bad harness %T", harnessType))
|
||||
}
|
||||
}
|
||||
|
||||
23
go/go.mod
23
go/go.mod
@@ -3,8 +3,29 @@ module xtx/eggsfs
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.4
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.16
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.80.2
|
||||
github.com/hanwen/go-fuse/v2 v2.2.0
|
||||
github.com/mattn/go-sqlite3 v1.14.16
|
||||
golang.org/x/sync v0.7.0
|
||||
golang.org/x/sync v0.11.0
|
||||
golang.org/x/sys v0.16.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.69 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.31 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.21 // indirect
|
||||
github.com/aws/smithy-go v1.22.2 // indirect
|
||||
)
|
||||
|
||||
40
go/go.sum
40
go/go.sum
@@ -1,3 +1,39 @@
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.4 h1:GySzjhVvx0ERP6eyfAbAuAXLtAda5TEy19E5q5W8I9E=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.4/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 h1:zAybnyUQXIZ5mok5Jqwlf58/TFE7uvd3IAsa1aF9cXs=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10/go.mod h1:qqvMj6gHLR/EXWZw4ZbqlPbQUyenf4h82UQUlKc+l14=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.16 h1:XkruGnXX1nEZ+Nyo9v84TzsX+nj86icbFAeust6uo8A=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.16/go.mod h1:uCW7PNjGwZ5cOGZ5jr8vCWrYkGIhPoTNV23Q/tpHKzg=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.69 h1:8B8ZQboRc3uaIKjshve/XlvJ570R7BKNy3gftSbS178=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.69/go.mod h1:gPME6I8grR1jCqBFEGthULiolzf/Sexq/Wy42ibKK9c=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.31 h1:oQWSGexYasNpYp4epLGZxxjsDo8BMBh6iNWkTXQvkwk=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.31/go.mod h1:nc332eGUU+djP3vrMI6blS0woaCfHTe3KiSQUVTMRq0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.35 h1:o1v1VFfPcDVlK3ll1L5xHsaQAFdNtZ5GXnNR7SwueC4=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.35/go.mod h1:rZUQNYMNG+8uZxz9FOerQJ+FceCiodXvixpeRtdESrU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.35 h1:R5b82ubO2NntENm3SAm0ADME+H630HomNJdgv+yZ3xw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.35/go.mod h1:FuA+nmgMRfkzVKYDNEqQadvEMxtxl9+RLT9ribCwEMs=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.35 h1:th/m+Q18CkajTw1iqx2cKkLCij/uz8NMwJFPK91p2ug=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.35/go.mod h1:dkJuf0a1Bc8HAA0Zm2MoTGm/WDC18Td9vSbrQ1+VqE8=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.3 h1:VHPZakq2L7w+RLzV54LmQavbvheFaR2u1NomJRSEfcU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.3/go.mod h1:DX1e/lkbsAt0MkY3NgLYuH4jQvRfw8MYxTe9feR7aXM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.16 h1:/ldKrPPXTC421bTNWrUIpq3CxwHwRI/kpc+jPUTJocM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.16/go.mod h1:5vkf/Ws0/wgIMJDQbjI4p2op86hNW6Hie5QtebrDgT8=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.16 h1:2HuI7vWKhFWsBhIr2Zq8KfFZT6xqaId2XXnXZjkbEuc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.16/go.mod h1:BrwWnsfbFtFeRjdx0iM1ymvlqDX1Oz68JsQaibX/wG8=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.80.2 h1:T6Wu+8E2LeTUqzqQ/Bh1EoFNj1u4jUyveMgmTlu9fDU=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.80.2/go.mod h1:chSY8zfqmS0OnhZoO/hpPx/BHfAIL80m77HwhRLYScY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.4 h1:EU58LP8ozQDVroOEyAfcq0cGc5R/FTZjVoYJ6tvby3w=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.4/go.mod h1:CrtOgCcysxMvrCoHnvNAD7PHWclmoFG78Q2xLK0KKcs=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.2 h1:XB4z0hbQtpmBnb1FQYvKaCM7UsS6Y/u8jVBwIUGeCTk=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.2/go.mod h1:hwRpqkRxnQ58J9blRDrB4IanlXCpcKmsC83EhG77upg=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.21 h1:nyLjs8sYJShFYj6aiyjCBI3EcLn1udWrQTjEF+SOXB0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.21/go.mod h1:EhdxtZ+g84MSGrSrHzZiUm9PYiZkrADNja15wtRJSJo=
|
||||
github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ=
|
||||
github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
||||
github.com/hanwen/go-fuse/v2 v2.2.0 h1:jo5QZYmBLNcl9ovypWaQ5yXMSSV+Ch68xoC3rtZvvBM=
|
||||
github.com/hanwen/go-fuse/v2 v2.2.0/go.mod h1:B1nGE/6RBFyBRC1RRnf23UpwCdyJ31eukw34oAKukAc=
|
||||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
|
||||
@@ -5,8 +41,8 @@ github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LE
|
||||
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
|
||||
893
go/s3/s3.go
Normal file
893
go/s3/s3.go
Normal file
@@ -0,0 +1,893 @@
|
||||
package s3
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"xtx/eggsfs/client"
|
||||
"xtx/eggsfs/lib"
|
||||
"xtx/eggsfs/msgs"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// S3Error represents an error response compliant with the S3 API.
|
||||
type S3Error struct {
|
||||
XMLName xml.Name `xml:"Error"`
|
||||
Code string `xml:"Code"`
|
||||
Message string `xml:"Message"`
|
||||
Resource string `xml:"Resource"`
|
||||
BucketName string `xml:"BucketName,omitempty"`
|
||||
StatusCode int `xml:"-"` // The HTTP status code to return.
|
||||
}
|
||||
|
||||
func (e *S3Error) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
// --- S3 XML Response Structures ---
|
||||
|
||||
type CommonPrefix struct {
|
||||
Prefix string `xml:"Prefix"`
|
||||
}
|
||||
type ListBucketResultV2 struct {
|
||||
XMLName xml.Name `xml:"ListBucketResult"`
|
||||
Name string `xml:"Name"`
|
||||
Prefix string `xml:"Prefix"`
|
||||
MaxKeys int `xml:"MaxKeys"`
|
||||
Delimiter string `xml:"Delimiter,omitempty"`
|
||||
Contents []Object `xml:"Contents"`
|
||||
CommonPrefixes []CommonPrefix `xml:"CommonPrefixes,omitempty"`
|
||||
IsTruncated bool `xml:"IsTruncated"`
|
||||
KeyCount int `xml:"KeyCount"`
|
||||
ContinuationToken string `xml:"ContinuationToken,omitempty"`
|
||||
NextContinuationToken string `xml:"NextContinuationToken,omitempty"`
|
||||
}
|
||||
type Object struct {
|
||||
Key string `xml:"Key"`
|
||||
LastModified time.Time `xml:"LastModified"`
|
||||
ETag string `xml:"ETag"`
|
||||
Size int64 `xml:"Size"`
|
||||
}
|
||||
type CreateMultipartUploadResult struct {
|
||||
XMLName xml.Name `xml:"InitiateMultipartUploadResult"`
|
||||
Bucket string `xml:"Bucket"`
|
||||
Key string `xml:"Key"`
|
||||
UploadID string `xml:"UploadId"`
|
||||
}
|
||||
type CompleteMultipartUploadResult struct {
|
||||
XMLName xml.Name `xml:"CompleteMultipartUploadResult"`
|
||||
Location string `xml:"Location"`
|
||||
Bucket string `xml:"Bucket"`
|
||||
Key string `xml:"Key"`
|
||||
ETag string `xml:"ETag"`
|
||||
}
|
||||
type DeleteResult struct {
|
||||
XMLName xml.Name `xml:"DeleteResult"`
|
||||
Deleted []DeletedObject `xml:"Deleted,omitempty"`
|
||||
Error []ErrorObject `xml:"Error,omitempty"`
|
||||
}
|
||||
type DeletedObject struct {
|
||||
Key string `xml:"Key"`
|
||||
}
|
||||
type ErrorObject struct {
|
||||
Key string `xml:"Key"`
|
||||
Code string `xml:"Code"`
|
||||
Message string `xml:"Message"`
|
||||
}
|
||||
|
||||
// --- S3 XML Request Structures ---
|
||||
type CompleteMultipartUpload struct {
|
||||
XMLName xml.Name `xml:"CompleteMultipartUpload"`
|
||||
Parts []UploadPart `xml:"Part"`
|
||||
}
|
||||
type UploadPart struct {
|
||||
PartNumber int `xml:"PartNumber"`
|
||||
ETag string `xml:"ETag"`
|
||||
}
|
||||
type Delete struct {
|
||||
XMLName xml.Name `xml:"Delete"`
|
||||
Objects []ObjectToDelete `xml:"Object"`
|
||||
Quiet bool `xml:"Quiet"`
|
||||
}
|
||||
type ObjectToDelete struct {
|
||||
Key string `xml:"Key"`
|
||||
}
|
||||
|
||||
type objectPath struct {
|
||||
segments []string
|
||||
isDirectory bool
|
||||
}
|
||||
|
||||
func (p *objectPath) String() string {
|
||||
s := "/" + strings.Join(p.segments, "/")
|
||||
if p.isDirectory && len(p.segments) > 0 {
|
||||
s += "/"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (p *objectPath) basename() string {
|
||||
if len(p.segments) == 0 {
|
||||
return ""
|
||||
}
|
||||
return p.segments[len(p.segments)-1]
|
||||
}
|
||||
|
||||
func (p *objectPath) dir() *objectPath {
|
||||
d := &objectPath{
|
||||
segments: []string{},
|
||||
isDirectory: true,
|
||||
}
|
||||
if len(p.segments) > 1 {
|
||||
d.segments = p.segments[:len(p.segments)-1]
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func parseObjectPath(str string) *objectPath {
|
||||
p := &objectPath{
|
||||
segments: []string{},
|
||||
isDirectory: len(str) > 0 && str[len(str)-1] == '/',
|
||||
}
|
||||
// Trim leading/trailing slashes for splitting
|
||||
for _, segment := range strings.Split(str, "/") {
|
||||
if len(segment) > 0 {
|
||||
p.segments = append(p.segments, segment)
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// --- Handler Implementation ---
|
||||
type S3Server struct {
|
||||
log *lib.Logger
|
||||
c *client.Client
|
||||
bufPool *lib.BufPool
|
||||
dirInfoCache *client.DirInfoCache
|
||||
bucketPaths map[string]string
|
||||
virtualHost string
|
||||
}
|
||||
|
||||
func NewS3Server(
|
||||
log *lib.Logger,
|
||||
client *client.Client,
|
||||
bufPool *lib.BufPool,
|
||||
dirInfoCache *client.DirInfoCache,
|
||||
buckets map[string]string, // mapping from bucket to paths
|
||||
virtualHost string, // if not present, path-style bucket resolution will be used
|
||||
) *S3Server {
|
||||
return &S3Server{
|
||||
log: log,
|
||||
c: client,
|
||||
bufPool: bufPool,
|
||||
dirInfoCache: dirInfoCache,
|
||||
bucketPaths: buckets,
|
||||
virtualHost: virtualHost,
|
||||
}
|
||||
}
|
||||
|
||||
// s3Handler defines the signature for all S3 operation handlers.
|
||||
type s3Handler func(ctx context.Context, w http.ResponseWriter, r *http.Request, bucket string, rootId msgs.InodeId, path *objectPath) error
|
||||
|
||||
var stacktraceLock sync.Mutex
|
||||
|
||||
// recoverPanics is a middleware that recovers from panics in a handler,
|
||||
// logs the stack trace, and returns an error.
|
||||
func (s *S3Server) recoverPanics(handler s3Handler) s3Handler {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, bucket string, rootId msgs.InodeId, path *objectPath) (err error) {
|
||||
defer func() {
|
||||
if rec := recover(); rec != nil {
|
||||
err = fmt.Errorf("internal server panic: %v", rec)
|
||||
s.log.RaiseAlert(fmt.Sprintf("caught stray error: %v", rec))
|
||||
stacktraceLock.Lock()
|
||||
fmt.Fprintf(os.Stderr, "PANIC %v. Stacktrace:\n", rec)
|
||||
for _, line := range strings.Split(string(debug.Stack()), "\n") {
|
||||
fmt.Fprintln(os.Stderr, line)
|
||||
}
|
||||
stacktraceLock.Unlock()
|
||||
}
|
||||
}()
|
||||
err = handler(ctx, w, r, bucket, rootId, path)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// FileEtag generates a consistent ETag for a given file ID.
|
||||
func FileEtag(id msgs.InodeId) string {
|
||||
return fmt.Sprintf(`"%x"`, uint64(id))
|
||||
}
|
||||
|
||||
// parseRange parses the HTTP Range header.
|
||||
func parseRange(rangeHeader string, totalSize int64) (start, length int64, err error) {
|
||||
if !strings.HasPrefix(rangeHeader, "bytes=") {
|
||||
return 0, 0, errors.New("invalid range header format")
|
||||
}
|
||||
rangeSpec := strings.TrimPrefix(rangeHeader, "bytes=")
|
||||
parts := strings.Split(rangeSpec, "-")
|
||||
if len(parts) != 2 {
|
||||
return 0, 0, errors.New("invalid range specification")
|
||||
}
|
||||
startStr, endStr := parts[0], parts[1]
|
||||
if startStr == "" && endStr == "" {
|
||||
return 0, 0, errors.New("invalid range: both start and end are empty")
|
||||
}
|
||||
if startStr != "" {
|
||||
start, err = strconv.ParseInt(startStr, 10, 64)
|
||||
if err != nil || start < 0 {
|
||||
return 0, 0, errors.New("invalid start range")
|
||||
}
|
||||
}
|
||||
var end int64
|
||||
if endStr != "" {
|
||||
end, err = strconv.ParseInt(endStr, 10, 64)
|
||||
if err != nil || end < 0 {
|
||||
return 0, 0, errors.New("invalid end range")
|
||||
}
|
||||
} else {
|
||||
end = totalSize - 1
|
||||
}
|
||||
if startStr == "" {
|
||||
// This is a suffix range, e.g., "bytes=-500"
|
||||
suffixLength, err := strconv.ParseInt(endStr, 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, errors.New("invalid suffix range")
|
||||
}
|
||||
start = totalSize - suffixLength
|
||||
length = suffixLength
|
||||
} else {
|
||||
length = end - start + 1
|
||||
}
|
||||
if start > end || start >= totalSize || length <= 0 {
|
||||
return 0, 0, errors.New("range not satisfiable")
|
||||
}
|
||||
return start, length, nil
|
||||
}
|
||||
|
||||
// extractBucketAndPath determines the bucket and object path from the request.
|
||||
// It supports both virtual-host and path-style addressing.
|
||||
func (s *S3Server) extractBucketAndPath(r *http.Request) (bucketName string, path *objectPath, err error) {
|
||||
fullPath := parseObjectPath(r.URL.Path)
|
||||
|
||||
// Virtual host-style routing
|
||||
if s.virtualHost != "" {
|
||||
host := r.Host
|
||||
suffix := "." + s.virtualHost
|
||||
if strings.HasSuffix(host, suffix) {
|
||||
bucketName = strings.TrimSuffix(host, suffix)
|
||||
path = fullPath
|
||||
return bucketName, path, nil
|
||||
}
|
||||
// If virtual host is configured, we only accept virtual-host style requests.
|
||||
return "", nil, &S3Error{
|
||||
Code: "InvalidRequest",
|
||||
Message: "Request does not comply with virtual host setup. When virtual host routing is configured, all requests must use virtual host-style addressing.",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
}
|
||||
}
|
||||
|
||||
// Path-style routing
|
||||
if len(fullPath.segments) == 0 {
|
||||
// For bucket/object operations, a bucket is always required in the path.
|
||||
// This handles the case of a request to the root '/' which might be for
|
||||
// service-level operations not implemented here.
|
||||
return "", nil, &S3Error{
|
||||
Code: "InvalidRequest",
|
||||
Message: "Request URI does not contain a bucket name.",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
}
|
||||
}
|
||||
|
||||
bucketName = fullPath.segments[0]
|
||||
path = &objectPath{
|
||||
segments: fullPath.segments[1:],
|
||||
isDirectory: fullPath.isDirectory,
|
||||
}
|
||||
return bucketName, path, nil
|
||||
}
|
||||
|
||||
// ServeHTTP is the main entry point for all S3 requests. It routes requests
|
||||
// to the appropriate handler and centralizes error handling.
|
||||
func (s *S3Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
var handler s3Handler
|
||||
var handlerErr error
|
||||
ctx := r.Context()
|
||||
|
||||
bucketName, path, err := s.extractBucketAndPath(r)
|
||||
if err != nil {
|
||||
s.log.Info("Failed to extract bucket and path: %v", err)
|
||||
var s3Err *S3Error
|
||||
if errors.As(err, &s3Err) {
|
||||
if s3Err.Resource == "" {
|
||||
s3Err.Resource = r.URL.Path
|
||||
}
|
||||
s.writeXML(w, s3Err.StatusCode, s3Err)
|
||||
} else {
|
||||
s.writeXML(w, http.StatusInternalServerError, &S3Error{Code: "InternalError", Message: err.Error(), Resource: r.URL.Path})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
s.log.Debug("Received request: Method=%q Host=%q Path=%q Query=%v -> Bucket=%q Key=%q", r.Method, r.Host, r.URL.Path, r.URL.Query(), bucketName, path.String())
|
||||
|
||||
// Look up the bucket's root path string.
|
||||
rootPath, ok := s.bucketPaths[bucketName]
|
||||
if !ok {
|
||||
s.writeXML(w, http.StatusNotFound, &S3Error{Code: "NoSuchBucket", Message: "The specified bucket does not exist", Resource: r.URL.Path, BucketName: bucketName, StatusCode: http.StatusNotFound})
|
||||
return
|
||||
}
|
||||
|
||||
// Resolve the path to an InodeId on every request.
|
||||
rootId, err := lookupPath(ctx, s.log, s.c, parseObjectPath(rootPath))
|
||||
if err != nil {
|
||||
s.log.RaiseAlert("Could not resolve root path %q for configured bucket %q: %v", rootPath, bucketName, err)
|
||||
s.writeXML(w, http.StatusInternalServerError, &S3Error{
|
||||
Code: "InternalError",
|
||||
Message: "The bucket's underlying storage is unavailable.",
|
||||
Resource: r.URL.Path,
|
||||
BucketName: bucketName,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
query := r.URL.Query()
|
||||
|
||||
// Route the request to the correct handler.
|
||||
switch {
|
||||
case query.Has("uploads"):
|
||||
handler = s.handleCreateMultipartUpload
|
||||
case query.Has("uploadId") && query.Has("partNumber"):
|
||||
handler = s.handleUploadPart
|
||||
case query.Has("uploadId"):
|
||||
handler = s.handleCompleteMultipartUpload
|
||||
case query.Has("attributes"):
|
||||
handler = s.handleGetObjectAttributes
|
||||
case query.Has("delete"):
|
||||
handler = s.handleDeleteObjects
|
||||
case query.Has("list-type") && query.Get("list-type") == "2":
|
||||
handler = s.handleListObjectsV2
|
||||
default:
|
||||
switch r.Method {
|
||||
case http.MethodGet, http.MethodHead:
|
||||
handler = s.handleGetObject
|
||||
case http.MethodPut:
|
||||
handler = s.handlePutObject
|
||||
case http.MethodDelete:
|
||||
handler = s.handleDeleteObject
|
||||
}
|
||||
}
|
||||
|
||||
if handler != nil {
|
||||
// Wrap the handler to recover from panics and call it.
|
||||
handlerErr = s.recoverPanics(handler)(ctx, w, r, bucketName, rootId, path)
|
||||
} else {
|
||||
handlerErr = &S3Error{Code: "MethodNotAllowed", Message: "The specified method is not allowed against this resource.", StatusCode: http.StatusMethodNotAllowed}
|
||||
}
|
||||
|
||||
// Centralized error handling.
|
||||
if handlerErr != nil {
|
||||
s.log.Debug("Request failed: %v", handlerErr)
|
||||
var s3Err *S3Error
|
||||
if errors.As(handlerErr, &s3Err) {
|
||||
if s3Err.Resource == "" {
|
||||
s3Err.Resource = r.URL.Path
|
||||
}
|
||||
s3Err.BucketName = bucketName
|
||||
s.writeXML(w, s3Err.StatusCode, s3Err)
|
||||
} else {
|
||||
// Generic internal error for any other unhandled error type.
|
||||
s.writeXML(w, http.StatusInternalServerError, &S3Error{
|
||||
Code: "InternalError",
|
||||
Message: handlerErr.Error(),
|
||||
Resource: r.URL.Path,
|
||||
BucketName: bucketName,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// writeXML marshals data to XML and writes it to the response.
|
||||
func (s *S3Server) writeXML(w http.ResponseWriter, statusCode int, data interface{}) {
|
||||
w.Header().Set("Content-Type", "application/xml; charset=utf-8")
|
||||
w.WriteHeader(statusCode)
|
||||
if err := xml.NewEncoder(w).Encode(data); err != nil {
|
||||
s.log.Info("Error writing XML response: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// lookupDir traverses a path to find the final directory's InodeId.
|
||||
func (s *S3Server) lookupDir(ctx context.Context, rootId msgs.InodeId, path *objectPath) (msgs.InodeId, error) {
|
||||
s.log.Debug("lookupDir=%q in root %d", path.String(), rootId)
|
||||
current := rootId
|
||||
|
||||
for _, segment := range path.segments {
|
||||
lookupResp := &msgs.LookupResp{}
|
||||
req := &msgs.LookupReq{DirId: current, Name: segment}
|
||||
if err := s.c.ShardRequest(s.log, current.Shard(), req, lookupResp); err != nil {
|
||||
if errors.Is(err, msgs.NAME_NOT_FOUND) {
|
||||
return 0, &S3Error{Code: "NoSuchKey", Message: "The specified key does not exist.", StatusCode: http.StatusNotFound}
|
||||
}
|
||||
return 0, fmt.Errorf("lookup failed for segment '%s': %w", segment, err)
|
||||
}
|
||||
if lookupResp.TargetId.Type() != msgs.DIRECTORY {
|
||||
return 0, &S3Error{Code: "InvalidRequest", Message: fmt.Sprintf("A component of the path is not a directory: %s", segment), StatusCode: http.StatusBadRequest}
|
||||
}
|
||||
current = lookupResp.TargetId
|
||||
}
|
||||
return current, nil
|
||||
}
|
||||
|
||||
func (s *S3Server) lookupDirEntry(ctx context.Context, rootId msgs.InodeId, path *objectPath) (dirId msgs.InodeId, lookupResp *msgs.LookupResp, err error) {
|
||||
if len(path.segments) == 0 {
|
||||
return msgs.NULL_INODE_ID, &msgs.LookupResp{TargetId: rootId}, nil
|
||||
}
|
||||
|
||||
dirId, err = s.lookupDir(ctx, rootId, path.dir())
|
||||
if err != nil {
|
||||
return 0, nil, err // Pass through S3Error from lookupDir
|
||||
}
|
||||
|
||||
lookupResp = &msgs.LookupResp{}
|
||||
req := &msgs.LookupReq{DirId: dirId, Name: path.basename()}
|
||||
if err := s.c.ShardRequest(s.log, dirId.Shard(), req, lookupResp); err != nil {
|
||||
if errors.Is(err, msgs.NAME_NOT_FOUND) {
|
||||
return 0, nil, &S3Error{Code: "NoSuchKey", Message: "The specified key does not exist.", StatusCode: http.StatusNotFound}
|
||||
}
|
||||
return 0, nil, fmt.Errorf("dir entry lookup for %q failed: %w", path.String(), err)
|
||||
}
|
||||
return dirId, lookupResp, nil
|
||||
}
|
||||
|
||||
func (s *S3Server) handleGetObject(ctx context.Context, w http.ResponseWriter, r *http.Request, bucket string, rootId msgs.InodeId, path *objectPath) error {
|
||||
s.log.Debug("GetObject: bucket=%s path=%s", bucket, path)
|
||||
_, dentry, err := s.lookupDirEntry(ctx, rootId, path)
|
||||
if err != nil {
|
||||
return err // Returns S3Error or internal error
|
||||
}
|
||||
|
||||
if dentry.TargetId.Type() == msgs.DIRECTORY && !path.isDirectory {
|
||||
return &S3Error{Code: "NoSuchKey", Message: "The specified key does not exist.", StatusCode: http.StatusNotFound}
|
||||
}
|
||||
|
||||
var lastModified msgs.EggsTime
|
||||
var size uint64
|
||||
var bodyReader io.ReadSeeker
|
||||
|
||||
if dentry.TargetId.Type() == msgs.DIRECTORY {
|
||||
statResp := &msgs.StatDirectoryResp{}
|
||||
if err := s.c.ShardRequest(s.log, dentry.TargetId.Shard(), &msgs.StatDirectoryReq{Id: dentry.TargetId}, statResp); err != nil {
|
||||
return fmt.Errorf("stat failed for directory %q: %w", path.String(), err)
|
||||
}
|
||||
lastModified = statResp.Mtime
|
||||
bodyReader = bytes.NewReader([]byte{})
|
||||
} else {
|
||||
statResp := &msgs.StatFileResp{}
|
||||
if err := s.c.ShardRequest(s.log, dentry.TargetId.Shard(), &msgs.StatFileReq{Id: dentry.TargetId}, statResp); err != nil {
|
||||
return fmt.Errorf("stat failed for file %q: %w", path.String(), err)
|
||||
}
|
||||
fileReader, err := s.c.ReadFile(s.log, s.bufPool, dentry.TargetId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read contents of file id=%v: %w", dentry.TargetId, err)
|
||||
}
|
||||
defer fileReader.Close()
|
||||
bodyReader = fileReader
|
||||
size = statResp.Size
|
||||
lastModified = statResp.Mtime
|
||||
}
|
||||
|
||||
rangeHeader := r.Header.Get("Range")
|
||||
w.Header().Set("ETag", FileEtag(dentry.TargetId))
|
||||
w.Header().Set("Last-Modified", lastModified.Time().Format(http.TimeFormat))
|
||||
w.Header().Set("Accept-Ranges", "bytes")
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
|
||||
if rangeHeader == "" {
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(int64(size), 10))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if r.Method != http.MethodHead {
|
||||
if _, err := io.Copy(w, bodyReader); err != nil {
|
||||
s.log.Info("GetObject: Error writing full response body for object %s: %v", path, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
start, length, err := parseRange(rangeHeader, int64(size))
|
||||
if err != nil {
|
||||
w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", size))
|
||||
return &S3Error{Code: "InvalidRange", Message: "The requested range is not satisfiable", StatusCode: http.StatusRequestedRangeNotSatisfiable}
|
||||
}
|
||||
if _, err := bodyReader.Seek(start, io.SeekStart); err != nil {
|
||||
return fmt.Errorf("failed to seek object: %w", err)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(length, 10))
|
||||
w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, start+length-1, size))
|
||||
w.WriteHeader(http.StatusPartialContent)
|
||||
if r.Method != http.MethodHead {
|
||||
if _, err := io.CopyN(w, bodyReader, length); err != nil {
|
||||
s.log.Info("GetObject: Error writing partial response body for object %s: %v", path, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *S3Server) handleGetObjectAttributes(ctx context.Context, w http.ResponseWriter, r *http.Request, bucket string, rootId msgs.InodeId, path *objectPath) error {
|
||||
if r.Method != http.MethodHead && r.Method != http.MethodGet {
|
||||
return &S3Error{Code: "MethodNotAllowed", Message: "This resource only supports GET or HEAD.", StatusCode: http.StatusMethodNotAllowed}
|
||||
}
|
||||
s.log.Debug("GetObjectAttributes: path=%s", path)
|
||||
|
||||
_, dentry, err := s.lookupDirEntry(ctx, rootId, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
inode := dentry.TargetId
|
||||
var size uint64
|
||||
var lastModified msgs.EggsTime
|
||||
|
||||
if inode.Type() == msgs.DIRECTORY {
|
||||
statResp := &msgs.StatDirectoryResp{}
|
||||
if err := s.c.ShardRequest(s.log, dentry.TargetId.Shard(), &msgs.StatDirectoryReq{Id: dentry.TargetId}, statResp); err != nil {
|
||||
return fmt.Errorf("stat failed for directory %q: %w", path.String(), err)
|
||||
}
|
||||
lastModified = statResp.Mtime
|
||||
} else {
|
||||
statResp := &msgs.StatFileResp{}
|
||||
if err := s.c.ShardRequest(s.log, dentry.TargetId.Shard(), &msgs.StatFileReq{Id: dentry.TargetId}, statResp); err != nil {
|
||||
return fmt.Errorf("stat failed for file %q: %w", path.String(), err)
|
||||
}
|
||||
size = statResp.Size
|
||||
lastModified = statResp.Mtime
|
||||
}
|
||||
|
||||
w.Header().Set("x-amz-object-attributes-etag", FileEtag(dentry.TargetId))
|
||||
w.Header().Set("x-amz-object-attributes-last-modified", lastModified.Time().UTC().Format(http.TimeFormat))
|
||||
w.Header().Set("x-amz-object-attributes-object-size", strconv.FormatInt(int64(size), 10))
|
||||
w.Header().Set("x-amz-storage-class", "STANDARD")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *S3Server) handleListObjectsV2(ctx context.Context, w http.ResponseWriter, r *http.Request, bucket string, rootId msgs.InodeId, path *objectPath) error {
|
||||
if r.Method != http.MethodGet {
|
||||
return &S3Error{Code: "MethodNotAllowed", Message: "This resource only supports GET.", StatusCode: http.StatusMethodNotAllowed}
|
||||
}
|
||||
|
||||
query := r.URL.Query()
|
||||
prefix := parseObjectPath(query.Get("prefix"))
|
||||
prefixStr := prefix.String()
|
||||
if !prefix.isDirectory {
|
||||
return &S3Error{Code: "InvalidArgument", Message: "Only prefixes terminating with / (directories) are allowed", StatusCode: http.StatusBadRequest}
|
||||
}
|
||||
delimiter := query.Get("delimiter")
|
||||
if delimiter == "" {
|
||||
delimiter = "/"
|
||||
}
|
||||
if delimiter != "/" {
|
||||
return &S3Error{Code: "InvalidArgument", Message: "Delimiter must be empty or '/'", StatusCode: http.StatusBadRequest}
|
||||
}
|
||||
maxKeys, _ := strconv.Atoi(query.Get("max-keys"))
|
||||
if maxKeys <= 0 {
|
||||
maxKeys = 1000
|
||||
}
|
||||
startHash, _ := strconv.ParseUint(query.Get("continuation-token"), 10, 64)
|
||||
|
||||
s.log.Debug("ListObjectsV2: bucket=%q prefix=%q", bucket, prefix.String())
|
||||
|
||||
dirId, err := s.lookupDir(ctx, rootId, prefix)
|
||||
if err != nil {
|
||||
// If the prefix itself doesn't exist, return an empty list.
|
||||
var s3Err *S3Error
|
||||
if errors.As(err, &s3Err) && s3Err.Code == "NoSuchKey" {
|
||||
response := ListBucketResultV2{
|
||||
Name: bucket,
|
||||
Prefix: prefix.String(),
|
||||
Delimiter: delimiter,
|
||||
MaxKeys: maxKeys,
|
||||
KeyCount: 0,
|
||||
}
|
||||
s.writeXML(w, http.StatusOK, response)
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
readDirResp := &msgs.ReadDirResp{}
|
||||
req := &msgs.ReadDirReq{DirId: dirId, StartHash: msgs.NameHash(startHash)}
|
||||
if err := s.c.ShardRequest(s.log, dirId.Shard(), req, readDirResp); err != nil {
|
||||
return fmt.Errorf("could not read directory %q: %w", prefix, err)
|
||||
}
|
||||
|
||||
response := ListBucketResultV2{
|
||||
Name: bucket,
|
||||
Prefix: prefix.String(),
|
||||
Delimiter: delimiter,
|
||||
MaxKeys: maxKeys,
|
||||
Contents: []Object{},
|
||||
CommonPrefixes: []CommonPrefix{},
|
||||
ContinuationToken: query.Get("continuation-token"),
|
||||
}
|
||||
|
||||
var filesToProcess []msgs.CurrentEdge
|
||||
for i := range readDirResp.Results {
|
||||
if len(response.Contents)+len(response.CommonPrefixes) >= maxKeys {
|
||||
response.IsTruncated = true
|
||||
response.NextContinuationToken = fmt.Sprintf("%d", uint64(readDirResp.Results[i].NameHash))
|
||||
break
|
||||
}
|
||||
entry := &readDirResp.Results[i]
|
||||
if entry.TargetId.Type() == msgs.DIRECTORY {
|
||||
response.CommonPrefixes = append(response.CommonPrefixes, CommonPrefix{Prefix: prefixStr + entry.Name + "/"})
|
||||
} else {
|
||||
filesToProcess = append(filesToProcess, *entry)
|
||||
}
|
||||
}
|
||||
|
||||
if len(filesToProcess) > 0 {
|
||||
g, _ := errgroup.WithContext(ctx)
|
||||
response.Contents = make([]Object, len(filesToProcess))
|
||||
for i, entry := range filesToProcess {
|
||||
i, entry := i, entry // capture loop variables
|
||||
g.Go(func() error {
|
||||
s.log.Debug("Spawning request for details of object %s", entry.Name)
|
||||
resp := &msgs.StatFileResp{}
|
||||
if err := s.c.ShardRequest(s.log, entry.TargetId.Shard(), &msgs.StatFileReq{Id: entry.TargetId}, resp); err != nil {
|
||||
return err
|
||||
}
|
||||
response.Contents[i] = Object{
|
||||
Key: prefixStr + entry.Name,
|
||||
ETag: FileEtag(entry.TargetId),
|
||||
Size: int64(resp.Size),
|
||||
LastModified: resp.Mtime.Time(),
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if err := g.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !response.IsTruncated && readDirResp.NextHash != 0 {
|
||||
isTruncated := len(response.Contents)+len(response.CommonPrefixes) < len(readDirResp.Results)
|
||||
if isTruncated || (readDirResp.NextHash != 0 && len(readDirResp.Results) > 0) {
|
||||
response.IsTruncated = true
|
||||
if response.NextContinuationToken == "" {
|
||||
response.NextContinuationToken = fmt.Sprintf("%d", uint64(readDirResp.NextHash))
|
||||
}
|
||||
}
|
||||
}
|
||||
response.KeyCount = len(response.Contents) + len(response.CommonPrefixes)
|
||||
s.writeXML(w, http.StatusOK, response)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *S3Server) handlePutObject(ctx context.Context, w http.ResponseWriter, r *http.Request, bucket string, rootId msgs.InodeId, path *objectPath) error {
|
||||
s.log.Debug("PutObject: bucket=%q path=%q", bucket, path.String())
|
||||
|
||||
if len(path.segments) == 0 {
|
||||
return &S3Error{Code: "MethodNotAllowed", Message: "PUT is not allowed on a bucket. To create a bucket, use the AWS CLI or other tools.", StatusCode: http.StatusMethodNotAllowed}
|
||||
}
|
||||
|
||||
ownerId := rootId
|
||||
var err error
|
||||
|
||||
// Create parent directories if they don't exist
|
||||
for _, dirName := range path.dir().segments {
|
||||
lookupResp := msgs.LookupResp{}
|
||||
err = s.c.ShardRequest(s.log, ownerId.Shard(), &msgs.LookupReq{DirId: ownerId, Name: dirName}, &lookupResp)
|
||||
if err != nil {
|
||||
if errors.Is(err, msgs.NAME_NOT_FOUND) {
|
||||
s.log.Debug("Directory %q in dir %d not found, creating it.", dirName, ownerId)
|
||||
resp := &msgs.MakeDirectoryResp{}
|
||||
if err = s.c.CDCRequest(s.log, &msgs.MakeDirectoryReq{OwnerId: ownerId, Name: dirName}, resp); err != nil {
|
||||
return fmt.Errorf("failed to construct directory %q: %w", dirName, err)
|
||||
}
|
||||
ownerId = resp.Id
|
||||
} else {
|
||||
return fmt.Errorf("failed to lookup directory %q: %w", dirName, err)
|
||||
}
|
||||
} else {
|
||||
if lookupResp.TargetId.Type() != msgs.DIRECTORY {
|
||||
return &S3Error{Code: "InvalidRequest", Message: fmt.Sprintf("A component of the path is not a directory: %q", dirName), StatusCode: http.StatusBadRequest}
|
||||
}
|
||||
ownerId = lookupResp.TargetId
|
||||
}
|
||||
}
|
||||
|
||||
var inode msgs.InodeId
|
||||
basename := path.basename()
|
||||
if path.isDirectory {
|
||||
resp := &msgs.MakeDirectoryResp{}
|
||||
if err := s.c.CDCRequest(s.log, &msgs.MakeDirectoryReq{OwnerId: ownerId, Name: basename}, resp); err != nil {
|
||||
return fmt.Errorf("failed to make directory: %w", err)
|
||||
} else {
|
||||
inode = resp.Id
|
||||
}
|
||||
} else {
|
||||
fileResp := msgs.ConstructFileResp{}
|
||||
if err := s.c.ShardRequest(s.log, ownerId.Shard(), &msgs.ConstructFileReq{Type: msgs.FILE}, &fileResp); err != nil {
|
||||
return fmt.Errorf("failed to construct file: %w", err)
|
||||
}
|
||||
fileId := fileResp.Id
|
||||
cookie := fileResp.Cookie
|
||||
if err := s.c.WriteFile(s.log, s.bufPool, s.dirInfoCache, ownerId, fileId, cookie, r.Body); err != nil {
|
||||
return fmt.Errorf("failed to write file data: %w", err)
|
||||
}
|
||||
linkReq := &msgs.LinkFileReq{FileId: fileId, Cookie: cookie, OwnerId: ownerId, Name: basename}
|
||||
if err := s.c.ShardRequest(s.log, ownerId.Shard(), linkReq, &msgs.LinkFileResp{}); err != nil {
|
||||
return fmt.Errorf("failed to link file %q: %w", path.String(), err)
|
||||
}
|
||||
inode = fileId
|
||||
}
|
||||
|
||||
w.Header().Set("ETag", FileEtag(inode))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *S3Server) handleCreateMultipartUpload(ctx context.Context, w http.ResponseWriter, r *http.Request, bucket string, rootId msgs.InodeId, path *objectPath) error {
|
||||
if r.Method != http.MethodPost {
|
||||
return &S3Error{Code: "MethodNotAllowed", Message: "This resource only supports POST.", StatusCode: http.StatusMethodNotAllowed}
|
||||
}
|
||||
return &S3Error{Code: "NotImplemented", Message: "Multipart upload is not implemented.", StatusCode: http.StatusNotImplemented}
|
||||
}
|
||||
|
||||
func (s *S3Server) handleUploadPart(ctx context.Context, w http.ResponseWriter, r *http.Request, bucket string, rootId msgs.InodeId, path *objectPath) error {
|
||||
if r.Method != http.MethodPut {
|
||||
return &S3Error{Code: "MethodNotAllowed", Message: "This resource only supports PUT.", StatusCode: http.StatusMethodNotAllowed}
|
||||
}
|
||||
return &S3Error{Code: "NotImplemented", Message: "Multipart upload is not implemented.", StatusCode: http.StatusNotImplemented}
|
||||
}
|
||||
|
||||
func (s *S3Server) handleCompleteMultipartUpload(ctx context.Context, w http.ResponseWriter, r *http.Request, bucket string, rootId msgs.InodeId, path *objectPath) error {
|
||||
if r.Method != http.MethodPost {
|
||||
return &S3Error{Code: "MethodNotAllowed", Message: "This resource only supports POST.", StatusCode: http.StatusMethodNotAllowed}
|
||||
}
|
||||
var payload CompleteMultipartUpload
|
||||
if err := xml.NewDecoder(r.Body).Decode(&payload); err != nil {
|
||||
s.log.Info("Could not decode XML for CompleteMultipartUpload: %v", err)
|
||||
return &S3Error{Code: "MalformedXML", Message: fmt.Sprintf("The XML you provided was not well-formed or did not validate against our published schema: %v", err), StatusCode: http.StatusBadRequest}
|
||||
}
|
||||
return &S3Error{Code: "NotImplemented", Message: "Multipart upload is not implemented.", StatusCode: http.StatusNotImplemented}
|
||||
}
|
||||
|
||||
// deleteObjectLogic contains the core logic for deleting a single object.
|
||||
func (s *S3Server) deleteObjectLogic(ctx context.Context, rootId msgs.InodeId, path *objectPath) error {
|
||||
if len(path.segments) == 0 {
|
||||
return &S3Error{Code: "InvalidRequest", Message: "Cannot delete bucket root with object deletion API", StatusCode: http.StatusBadRequest}
|
||||
}
|
||||
|
||||
dirId, dentry, err := s.lookupDirEntry(ctx, rootId, path)
|
||||
if err != nil {
|
||||
var s3Err *S3Error
|
||||
if errors.As(err, &s3Err) && s3Err.Code == "NoSuchKey" {
|
||||
s.log.Debug("deleteObjectLogic: Object %q not found, treating as success for deletion.", path.String())
|
||||
return nil // Success from S3 perspective
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if dentry.TargetId.Type() == msgs.DIRECTORY {
|
||||
req := &msgs.SoftUnlinkDirectoryReq{
|
||||
OwnerId: dirId,
|
||||
TargetId: dentry.TargetId,
|
||||
Name: path.basename(),
|
||||
CreationTime: dentry.CreationTime,
|
||||
}
|
||||
if err := s.c.CDCRequest(s.log, req, &msgs.SoftUnlinkDirectoryResp{}); err != nil {
|
||||
return fmt.Errorf("could not delete directory %q: %w", path.String(), err)
|
||||
}
|
||||
} else {
|
||||
req := &msgs.SoftUnlinkFileReq{
|
||||
OwnerId: dirId,
|
||||
FileId: dentry.TargetId,
|
||||
Name: path.basename(),
|
||||
CreationTime: dentry.CreationTime,
|
||||
}
|
||||
if err := s.c.ShardRequest(s.log, dirId.Shard(), req, &msgs.SoftUnlinkFileResp{}); err != nil {
|
||||
return fmt.Errorf("could not delete file %q: %w", path.String(), err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *S3Server) handleDeleteObject(ctx context.Context, w http.ResponseWriter, r *http.Request, bucket string, rootId msgs.InodeId, path *objectPath) error {
|
||||
s.log.Debug("DeleteObject: path=%q", path.String())
|
||||
if err := s.deleteObjectLogic(ctx, rootId, path); err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return nil
|
||||
}
|
||||
|
||||
// deleteResult holds the outcome of a single deletion operation.
|
||||
type deleteResult struct {
|
||||
Key string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (s *S3Server) handleDeleteObjects(ctx context.Context, w http.ResponseWriter, r *http.Request, bucket string, rootId msgs.InodeId, path *objectPath) error {
|
||||
s.log.Debug("DeleteObjects in bucket %q", bucket)
|
||||
|
||||
if r.Method != http.MethodPost {
|
||||
return &S3Error{Code: "MethodNotAllowed", Message: "This resource only supports POST.", StatusCode: http.StatusMethodNotAllowed}
|
||||
}
|
||||
if len(path.segments) != 0 {
|
||||
return &S3Error{Code: "InvalidRequest", Message: "DeleteObjects should be called on a bucket, not an object"}
|
||||
}
|
||||
var payload Delete
|
||||
if err := xml.NewDecoder(r.Body).Decode(&payload); err != nil {
|
||||
return &S3Error{Code: "MalformedXML", Message: fmt.Sprintf("The XML you provided was not well-formed or did not validate against our published schema: %v", err), StatusCode: http.StatusBadRequest}
|
||||
}
|
||||
|
||||
results := make([]deleteResult, len(payload.Objects))
|
||||
g, gCtx := errgroup.WithContext(ctx)
|
||||
|
||||
for i, obj := range payload.Objects {
|
||||
i, obj := i, obj // Capture loop variables to use in goroutine.
|
||||
g.Go(func() error {
|
||||
s.log.Debug("Batch deleting object: %q", obj.Key)
|
||||
err := s.deleteObjectLogic(gCtx, rootId, parseObjectPath(obj.Key))
|
||||
results[i] = deleteResult{Key: obj.Key, Err: err}
|
||||
// Return nil so that one failed deletion doesn't cancel others.
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
return err // Likely a context cancellation
|
||||
}
|
||||
|
||||
var deletedObjects []DeletedObject
|
||||
var errorObjects []ErrorObject
|
||||
for _, res := range results {
|
||||
if res.Err != nil {
|
||||
var s3Err *S3Error
|
||||
code := "InternalError"
|
||||
message := res.Err.Error()
|
||||
if errors.As(res.Err, &s3Err) {
|
||||
code = s3Err.Code
|
||||
message = s3Err.Message
|
||||
}
|
||||
errorObjects = append(errorObjects, ErrorObject{Key: res.Key, Code: code, Message: message})
|
||||
} else if !payload.Quiet {
|
||||
deletedObjects = append(deletedObjects, DeletedObject{Key: res.Key})
|
||||
}
|
||||
}
|
||||
|
||||
response := DeleteResult{
|
||||
Deleted: deletedObjects,
|
||||
Error: errorObjects,
|
||||
}
|
||||
|
||||
s.writeXML(w, http.StatusOK, response)
|
||||
return nil
|
||||
}
|
||||
|
||||
// lookupPath is a helper to resolve a full path from the filesystem root to an InodeId.
|
||||
func lookupPath(ctx context.Context, log *lib.Logger, c *client.Client, path *objectPath) (msgs.InodeId, error) {
|
||||
current := msgs.ROOT_DIR_INODE_ID
|
||||
for _, segment := range path.segments {
|
||||
lookupResp := &msgs.LookupResp{}
|
||||
req := &msgs.LookupReq{DirId: current, Name: segment}
|
||||
if err := c.ShardRequest(log, current.Shard(), req, lookupResp); err != nil {
|
||||
return 0, fmt.Errorf("lookup failed for segment '%s': %w", segment, err)
|
||||
}
|
||||
current = lookupResp.TargetId
|
||||
}
|
||||
return current, nil
|
||||
}
|
||||
202
go/vendor/github.com/aws/aws-sdk-go-v2/LICENSE.txt
generated
vendored
Normal file
202
go/vendor/github.com/aws/aws-sdk-go-v2/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
3
go/vendor/github.com/aws/aws-sdk-go-v2/NOTICE.txt
generated
vendored
Normal file
3
go/vendor/github.com/aws/aws-sdk-go-v2/NOTICE.txt
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
AWS SDK for Go
|
||||
Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
Copyright 2014-2015 Stripe, Inc.
|
||||
18
go/vendor/github.com/aws/aws-sdk-go-v2/aws/accountid_endpoint_mode.go
generated
vendored
Normal file
18
go/vendor/github.com/aws/aws-sdk-go-v2/aws/accountid_endpoint_mode.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package aws
|
||||
|
||||
// AccountIDEndpointMode controls how a resolved AWS account ID is handled for endpoint routing.
|
||||
type AccountIDEndpointMode string
|
||||
|
||||
const (
|
||||
// AccountIDEndpointModeUnset indicates the AWS account ID will not be used for endpoint routing
|
||||
AccountIDEndpointModeUnset AccountIDEndpointMode = ""
|
||||
|
||||
// AccountIDEndpointModePreferred indicates the AWS account ID will be used for endpoint routing if present
|
||||
AccountIDEndpointModePreferred = "preferred"
|
||||
|
||||
// AccountIDEndpointModeRequired indicates an error will be returned if the AWS account ID is not resolved from identity
|
||||
AccountIDEndpointModeRequired = "required"
|
||||
|
||||
// AccountIDEndpointModeDisabled indicates the AWS account ID will be ignored during endpoint routing
|
||||
AccountIDEndpointModeDisabled = "disabled"
|
||||
)
|
||||
92
go/vendor/github.com/aws/aws-sdk-go-v2/aws/arn/arn.go
generated
vendored
Normal file
92
go/vendor/github.com/aws/aws-sdk-go-v2/aws/arn/arn.go
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
// Package arn provides a parser for interacting with Amazon Resource Names.
|
||||
package arn
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
arnDelimiter = ":"
|
||||
arnSections = 6
|
||||
arnPrefix = "arn:"
|
||||
|
||||
// zero-indexed
|
||||
sectionPartition = 1
|
||||
sectionService = 2
|
||||
sectionRegion = 3
|
||||
sectionAccountID = 4
|
||||
sectionResource = 5
|
||||
|
||||
// errors
|
||||
invalidPrefix = "arn: invalid prefix"
|
||||
invalidSections = "arn: not enough sections"
|
||||
)
|
||||
|
||||
// ARN captures the individual fields of an Amazon Resource Name.
|
||||
// See http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html for more information.
|
||||
type ARN struct {
|
||||
// The partition that the resource is in. For standard AWS regions, the partition is "aws". If you have resources in
|
||||
// other partitions, the partition is "aws-partitionname". For example, the partition for resources in the China
|
||||
// (Beijing) region is "aws-cn".
|
||||
Partition string
|
||||
|
||||
// The service namespace that identifies the AWS product (for example, Amazon S3, IAM, or Amazon RDS). For a list of
|
||||
// namespaces, see
|
||||
// http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namespaces.
|
||||
Service string
|
||||
|
||||
// The region the resource resides in. Note that the ARNs for some resources do not require a region, so this
|
||||
// component might be omitted.
|
||||
Region string
|
||||
|
||||
// The ID of the AWS account that owns the resource, without the hyphens. For example, 123456789012. Note that the
|
||||
// ARNs for some resources don't require an account number, so this component might be omitted.
|
||||
AccountID string
|
||||
|
||||
// The content of this part of the ARN varies by service. It often includes an indicator of the type of resource —
|
||||
// for example, an IAM user or Amazon RDS database - followed by a slash (/) or a colon (:), followed by the
|
||||
// resource name itself. Some services allows paths for resource names, as described in
|
||||
// http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#arns-paths.
|
||||
Resource string
|
||||
}
|
||||
|
||||
// Parse parses an ARN into its constituent parts.
|
||||
//
|
||||
// Some example ARNs:
|
||||
// arn:aws:elasticbeanstalk:us-east-1:123456789012:environment/My App/MyEnvironment
|
||||
// arn:aws:iam::123456789012:user/David
|
||||
// arn:aws:rds:eu-west-1:123456789012:db:mysql-db
|
||||
// arn:aws:s3:::my_corporate_bucket/exampleobject.png
|
||||
func Parse(arn string) (ARN, error) {
|
||||
if !strings.HasPrefix(arn, arnPrefix) {
|
||||
return ARN{}, errors.New(invalidPrefix)
|
||||
}
|
||||
sections := strings.SplitN(arn, arnDelimiter, arnSections)
|
||||
if len(sections) != arnSections {
|
||||
return ARN{}, errors.New(invalidSections)
|
||||
}
|
||||
return ARN{
|
||||
Partition: sections[sectionPartition],
|
||||
Service: sections[sectionService],
|
||||
Region: sections[sectionRegion],
|
||||
AccountID: sections[sectionAccountID],
|
||||
Resource: sections[sectionResource],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// IsARN returns whether the given string is an arn
|
||||
// by looking for whether the string starts with arn:
|
||||
func IsARN(arn string) bool {
|
||||
return strings.HasPrefix(arn, arnPrefix) && strings.Count(arn, ":") >= arnSections-1
|
||||
}
|
||||
|
||||
// String returns the canonical representation of the ARN
|
||||
func (arn ARN) String() string {
|
||||
return arnPrefix +
|
||||
arn.Partition + arnDelimiter +
|
||||
arn.Service + arnDelimiter +
|
||||
arn.Region + arnDelimiter +
|
||||
arn.AccountID + arnDelimiter +
|
||||
arn.Resource
|
||||
}
|
||||
33
go/vendor/github.com/aws/aws-sdk-go-v2/aws/checksum.go
generated
vendored
Normal file
33
go/vendor/github.com/aws/aws-sdk-go-v2/aws/checksum.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package aws
|
||||
|
||||
// RequestChecksumCalculation controls request checksum calculation workflow
|
||||
type RequestChecksumCalculation int
|
||||
|
||||
const (
|
||||
// RequestChecksumCalculationUnset is the unset value for RequestChecksumCalculation
|
||||
RequestChecksumCalculationUnset RequestChecksumCalculation = iota
|
||||
|
||||
// RequestChecksumCalculationWhenSupported indicates request checksum will be calculated
|
||||
// if the operation supports input checksums
|
||||
RequestChecksumCalculationWhenSupported
|
||||
|
||||
// RequestChecksumCalculationWhenRequired indicates request checksum will be calculated
|
||||
// if required by the operation or if user elects to set a checksum algorithm in request
|
||||
RequestChecksumCalculationWhenRequired
|
||||
)
|
||||
|
||||
// ResponseChecksumValidation controls response checksum validation workflow
|
||||
type ResponseChecksumValidation int
|
||||
|
||||
const (
|
||||
// ResponseChecksumValidationUnset is the unset value for ResponseChecksumValidation
|
||||
ResponseChecksumValidationUnset ResponseChecksumValidation = iota
|
||||
|
||||
// ResponseChecksumValidationWhenSupported indicates response checksum will be validated
|
||||
// if the operation supports output checksums
|
||||
ResponseChecksumValidationWhenSupported
|
||||
|
||||
// ResponseChecksumValidationWhenRequired indicates response checksum will only
|
||||
// be validated if the operation requires output checksum validation
|
||||
ResponseChecksumValidationWhenRequired
|
||||
)
|
||||
238
go/vendor/github.com/aws/aws-sdk-go-v2/aws/config.go
generated
vendored
Normal file
238
go/vendor/github.com/aws/aws-sdk-go-v2/aws/config.go
generated
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
package aws
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
smithybearer "github.com/aws/smithy-go/auth/bearer"
|
||||
"github.com/aws/smithy-go/logging"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
)
|
||||
|
||||
// HTTPClient provides the interface to provide custom HTTPClients. Generally
|
||||
// *http.Client is sufficient for most use cases. The HTTPClient should not
|
||||
// follow 301 or 302 redirects.
|
||||
type HTTPClient interface {
|
||||
Do(*http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
// A Config provides service configuration for service clients.
|
||||
type Config struct {
|
||||
// The region to send requests to. This parameter is required and must
|
||||
// be configured globally or on a per-client basis unless otherwise
|
||||
// noted. A full list of regions is found in the "Regions and Endpoints"
|
||||
// document.
|
||||
//
|
||||
// See http://docs.aws.amazon.com/general/latest/gr/rande.html for
|
||||
// information on AWS regions.
|
||||
Region string
|
||||
|
||||
// The credentials object to use when signing requests.
|
||||
// Use the LoadDefaultConfig to load configuration from all the SDK's supported
|
||||
// sources, and resolve credentials using the SDK's default credential chain.
|
||||
Credentials CredentialsProvider
|
||||
|
||||
// The Bearer Authentication token provider to use for authenticating API
|
||||
// operation calls with a Bearer Authentication token. The API clients and
|
||||
// operation must support Bearer Authentication scheme in order for the
|
||||
// token provider to be used. API clients created with NewFromConfig will
|
||||
// automatically be configured with this option, if the API client support
|
||||
// Bearer Authentication.
|
||||
//
|
||||
// The SDK's config.LoadDefaultConfig can automatically populate this
|
||||
// option for external configuration options such as SSO session.
|
||||
// https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html
|
||||
BearerAuthTokenProvider smithybearer.TokenProvider
|
||||
|
||||
// The HTTP Client the SDK's API clients will use to invoke HTTP requests.
|
||||
// The SDK defaults to a BuildableClient allowing API clients to create
|
||||
// copies of the HTTP Client for service specific customizations.
|
||||
//
|
||||
// Use a (*http.Client) for custom behavior. Using a custom http.Client
|
||||
// will prevent the SDK from modifying the HTTP client.
|
||||
HTTPClient HTTPClient
|
||||
|
||||
// An endpoint resolver that can be used to provide or override an endpoint
|
||||
// for the given service and region.
|
||||
//
|
||||
// See the `aws.EndpointResolver` documentation for additional usage
|
||||
// information.
|
||||
//
|
||||
// Deprecated: See Config.EndpointResolverWithOptions
|
||||
EndpointResolver EndpointResolver
|
||||
|
||||
// An endpoint resolver that can be used to provide or override an endpoint
|
||||
// for the given service and region.
|
||||
//
|
||||
// When EndpointResolverWithOptions is specified, it will be used by a
|
||||
// service client rather than using EndpointResolver if also specified.
|
||||
//
|
||||
// See the `aws.EndpointResolverWithOptions` documentation for additional
|
||||
// usage information.
|
||||
//
|
||||
// Deprecated: with the release of endpoint resolution v2 in API clients,
|
||||
// EndpointResolver and EndpointResolverWithOptions are deprecated.
|
||||
// Providing a value for this field will likely prevent you from using
|
||||
// newer endpoint-related service features. See API client options
|
||||
// EndpointResolverV2 and BaseEndpoint.
|
||||
EndpointResolverWithOptions EndpointResolverWithOptions
|
||||
|
||||
// RetryMaxAttempts specifies the maximum number attempts an API client
|
||||
// will call an operation that fails with a retryable error.
|
||||
//
|
||||
// API Clients will only use this value to construct a retryer if the
|
||||
// Config.Retryer member is not nil. This value will be ignored if
|
||||
// Retryer is not nil.
|
||||
RetryMaxAttempts int
|
||||
|
||||
// RetryMode specifies the retry model the API client will be created with.
|
||||
//
|
||||
// API Clients will only use this value to construct a retryer if the
|
||||
// Config.Retryer member is not nil. This value will be ignored if
|
||||
// Retryer is not nil.
|
||||
RetryMode RetryMode
|
||||
|
||||
// Retryer is a function that provides a Retryer implementation. A Retryer
|
||||
// guides how HTTP requests should be retried in case of recoverable
|
||||
// failures. When nil the API client will use a default retryer.
|
||||
//
|
||||
// In general, the provider function should return a new instance of a
|
||||
// Retryer if you are attempting to provide a consistent Retryer
|
||||
// configuration across all clients. This will ensure that each client will
|
||||
// be provided a new instance of the Retryer implementation, and will avoid
|
||||
// issues such as sharing the same retry token bucket across services.
|
||||
//
|
||||
// If not nil, RetryMaxAttempts, and RetryMode will be ignored by API
|
||||
// clients.
|
||||
Retryer func() Retryer
|
||||
|
||||
// ConfigSources are the sources that were used to construct the Config.
|
||||
// Allows for additional configuration to be loaded by clients.
|
||||
ConfigSources []interface{}
|
||||
|
||||
// APIOptions provides the set of middleware mutations modify how the API
|
||||
// client requests will be handled. This is useful for adding additional
|
||||
// tracing data to a request, or changing behavior of the SDK's client.
|
||||
APIOptions []func(*middleware.Stack) error
|
||||
|
||||
// The logger writer interface to write logging messages to. Defaults to
|
||||
// standard error.
|
||||
Logger logging.Logger
|
||||
|
||||
// Configures the events that will be sent to the configured logger. This
|
||||
// can be used to configure the logging of signing, retries, request, and
|
||||
// responses of the SDK clients.
|
||||
//
|
||||
// See the ClientLogMode type documentation for the complete set of logging
|
||||
// modes and available configuration.
|
||||
ClientLogMode ClientLogMode
|
||||
|
||||
// The configured DefaultsMode. If not specified, service clients will
|
||||
// default to legacy.
|
||||
//
|
||||
// Supported modes are: auto, cross-region, in-region, legacy, mobile,
|
||||
// standard
|
||||
DefaultsMode DefaultsMode
|
||||
|
||||
// The RuntimeEnvironment configuration, only populated if the DefaultsMode
|
||||
// is set to DefaultsModeAuto and is initialized by
|
||||
// `config.LoadDefaultConfig`. You should not populate this structure
|
||||
// programmatically, or rely on the values here within your applications.
|
||||
RuntimeEnvironment RuntimeEnvironment
|
||||
|
||||
// AppId is an optional application specific identifier that can be set.
|
||||
// When set it will be appended to the User-Agent header of every request
|
||||
// in the form of App/{AppId}. This variable is sourced from environment
|
||||
// variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.
|
||||
// See https://docs.aws.amazon.com/sdkref/latest/guide/settings-reference.html for
|
||||
// more information on environment variables and shared config settings.
|
||||
AppID string
|
||||
|
||||
// BaseEndpoint is an intermediary transfer location to a service specific
|
||||
// BaseEndpoint on a service's Options.
|
||||
BaseEndpoint *string
|
||||
|
||||
// DisableRequestCompression toggles if an operation request could be
|
||||
// compressed or not. Will be set to false by default. This variable is sourced from
|
||||
// environment variable AWS_DISABLE_REQUEST_COMPRESSION or the shared config profile attribute
|
||||
// disable_request_compression
|
||||
DisableRequestCompression bool
|
||||
|
||||
// RequestMinCompressSizeBytes sets the inclusive min bytes of a request body that could be
|
||||
// compressed. Will be set to 10240 by default and must be within 0 and 10485760 bytes inclusively.
|
||||
// This variable is sourced from environment variable AWS_REQUEST_MIN_COMPRESSION_SIZE_BYTES or
|
||||
// the shared config profile attribute request_min_compression_size_bytes
|
||||
RequestMinCompressSizeBytes int64
|
||||
|
||||
// Controls how a resolved AWS account ID is handled for endpoint routing.
|
||||
AccountIDEndpointMode AccountIDEndpointMode
|
||||
|
||||
// RequestChecksumCalculation determines when request checksum calculation is performed.
|
||||
//
|
||||
// There are two possible values for this setting:
|
||||
//
|
||||
// 1. RequestChecksumCalculationWhenSupported (default): The checksum is always calculated
|
||||
// if the operation supports it, regardless of whether the user sets an algorithm in the request.
|
||||
//
|
||||
// 2. RequestChecksumCalculationWhenRequired: The checksum is only calculated if the user
|
||||
// explicitly sets a checksum algorithm in the request.
|
||||
//
|
||||
// This setting is sourced from the environment variable AWS_REQUEST_CHECKSUM_CALCULATION
|
||||
// or the shared config profile attribute "request_checksum_calculation".
|
||||
RequestChecksumCalculation RequestChecksumCalculation
|
||||
|
||||
// ResponseChecksumValidation determines when response checksum validation is performed
|
||||
//
|
||||
// There are two possible values for this setting:
|
||||
//
|
||||
// 1. ResponseChecksumValidationWhenSupported (default): The checksum is always validated
|
||||
// if the operation supports it, regardless of whether the user sets the validation mode to ENABLED in request.
|
||||
//
|
||||
// 2. ResponseChecksumValidationWhenRequired: The checksum is only validated if the user
|
||||
// explicitly sets the validation mode to ENABLED in the request
|
||||
// This variable is sourced from environment variable AWS_RESPONSE_CHECKSUM_VALIDATION or
|
||||
// the shared config profile attribute "response_checksum_validation".
|
||||
ResponseChecksumValidation ResponseChecksumValidation
|
||||
}
|
||||
|
||||
// NewConfig returns a new Config pointer that can be chained with builder
|
||||
// methods to set multiple configuration values inline without using pointers.
|
||||
func NewConfig() *Config {
|
||||
return &Config{}
|
||||
}
|
||||
|
||||
// Copy will return a shallow copy of the Config object.
|
||||
func (c Config) Copy() Config {
|
||||
cp := c
|
||||
return cp
|
||||
}
|
||||
|
||||
// EndpointDiscoveryEnableState indicates if endpoint discovery is
|
||||
// enabled, disabled, auto or unset state.
|
||||
//
|
||||
// Default behavior (Auto or Unset) indicates operations that require endpoint
|
||||
// discovery will use Endpoint Discovery by default. Operations that
|
||||
// optionally use Endpoint Discovery will not use Endpoint Discovery
|
||||
// unless EndpointDiscovery is explicitly enabled.
|
||||
type EndpointDiscoveryEnableState uint
|
||||
|
||||
// Enumeration values for EndpointDiscoveryEnableState
|
||||
const (
|
||||
// EndpointDiscoveryUnset represents EndpointDiscoveryEnableState is unset.
|
||||
// Users do not need to use this value explicitly. The behavior for unset
|
||||
// is the same as for EndpointDiscoveryAuto.
|
||||
EndpointDiscoveryUnset EndpointDiscoveryEnableState = iota
|
||||
|
||||
// EndpointDiscoveryAuto represents an AUTO state that allows endpoint
|
||||
// discovery only when required by the api. This is the default
|
||||
// configuration resolved by the client if endpoint discovery is neither
|
||||
// enabled or disabled.
|
||||
EndpointDiscoveryAuto // default state
|
||||
|
||||
// EndpointDiscoveryDisabled indicates client MUST not perform endpoint
|
||||
// discovery even when required.
|
||||
EndpointDiscoveryDisabled
|
||||
|
||||
// EndpointDiscoveryEnabled indicates client MUST always perform endpoint
|
||||
// discovery if supported for the operation.
|
||||
EndpointDiscoveryEnabled
|
||||
)
|
||||
22
go/vendor/github.com/aws/aws-sdk-go-v2/aws/context.go
generated
vendored
Normal file
22
go/vendor/github.com/aws/aws-sdk-go-v2/aws/context.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package aws
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type suppressedContext struct {
|
||||
context.Context
|
||||
}
|
||||
|
||||
func (s *suppressedContext) Deadline() (deadline time.Time, ok bool) {
|
||||
return time.Time{}, false
|
||||
}
|
||||
|
||||
func (s *suppressedContext) Done() <-chan struct{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *suppressedContext) Err() error {
|
||||
return nil
|
||||
}
|
||||
235
go/vendor/github.com/aws/aws-sdk-go-v2/aws/credential_cache.go
generated
vendored
Normal file
235
go/vendor/github.com/aws/aws-sdk-go-v2/aws/credential_cache.go
generated
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
package aws
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
sdkrand "github.com/aws/aws-sdk-go-v2/internal/rand"
|
||||
"github.com/aws/aws-sdk-go-v2/internal/sync/singleflight"
|
||||
)
|
||||
|
||||
// CredentialsCacheOptions are the options
|
||||
type CredentialsCacheOptions struct {
|
||||
|
||||
// ExpiryWindow will allow the credentials to trigger refreshing prior to
|
||||
// the credentials actually expiring. This is beneficial so race conditions
|
||||
// with expiring credentials do not cause request to fail unexpectedly
|
||||
// due to ExpiredTokenException exceptions.
|
||||
//
|
||||
// An ExpiryWindow of 10s would cause calls to IsExpired() to return true
|
||||
// 10 seconds before the credentials are actually expired. This can cause an
|
||||
// increased number of requests to refresh the credentials to occur.
|
||||
//
|
||||
// If ExpiryWindow is 0 or less it will be ignored.
|
||||
ExpiryWindow time.Duration
|
||||
|
||||
// ExpiryWindowJitterFrac provides a mechanism for randomizing the
|
||||
// expiration of credentials within the configured ExpiryWindow by a random
|
||||
// percentage. Valid values are between 0.0 and 1.0.
|
||||
//
|
||||
// As an example if ExpiryWindow is 60 seconds and ExpiryWindowJitterFrac
|
||||
// is 0.5 then credentials will be set to expire between 30 to 60 seconds
|
||||
// prior to their actual expiration time.
|
||||
//
|
||||
// If ExpiryWindow is 0 or less then ExpiryWindowJitterFrac is ignored.
|
||||
// If ExpiryWindowJitterFrac is 0 then no randomization will be applied to the window.
|
||||
// If ExpiryWindowJitterFrac < 0 the value will be treated as 0.
|
||||
// If ExpiryWindowJitterFrac > 1 the value will be treated as 1.
|
||||
ExpiryWindowJitterFrac float64
|
||||
}
|
||||
|
||||
// CredentialsCache provides caching and concurrency safe credentials retrieval
|
||||
// via the provider's retrieve method.
|
||||
//
|
||||
// CredentialsCache will look for optional interfaces on the Provider to adjust
|
||||
// how the credential cache handles credentials caching.
|
||||
//
|
||||
// - HandleFailRefreshCredentialsCacheStrategy - Allows provider to handle
|
||||
// credential refresh failures. This could return an updated Credentials
|
||||
// value, or attempt another means of retrieving credentials.
|
||||
//
|
||||
// - AdjustExpiresByCredentialsCacheStrategy - Allows provider to adjust how
|
||||
// credentials Expires is modified. This could modify how the Credentials
|
||||
// Expires is adjusted based on the CredentialsCache ExpiryWindow option.
|
||||
// Such as providing a floor not to reduce the Expires below.
|
||||
type CredentialsCache struct {
|
||||
provider CredentialsProvider
|
||||
|
||||
options CredentialsCacheOptions
|
||||
creds atomic.Value
|
||||
sf singleflight.Group
|
||||
}
|
||||
|
||||
// NewCredentialsCache returns a CredentialsCache that wraps provider. Provider
|
||||
// is expected to not be nil. A variadic list of one or more functions can be
|
||||
// provided to modify the CredentialsCache configuration. This allows for
|
||||
// configuration of credential expiry window and jitter.
|
||||
func NewCredentialsCache(provider CredentialsProvider, optFns ...func(options *CredentialsCacheOptions)) *CredentialsCache {
|
||||
options := CredentialsCacheOptions{}
|
||||
|
||||
for _, fn := range optFns {
|
||||
fn(&options)
|
||||
}
|
||||
|
||||
if options.ExpiryWindow < 0 {
|
||||
options.ExpiryWindow = 0
|
||||
}
|
||||
|
||||
if options.ExpiryWindowJitterFrac < 0 {
|
||||
options.ExpiryWindowJitterFrac = 0
|
||||
} else if options.ExpiryWindowJitterFrac > 1 {
|
||||
options.ExpiryWindowJitterFrac = 1
|
||||
}
|
||||
|
||||
return &CredentialsCache{
|
||||
provider: provider,
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve returns the credentials. If the credentials have already been
|
||||
// retrieved, and not expired the cached credentials will be returned. If the
|
||||
// credentials have not been retrieved yet, or expired the provider's Retrieve
|
||||
// method will be called.
|
||||
//
|
||||
// Returns and error if the provider's retrieve method returns an error.
|
||||
func (p *CredentialsCache) Retrieve(ctx context.Context) (Credentials, error) {
|
||||
if creds, ok := p.getCreds(); ok && !creds.Expired() {
|
||||
return creds, nil
|
||||
}
|
||||
|
||||
resCh := p.sf.DoChan("", func() (interface{}, error) {
|
||||
return p.singleRetrieve(&suppressedContext{ctx})
|
||||
})
|
||||
select {
|
||||
case res := <-resCh:
|
||||
return res.Val.(Credentials), res.Err
|
||||
case <-ctx.Done():
|
||||
return Credentials{}, &RequestCanceledError{Err: ctx.Err()}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *CredentialsCache) singleRetrieve(ctx context.Context) (interface{}, error) {
|
||||
currCreds, ok := p.getCreds()
|
||||
if ok && !currCreds.Expired() {
|
||||
return currCreds, nil
|
||||
}
|
||||
|
||||
newCreds, err := p.provider.Retrieve(ctx)
|
||||
if err != nil {
|
||||
handleFailToRefresh := defaultHandleFailToRefresh
|
||||
if cs, ok := p.provider.(HandleFailRefreshCredentialsCacheStrategy); ok {
|
||||
handleFailToRefresh = cs.HandleFailToRefresh
|
||||
}
|
||||
newCreds, err = handleFailToRefresh(ctx, currCreds, err)
|
||||
if err != nil {
|
||||
return Credentials{}, fmt.Errorf("failed to refresh cached credentials, %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if newCreds.CanExpire && p.options.ExpiryWindow > 0 {
|
||||
adjustExpiresBy := defaultAdjustExpiresBy
|
||||
if cs, ok := p.provider.(AdjustExpiresByCredentialsCacheStrategy); ok {
|
||||
adjustExpiresBy = cs.AdjustExpiresBy
|
||||
}
|
||||
|
||||
randFloat64, err := sdkrand.CryptoRandFloat64()
|
||||
if err != nil {
|
||||
return Credentials{}, fmt.Errorf("failed to get random provider, %w", err)
|
||||
}
|
||||
|
||||
var jitter time.Duration
|
||||
if p.options.ExpiryWindowJitterFrac > 0 {
|
||||
jitter = time.Duration(randFloat64 *
|
||||
p.options.ExpiryWindowJitterFrac * float64(p.options.ExpiryWindow))
|
||||
}
|
||||
|
||||
newCreds, err = adjustExpiresBy(newCreds, -(p.options.ExpiryWindow - jitter))
|
||||
if err != nil {
|
||||
return Credentials{}, fmt.Errorf("failed to adjust credentials expires, %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
p.creds.Store(&newCreds)
|
||||
return newCreds, nil
|
||||
}
|
||||
|
||||
// getCreds returns the currently stored credentials and true. Returning false
|
||||
// if no credentials were stored.
|
||||
func (p *CredentialsCache) getCreds() (Credentials, bool) {
|
||||
v := p.creds.Load()
|
||||
if v == nil {
|
||||
return Credentials{}, false
|
||||
}
|
||||
|
||||
c := v.(*Credentials)
|
||||
if c == nil || !c.HasKeys() {
|
||||
return Credentials{}, false
|
||||
}
|
||||
|
||||
return *c, true
|
||||
}
|
||||
|
||||
// ProviderSources returns a list of where the underlying credential provider
|
||||
// has been sourced, if available. Returns empty if the provider doesn't implement
|
||||
// the interface
|
||||
func (p *CredentialsCache) ProviderSources() []CredentialSource {
|
||||
asSource, ok := p.provider.(CredentialProviderSource)
|
||||
if !ok {
|
||||
return []CredentialSource{}
|
||||
}
|
||||
return asSource.ProviderSources()
|
||||
}
|
||||
|
||||
// Invalidate will invalidate the cached credentials. The next call to Retrieve
|
||||
// will cause the provider's Retrieve method to be called.
|
||||
func (p *CredentialsCache) Invalidate() {
|
||||
p.creds.Store((*Credentials)(nil))
|
||||
}
|
||||
|
||||
// IsCredentialsProvider returns whether credential provider wrapped by CredentialsCache
|
||||
// matches the target provider type.
|
||||
func (p *CredentialsCache) IsCredentialsProvider(target CredentialsProvider) bool {
|
||||
return IsCredentialsProvider(p.provider, target)
|
||||
}
|
||||
|
||||
// HandleFailRefreshCredentialsCacheStrategy is an interface for
|
||||
// CredentialsCache to allow CredentialsProvider how failed to refresh
|
||||
// credentials is handled.
|
||||
type HandleFailRefreshCredentialsCacheStrategy interface {
|
||||
// Given the previously cached Credentials, if any, and refresh error, may
|
||||
// returns new or modified set of Credentials, or error.
|
||||
//
|
||||
// Credential caches may use default implementation if nil.
|
||||
HandleFailToRefresh(context.Context, Credentials, error) (Credentials, error)
|
||||
}
|
||||
|
||||
// defaultHandleFailToRefresh returns the passed in error.
|
||||
func defaultHandleFailToRefresh(ctx context.Context, _ Credentials, err error) (Credentials, error) {
|
||||
return Credentials{}, err
|
||||
}
|
||||
|
||||
// AdjustExpiresByCredentialsCacheStrategy is an interface for CredentialCache
|
||||
// to allow CredentialsProvider to intercept adjustments to Credentials expiry
|
||||
// based on expectations and use cases of CredentialsProvider.
|
||||
//
|
||||
// Credential caches may use default implementation if nil.
|
||||
type AdjustExpiresByCredentialsCacheStrategy interface {
|
||||
// Given a Credentials as input, applying any mutations and
|
||||
// returning the potentially updated Credentials, or error.
|
||||
AdjustExpiresBy(Credentials, time.Duration) (Credentials, error)
|
||||
}
|
||||
|
||||
// defaultAdjustExpiresBy adds the duration to the passed in credentials Expires,
|
||||
// and returns the updated credentials value. If Credentials value's CanExpire
|
||||
// is false, the passed in credentials are returned unchanged.
|
||||
func defaultAdjustExpiresBy(creds Credentials, dur time.Duration) (Credentials, error) {
|
||||
if !creds.CanExpire {
|
||||
return creds, nil
|
||||
}
|
||||
|
||||
creds.Expires = creds.Expires.Add(dur)
|
||||
return creds, nil
|
||||
}
|
||||
230
go/vendor/github.com/aws/aws-sdk-go-v2/aws/credentials.go
generated
vendored
Normal file
230
go/vendor/github.com/aws/aws-sdk-go-v2/aws/credentials.go
generated
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
package aws
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
||||
)
|
||||
|
||||
// AnonymousCredentials provides a sentinel CredentialsProvider that should be
|
||||
// used to instruct the SDK's signing middleware to not sign the request.
|
||||
//
|
||||
// Using `nil` credentials when configuring an API client will achieve the same
|
||||
// result. The AnonymousCredentials type allows you to configure the SDK's
|
||||
// external config loading to not attempt to source credentials from the shared
|
||||
// config or environment.
|
||||
//
|
||||
// For example you can use this CredentialsProvider with an API client's
|
||||
// Options to instruct the client not to sign a request for accessing public
|
||||
// S3 bucket objects.
|
||||
//
|
||||
// The following example demonstrates using the AnonymousCredentials to prevent
|
||||
// SDK's external config loading attempt to resolve credentials.
|
||||
//
|
||||
// cfg, err := config.LoadDefaultConfig(context.TODO(),
|
||||
// config.WithCredentialsProvider(aws.AnonymousCredentials{}),
|
||||
// )
|
||||
// if err != nil {
|
||||
// log.Fatalf("failed to load config, %v", err)
|
||||
// }
|
||||
//
|
||||
// client := s3.NewFromConfig(cfg)
|
||||
//
|
||||
// Alternatively you can leave the API client Option's `Credential` member to
|
||||
// nil. If using the `NewFromConfig` constructor you'll need to explicitly set
|
||||
// the `Credentials` member to nil, if the external config resolved a
|
||||
// credential provider.
|
||||
//
|
||||
// client := s3.New(s3.Options{
|
||||
// // Credentials defaults to a nil value.
|
||||
// })
|
||||
//
|
||||
// This can also be configured for specific operations calls too.
|
||||
//
|
||||
// cfg, err := config.LoadDefaultConfig(context.TODO())
|
||||
// if err != nil {
|
||||
// log.Fatalf("failed to load config, %v", err)
|
||||
// }
|
||||
//
|
||||
// client := s3.NewFromConfig(config)
|
||||
//
|
||||
// result, err := client.GetObject(context.TODO(), s3.GetObject{
|
||||
// Bucket: aws.String("example-bucket"),
|
||||
// Key: aws.String("example-key"),
|
||||
// }, func(o *s3.Options) {
|
||||
// o.Credentials = nil
|
||||
// // Or
|
||||
// o.Credentials = aws.AnonymousCredentials{}
|
||||
// })
|
||||
type AnonymousCredentials struct{}
|
||||
|
||||
// Retrieve implements the CredentialsProvider interface, but will always
|
||||
// return error, and cannot be used to sign a request. The AnonymousCredentials
|
||||
// type is used as a sentinel type instructing the AWS request signing
|
||||
// middleware to not sign a request.
|
||||
func (AnonymousCredentials) Retrieve(context.Context) (Credentials, error) {
|
||||
return Credentials{Source: "AnonymousCredentials"},
|
||||
fmt.Errorf("the AnonymousCredentials is not a valid credential provider, and cannot be used to sign AWS requests with")
|
||||
}
|
||||
|
||||
// CredentialSource is the source of the credential provider.
|
||||
// A provider can have multiple credential sources: For example, a provider that reads a profile, calls ECS to
|
||||
// get credentials and then assumes a role using STS will have all these as part of its provider chain.
|
||||
type CredentialSource int
|
||||
|
||||
const (
|
||||
// CredentialSourceUndefined is the sentinel zero value
|
||||
CredentialSourceUndefined CredentialSource = iota
|
||||
// CredentialSourceCode credentials resolved from code, cli parameters, session object, or client instance
|
||||
CredentialSourceCode
|
||||
// CredentialSourceEnvVars credentials resolved from environment variables
|
||||
CredentialSourceEnvVars
|
||||
// CredentialSourceEnvVarsSTSWebIDToken credentials resolved from environment variables for assuming a role with STS using a web identity token
|
||||
CredentialSourceEnvVarsSTSWebIDToken
|
||||
// CredentialSourceSTSAssumeRole credentials resolved from STS using AssumeRole
|
||||
CredentialSourceSTSAssumeRole
|
||||
// CredentialSourceSTSAssumeRoleSaml credentials resolved from STS using assume role with SAML
|
||||
CredentialSourceSTSAssumeRoleSaml
|
||||
// CredentialSourceSTSAssumeRoleWebID credentials resolved from STS using assume role with web identity
|
||||
CredentialSourceSTSAssumeRoleWebID
|
||||
// CredentialSourceSTSFederationToken credentials resolved from STS using a federation token
|
||||
CredentialSourceSTSFederationToken
|
||||
// CredentialSourceSTSSessionToken credentials resolved from STS using a session token S
|
||||
CredentialSourceSTSSessionToken
|
||||
// CredentialSourceProfile credentials resolved from a config file(s) profile with static credentials
|
||||
CredentialSourceProfile
|
||||
// CredentialSourceProfileSourceProfile credentials resolved from a source profile in a config file(s) profile
|
||||
CredentialSourceProfileSourceProfile
|
||||
// CredentialSourceProfileNamedProvider credentials resolved from a named provider in a config file(s) profile (like EcsContainer)
|
||||
CredentialSourceProfileNamedProvider
|
||||
// CredentialSourceProfileSTSWebIDToken credentials resolved from configuration for assuming a role with STS using web identity token in a config file(s) profile
|
||||
CredentialSourceProfileSTSWebIDToken
|
||||
// CredentialSourceProfileSSO credentials resolved from an SSO session in a config file(s) profile
|
||||
CredentialSourceProfileSSO
|
||||
// CredentialSourceSSO credentials resolved from an SSO session
|
||||
CredentialSourceSSO
|
||||
// CredentialSourceProfileSSOLegacy credentials resolved from an SSO session in a config file(s) profile using legacy format
|
||||
CredentialSourceProfileSSOLegacy
|
||||
// CredentialSourceSSOLegacy credentials resolved from an SSO session using legacy format
|
||||
CredentialSourceSSOLegacy
|
||||
// CredentialSourceProfileProcess credentials resolved from a process in a config file(s) profile
|
||||
CredentialSourceProfileProcess
|
||||
// CredentialSourceProcess credentials resolved from a process
|
||||
CredentialSourceProcess
|
||||
// CredentialSourceHTTP credentials resolved from an HTTP endpoint
|
||||
CredentialSourceHTTP
|
||||
// CredentialSourceIMDS credentials resolved from the instance metadata service (IMDS)
|
||||
CredentialSourceIMDS
|
||||
)
|
||||
|
||||
// A Credentials is the AWS credentials value for individual credential fields.
|
||||
type Credentials struct {
|
||||
// AWS Access key ID
|
||||
AccessKeyID string
|
||||
|
||||
// AWS Secret Access Key
|
||||
SecretAccessKey string
|
||||
|
||||
// AWS Session Token
|
||||
SessionToken string
|
||||
|
||||
// Source of the credentials
|
||||
Source string
|
||||
|
||||
// States if the credentials can expire or not.
|
||||
CanExpire bool
|
||||
|
||||
// The time the credentials will expire at. Should be ignored if CanExpire
|
||||
// is false.
|
||||
Expires time.Time
|
||||
|
||||
// The ID of the account for the credentials.
|
||||
AccountID string
|
||||
}
|
||||
|
||||
// Expired returns if the credentials have expired.
|
||||
func (v Credentials) Expired() bool {
|
||||
if v.CanExpire {
|
||||
// Calling Round(0) on the current time will truncate the monotonic
|
||||
// reading only. Ensures credential expiry time is always based on
|
||||
// reported wall-clock time.
|
||||
return !v.Expires.After(sdk.NowTime().Round(0))
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// HasKeys returns if the credentials keys are set.
|
||||
func (v Credentials) HasKeys() bool {
|
||||
return len(v.AccessKeyID) > 0 && len(v.SecretAccessKey) > 0
|
||||
}
|
||||
|
||||
// A CredentialsProvider is the interface for any component which will provide
|
||||
// credentials Credentials. A CredentialsProvider is required to manage its own
|
||||
// Expired state, and what to be expired means.
|
||||
//
|
||||
// A credentials provider implementation can be wrapped with a CredentialCache
|
||||
// to cache the credential value retrieved. Without the cache the SDK will
|
||||
// attempt to retrieve the credentials for every request.
|
||||
type CredentialsProvider interface {
|
||||
// Retrieve returns nil if it successfully retrieved the value.
|
||||
// Error is returned if the value were not obtainable, or empty.
|
||||
Retrieve(ctx context.Context) (Credentials, error)
|
||||
}
|
||||
|
||||
// CredentialProviderSource allows any credential provider to track
|
||||
// all providers where a credential provider were sourced. For example, if the credentials came from a
|
||||
// call to a role specified in the profile, this method will give the whole breadcrumb trail
|
||||
type CredentialProviderSource interface {
|
||||
ProviderSources() []CredentialSource
|
||||
}
|
||||
|
||||
// CredentialsProviderFunc provides a helper wrapping a function value to
|
||||
// satisfy the CredentialsProvider interface.
|
||||
type CredentialsProviderFunc func(context.Context) (Credentials, error)
|
||||
|
||||
// Retrieve delegates to the function value the CredentialsProviderFunc wraps.
|
||||
func (fn CredentialsProviderFunc) Retrieve(ctx context.Context) (Credentials, error) {
|
||||
return fn(ctx)
|
||||
}
|
||||
|
||||
type isCredentialsProvider interface {
|
||||
IsCredentialsProvider(CredentialsProvider) bool
|
||||
}
|
||||
|
||||
// IsCredentialsProvider returns whether the target CredentialProvider is the same type as provider when comparing the
|
||||
// implementation type.
|
||||
//
|
||||
// If provider has a method IsCredentialsProvider(CredentialsProvider) bool it will be responsible for validating
|
||||
// whether target matches the credential provider type.
|
||||
//
|
||||
// When comparing the CredentialProvider implementations provider and target for equality, the following rules are used:
|
||||
//
|
||||
// If provider is of type T and target is of type V, true if type *T is the same as type *V, otherwise false
|
||||
// If provider is of type *T and target is of type V, true if type *T is the same as type *V, otherwise false
|
||||
// If provider is of type T and target is of type *V, true if type *T is the same as type *V, otherwise false
|
||||
// If provider is of type *T and target is of type *V,true if type *T is the same as type *V, otherwise false
|
||||
func IsCredentialsProvider(provider, target CredentialsProvider) bool {
|
||||
if target == nil || provider == nil {
|
||||
return provider == target
|
||||
}
|
||||
|
||||
if x, ok := provider.(isCredentialsProvider); ok {
|
||||
return x.IsCredentialsProvider(target)
|
||||
}
|
||||
|
||||
targetType := reflect.TypeOf(target)
|
||||
if targetType.Kind() != reflect.Ptr {
|
||||
targetType = reflect.PtrTo(targetType)
|
||||
}
|
||||
|
||||
providerType := reflect.TypeOf(provider)
|
||||
if providerType.Kind() != reflect.Ptr {
|
||||
providerType = reflect.PtrTo(providerType)
|
||||
}
|
||||
|
||||
return targetType.AssignableTo(providerType)
|
||||
}
|
||||
38
go/vendor/github.com/aws/aws-sdk-go-v2/aws/defaults/auto.go
generated
vendored
Normal file
38
go/vendor/github.com/aws/aws-sdk-go-v2/aws/defaults/auto.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package defaults
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var getGOOS = func() string {
|
||||
return runtime.GOOS
|
||||
}
|
||||
|
||||
// ResolveDefaultsModeAuto is used to determine the effective aws.DefaultsMode when the mode
|
||||
// is set to aws.DefaultsModeAuto.
|
||||
func ResolveDefaultsModeAuto(region string, environment aws.RuntimeEnvironment) aws.DefaultsMode {
|
||||
goos := getGOOS()
|
||||
if goos == "android" || goos == "ios" {
|
||||
return aws.DefaultsModeMobile
|
||||
}
|
||||
|
||||
var currentRegion string
|
||||
if len(environment.EnvironmentIdentifier) > 0 {
|
||||
currentRegion = environment.Region
|
||||
}
|
||||
|
||||
if len(currentRegion) == 0 && len(environment.EC2InstanceMetadataRegion) > 0 {
|
||||
currentRegion = environment.EC2InstanceMetadataRegion
|
||||
}
|
||||
|
||||
if len(region) > 0 && len(currentRegion) > 0 {
|
||||
if strings.EqualFold(region, currentRegion) {
|
||||
return aws.DefaultsModeInRegion
|
||||
}
|
||||
return aws.DefaultsModeCrossRegion
|
||||
}
|
||||
|
||||
return aws.DefaultsModeStandard
|
||||
}
|
||||
43
go/vendor/github.com/aws/aws-sdk-go-v2/aws/defaults/configuration.go
generated
vendored
Normal file
43
go/vendor/github.com/aws/aws-sdk-go-v2/aws/defaults/configuration.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package defaults
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
)
|
||||
|
||||
// Configuration is the set of SDK configuration options that are determined based
|
||||
// on the configured DefaultsMode.
|
||||
type Configuration struct {
|
||||
// RetryMode is the configuration's default retry mode API clients should
|
||||
// use for constructing a Retryer.
|
||||
RetryMode aws.RetryMode
|
||||
|
||||
// ConnectTimeout is the maximum amount of time a dial will wait for
|
||||
// a connect to complete.
|
||||
//
|
||||
// See https://pkg.go.dev/net#Dialer.Timeout
|
||||
ConnectTimeout *time.Duration
|
||||
|
||||
// TLSNegotiationTimeout specifies the maximum amount of time waiting to
|
||||
// wait for a TLS handshake.
|
||||
//
|
||||
// See https://pkg.go.dev/net/http#Transport.TLSHandshakeTimeout
|
||||
TLSNegotiationTimeout *time.Duration
|
||||
}
|
||||
|
||||
// GetConnectTimeout returns the ConnectTimeout value, returns false if the value is not set.
|
||||
func (c *Configuration) GetConnectTimeout() (time.Duration, bool) {
|
||||
if c.ConnectTimeout == nil {
|
||||
return 0, false
|
||||
}
|
||||
return *c.ConnectTimeout, true
|
||||
}
|
||||
|
||||
// GetTLSNegotiationTimeout returns the TLSNegotiationTimeout value, returns false if the value is not set.
|
||||
func (c *Configuration) GetTLSNegotiationTimeout() (time.Duration, bool) {
|
||||
if c.TLSNegotiationTimeout == nil {
|
||||
return 0, false
|
||||
}
|
||||
return *c.TLSNegotiationTimeout, true
|
||||
}
|
||||
50
go/vendor/github.com/aws/aws-sdk-go-v2/aws/defaults/defaults.go
generated
vendored
Normal file
50
go/vendor/github.com/aws/aws-sdk-go-v2/aws/defaults/defaults.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// Code generated by github.com/aws/aws-sdk-go-v2/internal/codegen/cmd/defaultsconfig. DO NOT EDIT.
|
||||
|
||||
package defaults
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GetModeConfiguration returns the default Configuration descriptor for the given mode.
|
||||
//
|
||||
// Supports the following modes: cross-region, in-region, mobile, standard
|
||||
func GetModeConfiguration(mode aws.DefaultsMode) (Configuration, error) {
|
||||
var mv aws.DefaultsMode
|
||||
mv.SetFromString(string(mode))
|
||||
|
||||
switch mv {
|
||||
case aws.DefaultsModeCrossRegion:
|
||||
settings := Configuration{
|
||||
ConnectTimeout: aws.Duration(3100 * time.Millisecond),
|
||||
RetryMode: aws.RetryMode("standard"),
|
||||
TLSNegotiationTimeout: aws.Duration(3100 * time.Millisecond),
|
||||
}
|
||||
return settings, nil
|
||||
case aws.DefaultsModeInRegion:
|
||||
settings := Configuration{
|
||||
ConnectTimeout: aws.Duration(1100 * time.Millisecond),
|
||||
RetryMode: aws.RetryMode("standard"),
|
||||
TLSNegotiationTimeout: aws.Duration(1100 * time.Millisecond),
|
||||
}
|
||||
return settings, nil
|
||||
case aws.DefaultsModeMobile:
|
||||
settings := Configuration{
|
||||
ConnectTimeout: aws.Duration(30000 * time.Millisecond),
|
||||
RetryMode: aws.RetryMode("standard"),
|
||||
TLSNegotiationTimeout: aws.Duration(30000 * time.Millisecond),
|
||||
}
|
||||
return settings, nil
|
||||
case aws.DefaultsModeStandard:
|
||||
settings := Configuration{
|
||||
ConnectTimeout: aws.Duration(3100 * time.Millisecond),
|
||||
RetryMode: aws.RetryMode("standard"),
|
||||
TLSNegotiationTimeout: aws.Duration(3100 * time.Millisecond),
|
||||
}
|
||||
return settings, nil
|
||||
default:
|
||||
return Configuration{}, fmt.Errorf("unsupported defaults mode: %v", mode)
|
||||
}
|
||||
}
|
||||
2
go/vendor/github.com/aws/aws-sdk-go-v2/aws/defaults/doc.go
generated
vendored
Normal file
2
go/vendor/github.com/aws/aws-sdk-go-v2/aws/defaults/doc.go
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package defaults provides recommended configuration values for AWS SDKs and CLIs.
|
||||
package defaults
|
||||
95
go/vendor/github.com/aws/aws-sdk-go-v2/aws/defaultsmode.go
generated
vendored
Normal file
95
go/vendor/github.com/aws/aws-sdk-go-v2/aws/defaultsmode.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
// Code generated by github.com/aws/aws-sdk-go-v2/internal/codegen/cmd/defaultsmode. DO NOT EDIT.
|
||||
|
||||
package aws
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// DefaultsMode is the SDK defaults mode setting.
|
||||
type DefaultsMode string
|
||||
|
||||
// The DefaultsMode constants.
|
||||
const (
|
||||
// DefaultsModeAuto is an experimental mode that builds on the standard mode.
|
||||
// The SDK will attempt to discover the execution environment to determine the
|
||||
// appropriate settings automatically.
|
||||
//
|
||||
// Note that the auto detection is heuristics-based and does not guarantee 100%
|
||||
// accuracy. STANDARD mode will be used if the execution environment cannot
|
||||
// be determined. The auto detection might query EC2 Instance Metadata service
|
||||
// (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html),
|
||||
// which might introduce latency. Therefore we recommend choosing an explicit
|
||||
// defaults_mode instead if startup latency is critical to your application
|
||||
DefaultsModeAuto DefaultsMode = "auto"
|
||||
|
||||
// DefaultsModeCrossRegion builds on the standard mode and includes optimization
|
||||
// tailored for applications which call AWS services in a different region
|
||||
//
|
||||
// Note that the default values vended from this mode might change as best practices
|
||||
// may evolve. As a result, it is encouraged to perform tests when upgrading
|
||||
// the SDK
|
||||
DefaultsModeCrossRegion DefaultsMode = "cross-region"
|
||||
|
||||
// DefaultsModeInRegion builds on the standard mode and includes optimization
|
||||
// tailored for applications which call AWS services from within the same AWS
|
||||
// region
|
||||
//
|
||||
// Note that the default values vended from this mode might change as best practices
|
||||
// may evolve. As a result, it is encouraged to perform tests when upgrading
|
||||
// the SDK
|
||||
DefaultsModeInRegion DefaultsMode = "in-region"
|
||||
|
||||
// DefaultsModeLegacy provides default settings that vary per SDK and were used
|
||||
// prior to establishment of defaults_mode
|
||||
DefaultsModeLegacy DefaultsMode = "legacy"
|
||||
|
||||
// DefaultsModeMobile builds on the standard mode and includes optimization
|
||||
// tailored for mobile applications
|
||||
//
|
||||
// Note that the default values vended from this mode might change as best practices
|
||||
// may evolve. As a result, it is encouraged to perform tests when upgrading
|
||||
// the SDK
|
||||
DefaultsModeMobile DefaultsMode = "mobile"
|
||||
|
||||
// DefaultsModeStandard provides the latest recommended default values that
|
||||
// should be safe to run in most scenarios
|
||||
//
|
||||
// Note that the default values vended from this mode might change as best practices
|
||||
// may evolve. As a result, it is encouraged to perform tests when upgrading
|
||||
// the SDK
|
||||
DefaultsModeStandard DefaultsMode = "standard"
|
||||
)
|
||||
|
||||
// SetFromString sets the DefaultsMode value to one of the pre-defined constants that matches
|
||||
// the provided string when compared using EqualFold. If the value does not match a known
|
||||
// constant it will be set to as-is and the function will return false. As a special case, if the
|
||||
// provided value is a zero-length string, the mode will be set to LegacyDefaultsMode.
|
||||
func (d *DefaultsMode) SetFromString(v string) (ok bool) {
|
||||
switch {
|
||||
case strings.EqualFold(v, string(DefaultsModeAuto)):
|
||||
*d = DefaultsModeAuto
|
||||
ok = true
|
||||
case strings.EqualFold(v, string(DefaultsModeCrossRegion)):
|
||||
*d = DefaultsModeCrossRegion
|
||||
ok = true
|
||||
case strings.EqualFold(v, string(DefaultsModeInRegion)):
|
||||
*d = DefaultsModeInRegion
|
||||
ok = true
|
||||
case strings.EqualFold(v, string(DefaultsModeLegacy)):
|
||||
*d = DefaultsModeLegacy
|
||||
ok = true
|
||||
case strings.EqualFold(v, string(DefaultsModeMobile)):
|
||||
*d = DefaultsModeMobile
|
||||
ok = true
|
||||
case strings.EqualFold(v, string(DefaultsModeStandard)):
|
||||
*d = DefaultsModeStandard
|
||||
ok = true
|
||||
case len(v) == 0:
|
||||
*d = DefaultsModeLegacy
|
||||
ok = true
|
||||
default:
|
||||
*d = DefaultsMode(v)
|
||||
}
|
||||
return ok
|
||||
}
|
||||
62
go/vendor/github.com/aws/aws-sdk-go-v2/aws/doc.go
generated
vendored
Normal file
62
go/vendor/github.com/aws/aws-sdk-go-v2/aws/doc.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
// Package aws provides the core SDK's utilities and shared types. Use this package's
|
||||
// utilities to simplify setting and reading API operations parameters.
|
||||
//
|
||||
// # Value and Pointer Conversion Utilities
|
||||
//
|
||||
// This package includes a helper conversion utility for each scalar type the SDK's
|
||||
// API use. These utilities make getting a pointer of the scalar, and dereferencing
|
||||
// a pointer easier.
|
||||
//
|
||||
// Each conversion utility comes in two forms. Value to Pointer and Pointer to Value.
|
||||
// The Pointer to value will safely dereference the pointer and return its value.
|
||||
// If the pointer was nil, the scalar's zero value will be returned.
|
||||
//
|
||||
// The value to pointer functions will be named after the scalar type. So get a
|
||||
// *string from a string value use the "String" function. This makes it easy to
|
||||
// to get pointer of a literal string value, because getting the address of a
|
||||
// literal requires assigning the value to a variable first.
|
||||
//
|
||||
// var strPtr *string
|
||||
//
|
||||
// // Without the SDK's conversion functions
|
||||
// str := "my string"
|
||||
// strPtr = &str
|
||||
//
|
||||
// // With the SDK's conversion functions
|
||||
// strPtr = aws.String("my string")
|
||||
//
|
||||
// // Convert *string to string value
|
||||
// str = aws.ToString(strPtr)
|
||||
//
|
||||
// In addition to scalars the aws package also includes conversion utilities for
|
||||
// map and slice for commonly types used in API parameters. The map and slice
|
||||
// conversion functions use similar naming pattern as the scalar conversion
|
||||
// functions.
|
||||
//
|
||||
// var strPtrs []*string
|
||||
// var strs []string = []string{"Go", "Gophers", "Go"}
|
||||
//
|
||||
// // Convert []string to []*string
|
||||
// strPtrs = aws.StringSlice(strs)
|
||||
//
|
||||
// // Convert []*string to []string
|
||||
// strs = aws.ToStringSlice(strPtrs)
|
||||
//
|
||||
// # SDK Default HTTP Client
|
||||
//
|
||||
// The SDK will use the http.DefaultClient if a HTTP client is not provided to
|
||||
// the SDK's Session, or service client constructor. This means that if the
|
||||
// http.DefaultClient is modified by other components of your application the
|
||||
// modifications will be picked up by the SDK as well.
|
||||
//
|
||||
// In some cases this might be intended, but it is a better practice to create
|
||||
// a custom HTTP Client to share explicitly through your application. You can
|
||||
// configure the SDK to use the custom HTTP Client by setting the HTTPClient
|
||||
// value of the SDK's Config type when creating a Session or service client.
|
||||
package aws
|
||||
|
||||
// generate.go uses a build tag of "ignore", go run doesn't need to specify
|
||||
// this because go run ignores all build flags when running a go file directly.
|
||||
//go:generate go run -tags codegen generate.go
|
||||
//go:generate go run -tags codegen logging_generate.go
|
||||
//go:generate gofmt -w -s .
|
||||
247
go/vendor/github.com/aws/aws-sdk-go-v2/aws/endpoints.go
generated
vendored
Normal file
247
go/vendor/github.com/aws/aws-sdk-go-v2/aws/endpoints.go
generated
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// DualStackEndpointState is a constant to describe the dual-stack endpoint resolution behavior.
|
||||
type DualStackEndpointState uint
|
||||
|
||||
const (
|
||||
// DualStackEndpointStateUnset is the default value behavior for dual-stack endpoint resolution.
|
||||
DualStackEndpointStateUnset DualStackEndpointState = iota
|
||||
|
||||
// DualStackEndpointStateEnabled enables dual-stack endpoint resolution for service endpoints.
|
||||
DualStackEndpointStateEnabled
|
||||
|
||||
// DualStackEndpointStateDisabled disables dual-stack endpoint resolution for endpoints.
|
||||
DualStackEndpointStateDisabled
|
||||
)
|
||||
|
||||
// GetUseDualStackEndpoint takes a service's EndpointResolverOptions and returns the UseDualStackEndpoint value.
|
||||
// Returns boolean false if the provided options does not have a method to retrieve the DualStackEndpointState.
|
||||
func GetUseDualStackEndpoint(options ...interface{}) (value DualStackEndpointState, found bool) {
|
||||
type iface interface {
|
||||
GetUseDualStackEndpoint() DualStackEndpointState
|
||||
}
|
||||
for _, option := range options {
|
||||
if i, ok := option.(iface); ok {
|
||||
value = i.GetUseDualStackEndpoint()
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return value, found
|
||||
}
|
||||
|
||||
// FIPSEndpointState is a constant to describe the FIPS endpoint resolution behavior.
|
||||
type FIPSEndpointState uint
|
||||
|
||||
const (
|
||||
// FIPSEndpointStateUnset is the default value behavior for FIPS endpoint resolution.
|
||||
FIPSEndpointStateUnset FIPSEndpointState = iota
|
||||
|
||||
// FIPSEndpointStateEnabled enables FIPS endpoint resolution for service endpoints.
|
||||
FIPSEndpointStateEnabled
|
||||
|
||||
// FIPSEndpointStateDisabled disables FIPS endpoint resolution for endpoints.
|
||||
FIPSEndpointStateDisabled
|
||||
)
|
||||
|
||||
// GetUseFIPSEndpoint takes a service's EndpointResolverOptions and returns the UseDualStackEndpoint value.
|
||||
// Returns boolean false if the provided options does not have a method to retrieve the DualStackEndpointState.
|
||||
func GetUseFIPSEndpoint(options ...interface{}) (value FIPSEndpointState, found bool) {
|
||||
type iface interface {
|
||||
GetUseFIPSEndpoint() FIPSEndpointState
|
||||
}
|
||||
for _, option := range options {
|
||||
if i, ok := option.(iface); ok {
|
||||
value = i.GetUseFIPSEndpoint()
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return value, found
|
||||
}
|
||||
|
||||
// Endpoint represents the endpoint a service client should make API operation
|
||||
// calls to.
|
||||
//
|
||||
// The SDK will automatically resolve these endpoints per API client using an
|
||||
// internal endpoint resolvers. If you'd like to provide custom endpoint
|
||||
// resolving behavior you can implement the EndpointResolver interface.
|
||||
//
|
||||
// Deprecated: This structure was used with the global [EndpointResolver]
|
||||
// interface, which has been deprecated in favor of service-specific endpoint
|
||||
// resolution. See the deprecation docs on that interface for more information.
|
||||
type Endpoint struct {
|
||||
// The base URL endpoint the SDK API clients will use to make API calls to.
|
||||
// The SDK will suffix URI path and query elements to this endpoint.
|
||||
URL string
|
||||
|
||||
// Specifies if the endpoint's hostname can be modified by the SDK's API
|
||||
// client.
|
||||
//
|
||||
// If the hostname is mutable the SDK API clients may modify any part of
|
||||
// the hostname based on the requirements of the API, (e.g. adding, or
|
||||
// removing content in the hostname). Such as, Amazon S3 API client
|
||||
// prefixing "bucketname" to the hostname, or changing the
|
||||
// hostname service name component from "s3." to "s3-accesspoint.dualstack."
|
||||
// for the dualstack endpoint of an S3 Accesspoint resource.
|
||||
//
|
||||
// Care should be taken when providing a custom endpoint for an API. If the
|
||||
// endpoint hostname is mutable, and the client cannot modify the endpoint
|
||||
// correctly, the operation call will most likely fail, or have undefined
|
||||
// behavior.
|
||||
//
|
||||
// If hostname is immutable, the SDK API clients will not modify the
|
||||
// hostname of the URL. This may cause the API client not to function
|
||||
// correctly if the API requires the operation specific hostname values
|
||||
// to be used by the client.
|
||||
//
|
||||
// This flag does not modify the API client's behavior if this endpoint
|
||||
// will be used instead of Endpoint Discovery, or if the endpoint will be
|
||||
// used to perform Endpoint Discovery. That behavior is configured via the
|
||||
// API Client's Options.
|
||||
HostnameImmutable bool
|
||||
|
||||
// The AWS partition the endpoint belongs to.
|
||||
PartitionID string
|
||||
|
||||
// The service name that should be used for signing the requests to the
|
||||
// endpoint.
|
||||
SigningName string
|
||||
|
||||
// The region that should be used for signing the request to the endpoint.
|
||||
SigningRegion string
|
||||
|
||||
// The signing method that should be used for signing the requests to the
|
||||
// endpoint.
|
||||
SigningMethod string
|
||||
|
||||
// The source of the Endpoint. By default, this will be EndpointSourceServiceMetadata.
|
||||
// When providing a custom endpoint, you should set the source as EndpointSourceCustom.
|
||||
// If source is not provided when providing a custom endpoint, the SDK may not
|
||||
// perform required host mutations correctly. Source should be used along with
|
||||
// HostnameImmutable property as per the usage requirement.
|
||||
Source EndpointSource
|
||||
}
|
||||
|
||||
// EndpointSource is the endpoint source type.
|
||||
//
|
||||
// Deprecated: The global [Endpoint] structure is deprecated.
|
||||
type EndpointSource int
|
||||
|
||||
const (
|
||||
// EndpointSourceServiceMetadata denotes service modeled endpoint metadata is used as Endpoint Source.
|
||||
EndpointSourceServiceMetadata EndpointSource = iota
|
||||
|
||||
// EndpointSourceCustom denotes endpoint is a custom endpoint. This source should be used when
|
||||
// user provides a custom endpoint to be used by the SDK.
|
||||
EndpointSourceCustom
|
||||
)
|
||||
|
||||
// EndpointNotFoundError is a sentinel error to indicate that the
|
||||
// EndpointResolver implementation was unable to resolve an endpoint for the
|
||||
// given service and region. Resolvers should use this to indicate that an API
|
||||
// client should fallback and attempt to use it's internal default resolver to
|
||||
// resolve the endpoint.
|
||||
type EndpointNotFoundError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
// Error is the error message.
|
||||
func (e *EndpointNotFoundError) Error() string {
|
||||
return fmt.Sprintf("endpoint not found, %v", e.Err)
|
||||
}
|
||||
|
||||
// Unwrap returns the underlying error.
|
||||
func (e *EndpointNotFoundError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// EndpointResolver is an endpoint resolver that can be used to provide or
|
||||
// override an endpoint for the given service and region. API clients will
|
||||
// attempt to use the EndpointResolver first to resolve an endpoint if
|
||||
// available. If the EndpointResolver returns an EndpointNotFoundError error,
|
||||
// API clients will fallback to attempting to resolve the endpoint using its
|
||||
// internal default endpoint resolver.
|
||||
//
|
||||
// Deprecated: The global endpoint resolution interface is deprecated. The API
|
||||
// for endpoint resolution is now unique to each service and is set via the
|
||||
// EndpointResolverV2 field on service client options. Setting a value for
|
||||
// EndpointResolver on aws.Config or service client options will prevent you
|
||||
// from using any endpoint-related service features released after the
|
||||
// introduction of EndpointResolverV2. You may also encounter broken or
|
||||
// unexpected behavior when using the old global interface with services that
|
||||
// use many endpoint-related customizations such as S3.
|
||||
type EndpointResolver interface {
|
||||
ResolveEndpoint(service, region string) (Endpoint, error)
|
||||
}
|
||||
|
||||
// EndpointResolverFunc wraps a function to satisfy the EndpointResolver interface.
|
||||
//
|
||||
// Deprecated: The global endpoint resolution interface is deprecated. See
|
||||
// deprecation docs on [EndpointResolver].
|
||||
type EndpointResolverFunc func(service, region string) (Endpoint, error)
|
||||
|
||||
// ResolveEndpoint calls the wrapped function and returns the results.
|
||||
func (e EndpointResolverFunc) ResolveEndpoint(service, region string) (Endpoint, error) {
|
||||
return e(service, region)
|
||||
}
|
||||
|
||||
// EndpointResolverWithOptions is an endpoint resolver that can be used to provide or
|
||||
// override an endpoint for the given service, region, and the service client's EndpointOptions. API clients will
|
||||
// attempt to use the EndpointResolverWithOptions first to resolve an endpoint if
|
||||
// available. If the EndpointResolverWithOptions returns an EndpointNotFoundError error,
|
||||
// API clients will fallback to attempting to resolve the endpoint using its
|
||||
// internal default endpoint resolver.
|
||||
//
|
||||
// Deprecated: The global endpoint resolution interface is deprecated. See
|
||||
// deprecation docs on [EndpointResolver].
|
||||
type EndpointResolverWithOptions interface {
|
||||
ResolveEndpoint(service, region string, options ...interface{}) (Endpoint, error)
|
||||
}
|
||||
|
||||
// EndpointResolverWithOptionsFunc wraps a function to satisfy the EndpointResolverWithOptions interface.
|
||||
//
|
||||
// Deprecated: The global endpoint resolution interface is deprecated. See
|
||||
// deprecation docs on [EndpointResolver].
|
||||
type EndpointResolverWithOptionsFunc func(service, region string, options ...interface{}) (Endpoint, error)
|
||||
|
||||
// ResolveEndpoint calls the wrapped function and returns the results.
|
||||
func (e EndpointResolverWithOptionsFunc) ResolveEndpoint(service, region string, options ...interface{}) (Endpoint, error) {
|
||||
return e(service, region, options...)
|
||||
}
|
||||
|
||||
// GetDisableHTTPS takes a service's EndpointResolverOptions and returns the DisableHTTPS value.
|
||||
// Returns boolean false if the provided options does not have a method to retrieve the DisableHTTPS.
|
||||
func GetDisableHTTPS(options ...interface{}) (value bool, found bool) {
|
||||
type iface interface {
|
||||
GetDisableHTTPS() bool
|
||||
}
|
||||
for _, option := range options {
|
||||
if i, ok := option.(iface); ok {
|
||||
value = i.GetDisableHTTPS()
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return value, found
|
||||
}
|
||||
|
||||
// GetResolvedRegion takes a service's EndpointResolverOptions and returns the ResolvedRegion value.
|
||||
// Returns boolean false if the provided options does not have a method to retrieve the ResolvedRegion.
|
||||
func GetResolvedRegion(options ...interface{}) (value string, found bool) {
|
||||
type iface interface {
|
||||
GetResolvedRegion() string
|
||||
}
|
||||
for _, option := range options {
|
||||
if i, ok := option.(iface); ok {
|
||||
value = i.GetResolvedRegion()
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return value, found
|
||||
}
|
||||
9
go/vendor/github.com/aws/aws-sdk-go-v2/aws/errors.go
generated
vendored
Normal file
9
go/vendor/github.com/aws/aws-sdk-go-v2/aws/errors.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package aws
|
||||
|
||||
// MissingRegionError is an error that is returned if region configuration
|
||||
// value was not found.
|
||||
type MissingRegionError struct{}
|
||||
|
||||
func (*MissingRegionError) Error() string {
|
||||
return "an AWS region is required, but was not found"
|
||||
}
|
||||
365
go/vendor/github.com/aws/aws-sdk-go-v2/aws/from_ptr.go
generated
vendored
Normal file
365
go/vendor/github.com/aws/aws-sdk-go-v2/aws/from_ptr.go
generated
vendored
Normal file
@@ -0,0 +1,365 @@
|
||||
// Code generated by aws/generate.go DO NOT EDIT.
|
||||
|
||||
package aws
|
||||
|
||||
import (
|
||||
"github.com/aws/smithy-go/ptr"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ToBool returns bool value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a bool zero value if the
|
||||
// pointer was nil.
|
||||
func ToBool(p *bool) (v bool) {
|
||||
return ptr.ToBool(p)
|
||||
}
|
||||
|
||||
// ToBoolSlice returns a slice of bool values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a bool
|
||||
// zero value if the pointer was nil.
|
||||
func ToBoolSlice(vs []*bool) []bool {
|
||||
return ptr.ToBoolSlice(vs)
|
||||
}
|
||||
|
||||
// ToBoolMap returns a map of bool values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The bool
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToBoolMap(vs map[string]*bool) map[string]bool {
|
||||
return ptr.ToBoolMap(vs)
|
||||
}
|
||||
|
||||
// ToByte returns byte value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a byte zero value if the
|
||||
// pointer was nil.
|
||||
func ToByte(p *byte) (v byte) {
|
||||
return ptr.ToByte(p)
|
||||
}
|
||||
|
||||
// ToByteSlice returns a slice of byte values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a byte
|
||||
// zero value if the pointer was nil.
|
||||
func ToByteSlice(vs []*byte) []byte {
|
||||
return ptr.ToByteSlice(vs)
|
||||
}
|
||||
|
||||
// ToByteMap returns a map of byte values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The byte
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToByteMap(vs map[string]*byte) map[string]byte {
|
||||
return ptr.ToByteMap(vs)
|
||||
}
|
||||
|
||||
// ToString returns string value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a string zero value if the
|
||||
// pointer was nil.
|
||||
func ToString(p *string) (v string) {
|
||||
return ptr.ToString(p)
|
||||
}
|
||||
|
||||
// ToStringSlice returns a slice of string values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a string
|
||||
// zero value if the pointer was nil.
|
||||
func ToStringSlice(vs []*string) []string {
|
||||
return ptr.ToStringSlice(vs)
|
||||
}
|
||||
|
||||
// ToStringMap returns a map of string values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The string
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToStringMap(vs map[string]*string) map[string]string {
|
||||
return ptr.ToStringMap(vs)
|
||||
}
|
||||
|
||||
// ToInt returns int value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a int zero value if the
|
||||
// pointer was nil.
|
||||
func ToInt(p *int) (v int) {
|
||||
return ptr.ToInt(p)
|
||||
}
|
||||
|
||||
// ToIntSlice returns a slice of int values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a int
|
||||
// zero value if the pointer was nil.
|
||||
func ToIntSlice(vs []*int) []int {
|
||||
return ptr.ToIntSlice(vs)
|
||||
}
|
||||
|
||||
// ToIntMap returns a map of int values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The int
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToIntMap(vs map[string]*int) map[string]int {
|
||||
return ptr.ToIntMap(vs)
|
||||
}
|
||||
|
||||
// ToInt8 returns int8 value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a int8 zero value if the
|
||||
// pointer was nil.
|
||||
func ToInt8(p *int8) (v int8) {
|
||||
return ptr.ToInt8(p)
|
||||
}
|
||||
|
||||
// ToInt8Slice returns a slice of int8 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a int8
|
||||
// zero value if the pointer was nil.
|
||||
func ToInt8Slice(vs []*int8) []int8 {
|
||||
return ptr.ToInt8Slice(vs)
|
||||
}
|
||||
|
||||
// ToInt8Map returns a map of int8 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The int8
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToInt8Map(vs map[string]*int8) map[string]int8 {
|
||||
return ptr.ToInt8Map(vs)
|
||||
}
|
||||
|
||||
// ToInt16 returns int16 value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a int16 zero value if the
|
||||
// pointer was nil.
|
||||
func ToInt16(p *int16) (v int16) {
|
||||
return ptr.ToInt16(p)
|
||||
}
|
||||
|
||||
// ToInt16Slice returns a slice of int16 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a int16
|
||||
// zero value if the pointer was nil.
|
||||
func ToInt16Slice(vs []*int16) []int16 {
|
||||
return ptr.ToInt16Slice(vs)
|
||||
}
|
||||
|
||||
// ToInt16Map returns a map of int16 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The int16
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToInt16Map(vs map[string]*int16) map[string]int16 {
|
||||
return ptr.ToInt16Map(vs)
|
||||
}
|
||||
|
||||
// ToInt32 returns int32 value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a int32 zero value if the
|
||||
// pointer was nil.
|
||||
func ToInt32(p *int32) (v int32) {
|
||||
return ptr.ToInt32(p)
|
||||
}
|
||||
|
||||
// ToInt32Slice returns a slice of int32 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a int32
|
||||
// zero value if the pointer was nil.
|
||||
func ToInt32Slice(vs []*int32) []int32 {
|
||||
return ptr.ToInt32Slice(vs)
|
||||
}
|
||||
|
||||
// ToInt32Map returns a map of int32 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The int32
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToInt32Map(vs map[string]*int32) map[string]int32 {
|
||||
return ptr.ToInt32Map(vs)
|
||||
}
|
||||
|
||||
// ToInt64 returns int64 value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a int64 zero value if the
|
||||
// pointer was nil.
|
||||
func ToInt64(p *int64) (v int64) {
|
||||
return ptr.ToInt64(p)
|
||||
}
|
||||
|
||||
// ToInt64Slice returns a slice of int64 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a int64
|
||||
// zero value if the pointer was nil.
|
||||
func ToInt64Slice(vs []*int64) []int64 {
|
||||
return ptr.ToInt64Slice(vs)
|
||||
}
|
||||
|
||||
// ToInt64Map returns a map of int64 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The int64
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToInt64Map(vs map[string]*int64) map[string]int64 {
|
||||
return ptr.ToInt64Map(vs)
|
||||
}
|
||||
|
||||
// ToUint returns uint value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a uint zero value if the
|
||||
// pointer was nil.
|
||||
func ToUint(p *uint) (v uint) {
|
||||
return ptr.ToUint(p)
|
||||
}
|
||||
|
||||
// ToUintSlice returns a slice of uint values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a uint
|
||||
// zero value if the pointer was nil.
|
||||
func ToUintSlice(vs []*uint) []uint {
|
||||
return ptr.ToUintSlice(vs)
|
||||
}
|
||||
|
||||
// ToUintMap returns a map of uint values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The uint
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToUintMap(vs map[string]*uint) map[string]uint {
|
||||
return ptr.ToUintMap(vs)
|
||||
}
|
||||
|
||||
// ToUint8 returns uint8 value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a uint8 zero value if the
|
||||
// pointer was nil.
|
||||
func ToUint8(p *uint8) (v uint8) {
|
||||
return ptr.ToUint8(p)
|
||||
}
|
||||
|
||||
// ToUint8Slice returns a slice of uint8 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a uint8
|
||||
// zero value if the pointer was nil.
|
||||
func ToUint8Slice(vs []*uint8) []uint8 {
|
||||
return ptr.ToUint8Slice(vs)
|
||||
}
|
||||
|
||||
// ToUint8Map returns a map of uint8 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The uint8
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToUint8Map(vs map[string]*uint8) map[string]uint8 {
|
||||
return ptr.ToUint8Map(vs)
|
||||
}
|
||||
|
||||
// ToUint16 returns uint16 value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a uint16 zero value if the
|
||||
// pointer was nil.
|
||||
func ToUint16(p *uint16) (v uint16) {
|
||||
return ptr.ToUint16(p)
|
||||
}
|
||||
|
||||
// ToUint16Slice returns a slice of uint16 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a uint16
|
||||
// zero value if the pointer was nil.
|
||||
func ToUint16Slice(vs []*uint16) []uint16 {
|
||||
return ptr.ToUint16Slice(vs)
|
||||
}
|
||||
|
||||
// ToUint16Map returns a map of uint16 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The uint16
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToUint16Map(vs map[string]*uint16) map[string]uint16 {
|
||||
return ptr.ToUint16Map(vs)
|
||||
}
|
||||
|
||||
// ToUint32 returns uint32 value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a uint32 zero value if the
|
||||
// pointer was nil.
|
||||
func ToUint32(p *uint32) (v uint32) {
|
||||
return ptr.ToUint32(p)
|
||||
}
|
||||
|
||||
// ToUint32Slice returns a slice of uint32 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a uint32
|
||||
// zero value if the pointer was nil.
|
||||
func ToUint32Slice(vs []*uint32) []uint32 {
|
||||
return ptr.ToUint32Slice(vs)
|
||||
}
|
||||
|
||||
// ToUint32Map returns a map of uint32 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The uint32
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToUint32Map(vs map[string]*uint32) map[string]uint32 {
|
||||
return ptr.ToUint32Map(vs)
|
||||
}
|
||||
|
||||
// ToUint64 returns uint64 value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a uint64 zero value if the
|
||||
// pointer was nil.
|
||||
func ToUint64(p *uint64) (v uint64) {
|
||||
return ptr.ToUint64(p)
|
||||
}
|
||||
|
||||
// ToUint64Slice returns a slice of uint64 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a uint64
|
||||
// zero value if the pointer was nil.
|
||||
func ToUint64Slice(vs []*uint64) []uint64 {
|
||||
return ptr.ToUint64Slice(vs)
|
||||
}
|
||||
|
||||
// ToUint64Map returns a map of uint64 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The uint64
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToUint64Map(vs map[string]*uint64) map[string]uint64 {
|
||||
return ptr.ToUint64Map(vs)
|
||||
}
|
||||
|
||||
// ToFloat32 returns float32 value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a float32 zero value if the
|
||||
// pointer was nil.
|
||||
func ToFloat32(p *float32) (v float32) {
|
||||
return ptr.ToFloat32(p)
|
||||
}
|
||||
|
||||
// ToFloat32Slice returns a slice of float32 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a float32
|
||||
// zero value if the pointer was nil.
|
||||
func ToFloat32Slice(vs []*float32) []float32 {
|
||||
return ptr.ToFloat32Slice(vs)
|
||||
}
|
||||
|
||||
// ToFloat32Map returns a map of float32 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The float32
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToFloat32Map(vs map[string]*float32) map[string]float32 {
|
||||
return ptr.ToFloat32Map(vs)
|
||||
}
|
||||
|
||||
// ToFloat64 returns float64 value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a float64 zero value if the
|
||||
// pointer was nil.
|
||||
func ToFloat64(p *float64) (v float64) {
|
||||
return ptr.ToFloat64(p)
|
||||
}
|
||||
|
||||
// ToFloat64Slice returns a slice of float64 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a float64
|
||||
// zero value if the pointer was nil.
|
||||
func ToFloat64Slice(vs []*float64) []float64 {
|
||||
return ptr.ToFloat64Slice(vs)
|
||||
}
|
||||
|
||||
// ToFloat64Map returns a map of float64 values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The float64
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToFloat64Map(vs map[string]*float64) map[string]float64 {
|
||||
return ptr.ToFloat64Map(vs)
|
||||
}
|
||||
|
||||
// ToTime returns time.Time value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a time.Time zero value if the
|
||||
// pointer was nil.
|
||||
func ToTime(p *time.Time) (v time.Time) {
|
||||
return ptr.ToTime(p)
|
||||
}
|
||||
|
||||
// ToTimeSlice returns a slice of time.Time values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a time.Time
|
||||
// zero value if the pointer was nil.
|
||||
func ToTimeSlice(vs []*time.Time) []time.Time {
|
||||
return ptr.ToTimeSlice(vs)
|
||||
}
|
||||
|
||||
// ToTimeMap returns a map of time.Time values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The time.Time
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToTimeMap(vs map[string]*time.Time) map[string]time.Time {
|
||||
return ptr.ToTimeMap(vs)
|
||||
}
|
||||
|
||||
// ToDuration returns time.Duration value dereferenced if the passed
|
||||
// in pointer was not nil. Returns a time.Duration zero value if the
|
||||
// pointer was nil.
|
||||
func ToDuration(p *time.Duration) (v time.Duration) {
|
||||
return ptr.ToDuration(p)
|
||||
}
|
||||
|
||||
// ToDurationSlice returns a slice of time.Duration values, that are
|
||||
// dereferenced if the passed in pointer was not nil. Returns a time.Duration
|
||||
// zero value if the pointer was nil.
|
||||
func ToDurationSlice(vs []*time.Duration) []time.Duration {
|
||||
return ptr.ToDurationSlice(vs)
|
||||
}
|
||||
|
||||
// ToDurationMap returns a map of time.Duration values, that are
|
||||
// dereferenced if the passed in pointer was not nil. The time.Duration
|
||||
// zero value is used if the pointer was nil.
|
||||
func ToDurationMap(vs map[string]*time.Duration) map[string]time.Duration {
|
||||
return ptr.ToDurationMap(vs)
|
||||
}
|
||||
6
go/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go
generated
vendored
Normal file
6
go/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
// Code generated by internal/repotools/cmd/updatemodulemeta DO NOT EDIT.
|
||||
|
||||
package aws
|
||||
|
||||
// goModuleVersion is the tagged release for this module
|
||||
const goModuleVersion = "1.36.4"
|
||||
119
go/vendor/github.com/aws/aws-sdk-go-v2/aws/logging.go
generated
vendored
Normal file
119
go/vendor/github.com/aws/aws-sdk-go-v2/aws/logging.go
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
// Code generated by aws/logging_generate.go DO NOT EDIT.
|
||||
|
||||
package aws
|
||||
|
||||
// ClientLogMode represents the logging mode of SDK clients. The client logging mode is a bit-field where
|
||||
// each bit is a flag that describes the logging behavior for one or more client components.
|
||||
// The entire 64-bit group is reserved for later expansion by the SDK.
|
||||
//
|
||||
// Example: Setting ClientLogMode to enable logging of retries and requests
|
||||
//
|
||||
// clientLogMode := aws.LogRetries | aws.LogRequest
|
||||
//
|
||||
// Example: Adding an additional log mode to an existing ClientLogMode value
|
||||
//
|
||||
// clientLogMode |= aws.LogResponse
|
||||
type ClientLogMode uint64
|
||||
|
||||
// Supported ClientLogMode bits that can be configured to toggle logging of specific SDK events.
|
||||
const (
|
||||
LogSigning ClientLogMode = 1 << (64 - 1 - iota)
|
||||
LogRetries
|
||||
LogRequest
|
||||
LogRequestWithBody
|
||||
LogResponse
|
||||
LogResponseWithBody
|
||||
LogDeprecatedUsage
|
||||
LogRequestEventMessage
|
||||
LogResponseEventMessage
|
||||
)
|
||||
|
||||
// IsSigning returns whether the Signing logging mode bit is set
|
||||
func (m ClientLogMode) IsSigning() bool {
|
||||
return m&LogSigning != 0
|
||||
}
|
||||
|
||||
// IsRetries returns whether the Retries logging mode bit is set
|
||||
func (m ClientLogMode) IsRetries() bool {
|
||||
return m&LogRetries != 0
|
||||
}
|
||||
|
||||
// IsRequest returns whether the Request logging mode bit is set
|
||||
func (m ClientLogMode) IsRequest() bool {
|
||||
return m&LogRequest != 0
|
||||
}
|
||||
|
||||
// IsRequestWithBody returns whether the RequestWithBody logging mode bit is set
|
||||
func (m ClientLogMode) IsRequestWithBody() bool {
|
||||
return m&LogRequestWithBody != 0
|
||||
}
|
||||
|
||||
// IsResponse returns whether the Response logging mode bit is set
|
||||
func (m ClientLogMode) IsResponse() bool {
|
||||
return m&LogResponse != 0
|
||||
}
|
||||
|
||||
// IsResponseWithBody returns whether the ResponseWithBody logging mode bit is set
|
||||
func (m ClientLogMode) IsResponseWithBody() bool {
|
||||
return m&LogResponseWithBody != 0
|
||||
}
|
||||
|
||||
// IsDeprecatedUsage returns whether the DeprecatedUsage logging mode bit is set
|
||||
func (m ClientLogMode) IsDeprecatedUsage() bool {
|
||||
return m&LogDeprecatedUsage != 0
|
||||
}
|
||||
|
||||
// IsRequestEventMessage returns whether the RequestEventMessage logging mode bit is set
|
||||
func (m ClientLogMode) IsRequestEventMessage() bool {
|
||||
return m&LogRequestEventMessage != 0
|
||||
}
|
||||
|
||||
// IsResponseEventMessage returns whether the ResponseEventMessage logging mode bit is set
|
||||
func (m ClientLogMode) IsResponseEventMessage() bool {
|
||||
return m&LogResponseEventMessage != 0
|
||||
}
|
||||
|
||||
// ClearSigning clears the Signing logging mode bit
|
||||
func (m *ClientLogMode) ClearSigning() {
|
||||
*m &^= LogSigning
|
||||
}
|
||||
|
||||
// ClearRetries clears the Retries logging mode bit
|
||||
func (m *ClientLogMode) ClearRetries() {
|
||||
*m &^= LogRetries
|
||||
}
|
||||
|
||||
// ClearRequest clears the Request logging mode bit
|
||||
func (m *ClientLogMode) ClearRequest() {
|
||||
*m &^= LogRequest
|
||||
}
|
||||
|
||||
// ClearRequestWithBody clears the RequestWithBody logging mode bit
|
||||
func (m *ClientLogMode) ClearRequestWithBody() {
|
||||
*m &^= LogRequestWithBody
|
||||
}
|
||||
|
||||
// ClearResponse clears the Response logging mode bit
|
||||
func (m *ClientLogMode) ClearResponse() {
|
||||
*m &^= LogResponse
|
||||
}
|
||||
|
||||
// ClearResponseWithBody clears the ResponseWithBody logging mode bit
|
||||
func (m *ClientLogMode) ClearResponseWithBody() {
|
||||
*m &^= LogResponseWithBody
|
||||
}
|
||||
|
||||
// ClearDeprecatedUsage clears the DeprecatedUsage logging mode bit
|
||||
func (m *ClientLogMode) ClearDeprecatedUsage() {
|
||||
*m &^= LogDeprecatedUsage
|
||||
}
|
||||
|
||||
// ClearRequestEventMessage clears the RequestEventMessage logging mode bit
|
||||
func (m *ClientLogMode) ClearRequestEventMessage() {
|
||||
*m &^= LogRequestEventMessage
|
||||
}
|
||||
|
||||
// ClearResponseEventMessage clears the ResponseEventMessage logging mode bit
|
||||
func (m *ClientLogMode) ClearResponseEventMessage() {
|
||||
*m &^= LogResponseEventMessage
|
||||
}
|
||||
95
go/vendor/github.com/aws/aws-sdk-go-v2/aws/logging_generate.go
generated
vendored
Normal file
95
go/vendor/github.com/aws/aws-sdk-go-v2/aws/logging_generate.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
//go:build clientlogmode
|
||||
// +build clientlogmode
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var config = struct {
|
||||
ModeBits []string
|
||||
}{
|
||||
// Items should be appended only to keep bit-flag positions stable
|
||||
ModeBits: []string{
|
||||
"Signing",
|
||||
"Retries",
|
||||
"Request",
|
||||
"RequestWithBody",
|
||||
"Response",
|
||||
"ResponseWithBody",
|
||||
"DeprecatedUsage",
|
||||
"RequestEventMessage",
|
||||
"ResponseEventMessage",
|
||||
},
|
||||
}
|
||||
|
||||
func bitName(name string) string {
|
||||
return strings.ToUpper(name[:1]) + name[1:]
|
||||
}
|
||||
|
||||
var tmpl = template.Must(template.New("ClientLogMode").Funcs(map[string]interface{}{
|
||||
"symbolName": func(name string) string {
|
||||
return "Log" + bitName(name)
|
||||
},
|
||||
"bitName": bitName,
|
||||
}).Parse(`// Code generated by aws/logging_generate.go DO NOT EDIT.
|
||||
|
||||
package aws
|
||||
|
||||
// ClientLogMode represents the logging mode of SDK clients. The client logging mode is a bit-field where
|
||||
// each bit is a flag that describes the logging behavior for one or more client components.
|
||||
// The entire 64-bit group is reserved for later expansion by the SDK.
|
||||
//
|
||||
// Example: Setting ClientLogMode to enable logging of retries and requests
|
||||
// clientLogMode := aws.LogRetries | aws.LogRequest
|
||||
//
|
||||
// Example: Adding an additional log mode to an existing ClientLogMode value
|
||||
// clientLogMode |= aws.LogResponse
|
||||
type ClientLogMode uint64
|
||||
|
||||
// Supported ClientLogMode bits that can be configured to toggle logging of specific SDK events.
|
||||
const (
|
||||
{{- range $index, $field := .ModeBits }}
|
||||
{{ (symbolName $field) }}{{- if (eq 0 $index) }} ClientLogMode = 1 << (64 - 1 - iota){{- end }}
|
||||
{{- end }}
|
||||
)
|
||||
{{ range $_, $field := .ModeBits }}
|
||||
// Is{{- bitName $field }} returns whether the {{ bitName $field }} logging mode bit is set
|
||||
func (m ClientLogMode) Is{{- bitName $field }}() bool {
|
||||
return m&{{- (symbolName $field) }} != 0
|
||||
}
|
||||
{{ end }}
|
||||
{{- range $_, $field := .ModeBits }}
|
||||
// Clear{{- bitName $field }} clears the {{ bitName $field }} logging mode bit
|
||||
func (m *ClientLogMode) Clear{{- bitName $field }}() {
|
||||
*m &^= {{ (symbolName $field) }}
|
||||
}
|
||||
{{ end -}}
|
||||
`))
|
||||
|
||||
func main() {
|
||||
uniqueBitFields := make(map[string]struct{})
|
||||
|
||||
for _, bitName := range config.ModeBits {
|
||||
if _, ok := uniqueBitFields[strings.ToLower(bitName)]; ok {
|
||||
panic(fmt.Sprintf("duplicate bit field: %s", bitName))
|
||||
}
|
||||
uniqueBitFields[bitName] = struct{}{}
|
||||
}
|
||||
|
||||
file, err := os.Create("logging.go")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
err = tmpl.Execute(file, config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
213
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/metadata.go
generated
vendored
Normal file
213
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/metadata.go
generated
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
)
|
||||
|
||||
// RegisterServiceMetadata registers metadata about the service and operation into the middleware context
|
||||
// so that it is available at runtime for other middleware to introspect.
|
||||
type RegisterServiceMetadata struct {
|
||||
ServiceID string
|
||||
SigningName string
|
||||
Region string
|
||||
OperationName string
|
||||
}
|
||||
|
||||
// ID returns the middleware identifier.
|
||||
func (s *RegisterServiceMetadata) ID() string {
|
||||
return "RegisterServiceMetadata"
|
||||
}
|
||||
|
||||
// HandleInitialize registers service metadata information into the middleware context, allowing for introspection.
|
||||
func (s RegisterServiceMetadata) HandleInitialize(
|
||||
ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler,
|
||||
) (out middleware.InitializeOutput, metadata middleware.Metadata, err error) {
|
||||
if len(s.ServiceID) > 0 {
|
||||
ctx = SetServiceID(ctx, s.ServiceID)
|
||||
}
|
||||
if len(s.SigningName) > 0 {
|
||||
ctx = SetSigningName(ctx, s.SigningName)
|
||||
}
|
||||
if len(s.Region) > 0 {
|
||||
ctx = setRegion(ctx, s.Region)
|
||||
}
|
||||
if len(s.OperationName) > 0 {
|
||||
ctx = setOperationName(ctx, s.OperationName)
|
||||
}
|
||||
return next.HandleInitialize(ctx, in)
|
||||
}
|
||||
|
||||
// service metadata keys for storing and lookup of runtime stack information.
|
||||
type (
|
||||
serviceIDKey struct{}
|
||||
signingNameKey struct{}
|
||||
signingRegionKey struct{}
|
||||
regionKey struct{}
|
||||
operationNameKey struct{}
|
||||
partitionIDKey struct{}
|
||||
requiresLegacyEndpointsKey struct{}
|
||||
)
|
||||
|
||||
// GetServiceID retrieves the service id from the context.
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
func GetServiceID(ctx context.Context) (v string) {
|
||||
v, _ = middleware.GetStackValue(ctx, serviceIDKey{}).(string)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetSigningName retrieves the service signing name from the context.
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
//
|
||||
// Deprecated: This value is unstable. The resolved signing name is available
|
||||
// in the signer properties object passed to the signer.
|
||||
func GetSigningName(ctx context.Context) (v string) {
|
||||
v, _ = middleware.GetStackValue(ctx, signingNameKey{}).(string)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetSigningRegion retrieves the region from the context.
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
//
|
||||
// Deprecated: This value is unstable. The resolved signing region is available
|
||||
// in the signer properties object passed to the signer.
|
||||
func GetSigningRegion(ctx context.Context) (v string) {
|
||||
v, _ = middleware.GetStackValue(ctx, signingRegionKey{}).(string)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetRegion retrieves the endpoint region from the context.
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
func GetRegion(ctx context.Context) (v string) {
|
||||
v, _ = middleware.GetStackValue(ctx, regionKey{}).(string)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetOperationName retrieves the service operation metadata from the context.
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
func GetOperationName(ctx context.Context) (v string) {
|
||||
v, _ = middleware.GetStackValue(ctx, operationNameKey{}).(string)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetPartitionID retrieves the endpoint partition id from the context.
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
func GetPartitionID(ctx context.Context) string {
|
||||
v, _ := middleware.GetStackValue(ctx, partitionIDKey{}).(string)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetRequiresLegacyEndpoints the flag used to indicate if legacy endpoint
|
||||
// customizations need to be executed.
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
func GetRequiresLegacyEndpoints(ctx context.Context) bool {
|
||||
v, _ := middleware.GetStackValue(ctx, requiresLegacyEndpointsKey{}).(bool)
|
||||
return v
|
||||
}
|
||||
|
||||
// SetRequiresLegacyEndpoints set or modifies the flag indicated that
|
||||
// legacy endpoint customizations are needed.
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
func SetRequiresLegacyEndpoints(ctx context.Context, value bool) context.Context {
|
||||
return middleware.WithStackValue(ctx, requiresLegacyEndpointsKey{}, value)
|
||||
}
|
||||
|
||||
// SetSigningName set or modifies the sigv4 or sigv4a signing name on the context.
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
//
|
||||
// Deprecated: This value is unstable. Use WithSigV4SigningName client option
|
||||
// funcs instead.
|
||||
func SetSigningName(ctx context.Context, value string) context.Context {
|
||||
return middleware.WithStackValue(ctx, signingNameKey{}, value)
|
||||
}
|
||||
|
||||
// SetSigningRegion sets or modifies the region on the context.
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
//
|
||||
// Deprecated: This value is unstable. Use WithSigV4SigningRegion client option
|
||||
// funcs instead.
|
||||
func SetSigningRegion(ctx context.Context, value string) context.Context {
|
||||
return middleware.WithStackValue(ctx, signingRegionKey{}, value)
|
||||
}
|
||||
|
||||
// SetServiceID sets the service id on the context.
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
func SetServiceID(ctx context.Context, value string) context.Context {
|
||||
return middleware.WithStackValue(ctx, serviceIDKey{}, value)
|
||||
}
|
||||
|
||||
// setRegion sets the endpoint region on the context.
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
func setRegion(ctx context.Context, value string) context.Context {
|
||||
return middleware.WithStackValue(ctx, regionKey{}, value)
|
||||
}
|
||||
|
||||
// setOperationName sets the service operation on the context.
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
func setOperationName(ctx context.Context, value string) context.Context {
|
||||
return middleware.WithStackValue(ctx, operationNameKey{}, value)
|
||||
}
|
||||
|
||||
// SetPartitionID sets the partition id of a resolved region on the context
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
func SetPartitionID(ctx context.Context, value string) context.Context {
|
||||
return middleware.WithStackValue(ctx, partitionIDKey{}, value)
|
||||
}
|
||||
|
||||
// EndpointSource key
|
||||
type endpointSourceKey struct{}
|
||||
|
||||
// GetEndpointSource returns an endpoint source if set on context
|
||||
func GetEndpointSource(ctx context.Context) (v aws.EndpointSource) {
|
||||
v, _ = middleware.GetStackValue(ctx, endpointSourceKey{}).(aws.EndpointSource)
|
||||
return v
|
||||
}
|
||||
|
||||
// SetEndpointSource sets endpoint source on context
|
||||
func SetEndpointSource(ctx context.Context, value aws.EndpointSource) context.Context {
|
||||
return middleware.WithStackValue(ctx, endpointSourceKey{}, value)
|
||||
}
|
||||
|
||||
type signingCredentialsKey struct{}
|
||||
|
||||
// GetSigningCredentials returns the credentials that were used for signing if set on context.
|
||||
func GetSigningCredentials(ctx context.Context) (v aws.Credentials) {
|
||||
v, _ = middleware.GetStackValue(ctx, signingCredentialsKey{}).(aws.Credentials)
|
||||
return v
|
||||
}
|
||||
|
||||
// SetSigningCredentials sets the credentails used for signing on the context.
|
||||
func SetSigningCredentials(ctx context.Context, value aws.Credentials) context.Context {
|
||||
return middleware.WithStackValue(ctx, signingCredentialsKey{}, value)
|
||||
}
|
||||
168
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/middleware.go
generated
vendored
Normal file
168
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/middleware.go
generated
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/internal/rand"
|
||||
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
||||
"github.com/aws/smithy-go/logging"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
smithyrand "github.com/aws/smithy-go/rand"
|
||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
)
|
||||
|
||||
// ClientRequestID is a Smithy BuildMiddleware that will generate a unique ID for logical API operation
|
||||
// invocation.
|
||||
type ClientRequestID struct{}
|
||||
|
||||
// ID the identifier for the ClientRequestID
|
||||
func (r *ClientRequestID) ID() string {
|
||||
return "ClientRequestID"
|
||||
}
|
||||
|
||||
// HandleBuild attaches a unique operation invocation id for the operation to the request
|
||||
func (r ClientRequestID) HandleBuild(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) (
|
||||
out middleware.BuildOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
req, ok := in.Request.(*smithyhttp.Request)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("unknown transport type %T", req)
|
||||
}
|
||||
|
||||
invocationID, err := smithyrand.NewUUID(rand.Reader).GetUUID()
|
||||
if err != nil {
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
const invocationIDHeader = "Amz-Sdk-Invocation-Id"
|
||||
req.Header[invocationIDHeader] = append(req.Header[invocationIDHeader][:0], invocationID)
|
||||
|
||||
return next.HandleBuild(ctx, in)
|
||||
}
|
||||
|
||||
// RecordResponseTiming records the response timing for the SDK client requests.
|
||||
type RecordResponseTiming struct{}
|
||||
|
||||
// ID is the middleware identifier
|
||||
func (a *RecordResponseTiming) ID() string {
|
||||
return "RecordResponseTiming"
|
||||
}
|
||||
|
||||
// HandleDeserialize calculates response metadata and clock skew
|
||||
func (a RecordResponseTiming) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) (
|
||||
out middleware.DeserializeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
out, metadata, err = next.HandleDeserialize(ctx, in)
|
||||
responseAt := sdk.NowTime()
|
||||
setResponseAt(&metadata, responseAt)
|
||||
|
||||
var serverTime time.Time
|
||||
|
||||
switch resp := out.RawResponse.(type) {
|
||||
case *smithyhttp.Response:
|
||||
respDateHeader := resp.Header.Get("Date")
|
||||
if len(respDateHeader) == 0 {
|
||||
break
|
||||
}
|
||||
var parseErr error
|
||||
serverTime, parseErr = smithyhttp.ParseTime(respDateHeader)
|
||||
if parseErr != nil {
|
||||
logger := middleware.GetLogger(ctx)
|
||||
logger.Logf(logging.Warn, "failed to parse response Date header value, got %v",
|
||||
parseErr.Error())
|
||||
break
|
||||
}
|
||||
setServerTime(&metadata, serverTime)
|
||||
}
|
||||
|
||||
if !serverTime.IsZero() {
|
||||
attemptSkew := serverTime.Sub(responseAt)
|
||||
setAttemptSkew(&metadata, attemptSkew)
|
||||
}
|
||||
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
type responseAtKey struct{}
|
||||
|
||||
// GetResponseAt returns the time response was received at.
|
||||
func GetResponseAt(metadata middleware.Metadata) (v time.Time, ok bool) {
|
||||
v, ok = metadata.Get(responseAtKey{}).(time.Time)
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// setResponseAt sets the response time on the metadata.
|
||||
func setResponseAt(metadata *middleware.Metadata, v time.Time) {
|
||||
metadata.Set(responseAtKey{}, v)
|
||||
}
|
||||
|
||||
type serverTimeKey struct{}
|
||||
|
||||
// GetServerTime returns the server time for response.
|
||||
func GetServerTime(metadata middleware.Metadata) (v time.Time, ok bool) {
|
||||
v, ok = metadata.Get(serverTimeKey{}).(time.Time)
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// setServerTime sets the server time on the metadata.
|
||||
func setServerTime(metadata *middleware.Metadata, v time.Time) {
|
||||
metadata.Set(serverTimeKey{}, v)
|
||||
}
|
||||
|
||||
type attemptSkewKey struct{}
|
||||
|
||||
// GetAttemptSkew returns Attempt clock skew for response from metadata.
|
||||
func GetAttemptSkew(metadata middleware.Metadata) (v time.Duration, ok bool) {
|
||||
v, ok = metadata.Get(attemptSkewKey{}).(time.Duration)
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// setAttemptSkew sets the attempt clock skew on the metadata.
|
||||
func setAttemptSkew(metadata *middleware.Metadata, v time.Duration) {
|
||||
metadata.Set(attemptSkewKey{}, v)
|
||||
}
|
||||
|
||||
// AddClientRequestIDMiddleware adds ClientRequestID to the middleware stack
|
||||
func AddClientRequestIDMiddleware(stack *middleware.Stack) error {
|
||||
return stack.Build.Add(&ClientRequestID{}, middleware.After)
|
||||
}
|
||||
|
||||
// AddRecordResponseTiming adds RecordResponseTiming middleware to the
|
||||
// middleware stack.
|
||||
func AddRecordResponseTiming(stack *middleware.Stack) error {
|
||||
return stack.Deserialize.Add(&RecordResponseTiming{}, middleware.After)
|
||||
}
|
||||
|
||||
// rawResponseKey is the accessor key used to store and access the
|
||||
// raw response within the response metadata.
|
||||
type rawResponseKey struct{}
|
||||
|
||||
// AddRawResponse middleware adds raw response on to the metadata
|
||||
type AddRawResponse struct{}
|
||||
|
||||
// ID the identifier for the ClientRequestID
|
||||
func (m *AddRawResponse) ID() string {
|
||||
return "AddRawResponseToMetadata"
|
||||
}
|
||||
|
||||
// HandleDeserialize adds raw response on the middleware metadata
|
||||
func (m AddRawResponse) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) (
|
||||
out middleware.DeserializeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
out, metadata, err = next.HandleDeserialize(ctx, in)
|
||||
metadata.Set(rawResponseKey{}, out.RawResponse)
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
// AddRawResponseToMetadata adds middleware to the middleware stack that
|
||||
// store raw response on to the metadata.
|
||||
func AddRawResponseToMetadata(stack *middleware.Stack) error {
|
||||
return stack.Deserialize.Add(&AddRawResponse{}, middleware.Before)
|
||||
}
|
||||
|
||||
// GetRawResponse returns raw response set on metadata
|
||||
func GetRawResponse(metadata middleware.Metadata) interface{} {
|
||||
return metadata.Get(rawResponseKey{})
|
||||
}
|
||||
24
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/osname.go
generated
vendored
Normal file
24
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/osname.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
//go:build go1.16
|
||||
// +build go1.16
|
||||
|
||||
package middleware
|
||||
|
||||
import "runtime"
|
||||
|
||||
func getNormalizedOSName() (os string) {
|
||||
switch runtime.GOOS {
|
||||
case "android":
|
||||
os = "android"
|
||||
case "linux":
|
||||
os = "linux"
|
||||
case "windows":
|
||||
os = "windows"
|
||||
case "darwin":
|
||||
os = "macos"
|
||||
case "ios":
|
||||
os = "ios"
|
||||
default:
|
||||
os = "other"
|
||||
}
|
||||
return os
|
||||
}
|
||||
24
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/osname_go115.go
generated
vendored
Normal file
24
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/osname_go115.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
//go:build !go1.16
|
||||
// +build !go1.16
|
||||
|
||||
package middleware
|
||||
|
||||
import "runtime"
|
||||
|
||||
func getNormalizedOSName() (os string) {
|
||||
switch runtime.GOOS {
|
||||
case "android":
|
||||
os = "android"
|
||||
case "linux":
|
||||
os = "linux"
|
||||
case "windows":
|
||||
os = "windows"
|
||||
case "darwin":
|
||||
// Due to Apple M1 we can't distinguish between macOS and iOS when GOOS/GOARCH is darwin/amd64
|
||||
// For now declare this as "other" until we have a better detection mechanism.
|
||||
fallthrough
|
||||
default:
|
||||
os = "other"
|
||||
}
|
||||
return os
|
||||
}
|
||||
94
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/recursion_detection.go
generated
vendored
Normal file
94
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/recursion_detection.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
const envAwsLambdaFunctionName = "AWS_LAMBDA_FUNCTION_NAME"
|
||||
const envAmznTraceID = "_X_AMZN_TRACE_ID"
|
||||
const amznTraceIDHeader = "X-Amzn-Trace-Id"
|
||||
|
||||
// AddRecursionDetection adds recursionDetection to the middleware stack
|
||||
func AddRecursionDetection(stack *middleware.Stack) error {
|
||||
return stack.Build.Add(&RecursionDetection{}, middleware.After)
|
||||
}
|
||||
|
||||
// RecursionDetection detects Lambda environment and sets its X-Ray trace ID to request header if absent
|
||||
// to avoid recursion invocation in Lambda
|
||||
type RecursionDetection struct{}
|
||||
|
||||
// ID returns the middleware identifier
|
||||
func (m *RecursionDetection) ID() string {
|
||||
return "RecursionDetection"
|
||||
}
|
||||
|
||||
// HandleBuild detects Lambda environment and adds its trace ID to request header if absent
|
||||
func (m *RecursionDetection) HandleBuild(
|
||||
ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler,
|
||||
) (
|
||||
out middleware.BuildOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
req, ok := in.Request.(*smithyhttp.Request)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("unknown request type %T", req)
|
||||
}
|
||||
|
||||
_, hasLambdaEnv := os.LookupEnv(envAwsLambdaFunctionName)
|
||||
xAmznTraceID, hasTraceID := os.LookupEnv(envAmznTraceID)
|
||||
value := req.Header.Get(amznTraceIDHeader)
|
||||
// only set the X-Amzn-Trace-Id header when it is not set initially, the
|
||||
// current environment is Lambda and the _X_AMZN_TRACE_ID env variable exists
|
||||
if value != "" || !hasLambdaEnv || !hasTraceID {
|
||||
return next.HandleBuild(ctx, in)
|
||||
}
|
||||
|
||||
req.Header.Set(amznTraceIDHeader, percentEncode(xAmznTraceID))
|
||||
return next.HandleBuild(ctx, in)
|
||||
}
|
||||
|
||||
func percentEncode(s string) string {
|
||||
upperhex := "0123456789ABCDEF"
|
||||
hexCount := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if shouldEncode(c) {
|
||||
hexCount++
|
||||
}
|
||||
}
|
||||
|
||||
if hexCount == 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
required := len(s) + 2*hexCount
|
||||
t := make([]byte, required)
|
||||
j := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
if c := s[i]; shouldEncode(c) {
|
||||
t[j] = '%'
|
||||
t[j+1] = upperhex[c>>4]
|
||||
t[j+2] = upperhex[c&15]
|
||||
j += 3
|
||||
} else {
|
||||
t[j] = c
|
||||
j++
|
||||
}
|
||||
}
|
||||
return string(t)
|
||||
}
|
||||
|
||||
func shouldEncode(c byte) bool {
|
||||
if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
|
||||
return false
|
||||
}
|
||||
switch c {
|
||||
case '-', '=', ';', ':', '+', '&', '[', ']', '{', '}', '"', '\'', ',':
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
27
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/request_id.go
generated
vendored
Normal file
27
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/request_id.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
)
|
||||
|
||||
// requestIDKey is used to retrieve request id from response metadata
|
||||
type requestIDKey struct{}
|
||||
|
||||
// SetRequestIDMetadata sets the provided request id over middleware metadata
|
||||
func SetRequestIDMetadata(metadata *middleware.Metadata, id string) {
|
||||
metadata.Set(requestIDKey{}, id)
|
||||
}
|
||||
|
||||
// GetRequestIDMetadata retrieves the request id from middleware metadata
|
||||
// returns string and bool indicating value of request id, whether request id was set.
|
||||
func GetRequestIDMetadata(metadata middleware.Metadata) (string, bool) {
|
||||
if !metadata.Has(requestIDKey{}) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
v, ok := metadata.Get(requestIDKey{}).(string)
|
||||
if !ok {
|
||||
return "", true
|
||||
}
|
||||
return v, true
|
||||
}
|
||||
57
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/request_id_retriever.go
generated
vendored
Normal file
57
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/request_id_retriever.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
"github.com/aws/smithy-go/tracing"
|
||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
)
|
||||
|
||||
// AddRequestIDRetrieverMiddleware adds request id retriever middleware
|
||||
func AddRequestIDRetrieverMiddleware(stack *middleware.Stack) error {
|
||||
// add error wrapper middleware before operation deserializers so that it can wrap the error response
|
||||
// returned by operation deserializers
|
||||
return stack.Deserialize.Insert(&RequestIDRetriever{}, "OperationDeserializer", middleware.Before)
|
||||
}
|
||||
|
||||
// RequestIDRetriever middleware captures the AWS service request ID from the
|
||||
// raw response.
|
||||
type RequestIDRetriever struct {
|
||||
}
|
||||
|
||||
// ID returns the middleware identifier
|
||||
func (m *RequestIDRetriever) ID() string {
|
||||
return "RequestIDRetriever"
|
||||
}
|
||||
|
||||
// HandleDeserialize pulls the AWS request ID from the response, storing it in
|
||||
// operation metadata.
|
||||
func (m *RequestIDRetriever) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) (
|
||||
out middleware.DeserializeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
out, metadata, err = next.HandleDeserialize(ctx, in)
|
||||
|
||||
resp, ok := out.RawResponse.(*smithyhttp.Response)
|
||||
if !ok {
|
||||
// No raw response to wrap with.
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
// Different header which can map to request id
|
||||
requestIDHeaderList := []string{"X-Amzn-Requestid", "X-Amz-RequestId"}
|
||||
|
||||
for _, h := range requestIDHeaderList {
|
||||
// check for headers known to contain Request id
|
||||
if v := resp.Header.Get(h); len(v) != 0 {
|
||||
// set reqID on metadata for successful responses.
|
||||
SetRequestIDMetadata(&metadata, v)
|
||||
|
||||
span, _ := tracing.GetSpan(ctx)
|
||||
span.SetProperty("aws.request_id", v)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return out, metadata, err
|
||||
}
|
||||
391
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/user_agent.go
generated
vendored
Normal file
391
go/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/user_agent.go
generated
vendored
Normal file
@@ -0,0 +1,391 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
)
|
||||
|
||||
var languageVersion = strings.TrimPrefix(runtime.Version(), "go")
|
||||
|
||||
// SDKAgentKeyType is the metadata type to add to the SDK agent string
|
||||
type SDKAgentKeyType int
|
||||
|
||||
// The set of valid SDKAgentKeyType constants. If an unknown value is assigned for SDKAgentKeyType it will
|
||||
// be mapped to AdditionalMetadata.
|
||||
const (
|
||||
_ SDKAgentKeyType = iota
|
||||
APIMetadata
|
||||
OperatingSystemMetadata
|
||||
LanguageMetadata
|
||||
EnvironmentMetadata
|
||||
FeatureMetadata
|
||||
ConfigMetadata
|
||||
FrameworkMetadata
|
||||
AdditionalMetadata
|
||||
ApplicationIdentifier
|
||||
FeatureMetadata2
|
||||
)
|
||||
|
||||
// Hardcoded value to specify which version of the user agent we're using
|
||||
const uaMetadata = "ua/2.1"
|
||||
|
||||
func (k SDKAgentKeyType) string() string {
|
||||
switch k {
|
||||
case APIMetadata:
|
||||
return "api"
|
||||
case OperatingSystemMetadata:
|
||||
return "os"
|
||||
case LanguageMetadata:
|
||||
return "lang"
|
||||
case EnvironmentMetadata:
|
||||
return "exec-env"
|
||||
case FeatureMetadata:
|
||||
return "ft"
|
||||
case ConfigMetadata:
|
||||
return "cfg"
|
||||
case FrameworkMetadata:
|
||||
return "lib"
|
||||
case ApplicationIdentifier:
|
||||
return "app"
|
||||
case FeatureMetadata2:
|
||||
return "m"
|
||||
case AdditionalMetadata:
|
||||
fallthrough
|
||||
default:
|
||||
return "md"
|
||||
}
|
||||
}
|
||||
|
||||
const execEnvVar = `AWS_EXECUTION_ENV`
|
||||
|
||||
var validChars = map[rune]bool{
|
||||
'!': true, '#': true, '$': true, '%': true, '&': true, '\'': true, '*': true, '+': true,
|
||||
'-': true, '.': true, '^': true, '_': true, '`': true, '|': true, '~': true,
|
||||
}
|
||||
|
||||
// UserAgentFeature enumerates tracked SDK features.
|
||||
type UserAgentFeature string
|
||||
|
||||
// Enumerates UserAgentFeature.
|
||||
const (
|
||||
UserAgentFeatureResourceModel UserAgentFeature = "A" // n/a (we don't generate separate resource types)
|
||||
|
||||
UserAgentFeatureWaiter = "B"
|
||||
UserAgentFeaturePaginator = "C"
|
||||
|
||||
UserAgentFeatureRetryModeLegacy = "D" // n/a (equivalent to standard)
|
||||
UserAgentFeatureRetryModeStandard = "E"
|
||||
UserAgentFeatureRetryModeAdaptive = "F"
|
||||
|
||||
UserAgentFeatureS3Transfer = "G"
|
||||
UserAgentFeatureS3CryptoV1N = "H" // n/a (crypto client is external)
|
||||
UserAgentFeatureS3CryptoV2 = "I" // n/a
|
||||
UserAgentFeatureS3ExpressBucket = "J"
|
||||
UserAgentFeatureS3AccessGrants = "K" // not yet implemented
|
||||
|
||||
UserAgentFeatureGZIPRequestCompression = "L"
|
||||
|
||||
UserAgentFeatureProtocolRPCV2CBOR = "M"
|
||||
|
||||
UserAgentFeatureAccountIDEndpoint = "O" // DO NOT IMPLEMENT: rules output is not currently defined. SDKs should not parse endpoints for feature information.
|
||||
UserAgentFeatureAccountIDModePreferred = "P"
|
||||
UserAgentFeatureAccountIDModeDisabled = "Q"
|
||||
UserAgentFeatureAccountIDModeRequired = "R"
|
||||
|
||||
UserAgentFeatureRequestChecksumCRC32 = "U"
|
||||
UserAgentFeatureRequestChecksumCRC32C = "V"
|
||||
UserAgentFeatureRequestChecksumCRC64 = "W"
|
||||
UserAgentFeatureRequestChecksumSHA1 = "X"
|
||||
UserAgentFeatureRequestChecksumSHA256 = "Y"
|
||||
UserAgentFeatureRequestChecksumWhenSupported = "Z"
|
||||
UserAgentFeatureRequestChecksumWhenRequired = "a"
|
||||
UserAgentFeatureResponseChecksumWhenSupported = "b"
|
||||
UserAgentFeatureResponseChecksumWhenRequired = "c"
|
||||
|
||||
UserAgentFeatureDynamoDBUserAgent = "d" // not yet implemented
|
||||
|
||||
UserAgentFeatureCredentialsCode = "e"
|
||||
UserAgentFeatureCredentialsJvmSystemProperties = "f" // n/a (this is not a JVM sdk)
|
||||
UserAgentFeatureCredentialsEnvVars = "g"
|
||||
UserAgentFeatureCredentialsEnvVarsStsWebIDToken = "h"
|
||||
UserAgentFeatureCredentialsStsAssumeRole = "i"
|
||||
UserAgentFeatureCredentialsStsAssumeRoleSaml = "j" // not yet implemented
|
||||
UserAgentFeatureCredentialsStsAssumeRoleWebID = "k"
|
||||
UserAgentFeatureCredentialsStsFederationToken = "l" // not yet implemented
|
||||
UserAgentFeatureCredentialsStsSessionToken = "m" // not yet implemented
|
||||
UserAgentFeatureCredentialsProfile = "n"
|
||||
UserAgentFeatureCredentialsProfileSourceProfile = "o"
|
||||
UserAgentFeatureCredentialsProfileNamedProvider = "p"
|
||||
UserAgentFeatureCredentialsProfileStsWebIDToken = "q"
|
||||
UserAgentFeatureCredentialsProfileSso = "r"
|
||||
UserAgentFeatureCredentialsSso = "s"
|
||||
UserAgentFeatureCredentialsProfileSsoLegacy = "t"
|
||||
UserAgentFeatureCredentialsSsoLegacy = "u"
|
||||
UserAgentFeatureCredentialsProfileProcess = "v"
|
||||
UserAgentFeatureCredentialsProcess = "w"
|
||||
UserAgentFeatureCredentialsBoto2ConfigFile = "x" // n/a (this is not boto/Python)
|
||||
UserAgentFeatureCredentialsAwsSdkStore = "y" // n/a (this is used by .NET based sdk)
|
||||
UserAgentFeatureCredentialsHTTP = "z"
|
||||
UserAgentFeatureCredentialsIMDS = "0"
|
||||
)
|
||||
|
||||
var credentialSourceToFeature = map[aws.CredentialSource]UserAgentFeature{
|
||||
aws.CredentialSourceCode: UserAgentFeatureCredentialsCode,
|
||||
aws.CredentialSourceEnvVars: UserAgentFeatureCredentialsEnvVars,
|
||||
aws.CredentialSourceEnvVarsSTSWebIDToken: UserAgentFeatureCredentialsEnvVarsStsWebIDToken,
|
||||
aws.CredentialSourceSTSAssumeRole: UserAgentFeatureCredentialsStsAssumeRole,
|
||||
aws.CredentialSourceSTSAssumeRoleSaml: UserAgentFeatureCredentialsStsAssumeRoleSaml,
|
||||
aws.CredentialSourceSTSAssumeRoleWebID: UserAgentFeatureCredentialsStsAssumeRoleWebID,
|
||||
aws.CredentialSourceSTSFederationToken: UserAgentFeatureCredentialsStsFederationToken,
|
||||
aws.CredentialSourceSTSSessionToken: UserAgentFeatureCredentialsStsSessionToken,
|
||||
aws.CredentialSourceProfile: UserAgentFeatureCredentialsProfile,
|
||||
aws.CredentialSourceProfileSourceProfile: UserAgentFeatureCredentialsProfileSourceProfile,
|
||||
aws.CredentialSourceProfileNamedProvider: UserAgentFeatureCredentialsProfileNamedProvider,
|
||||
aws.CredentialSourceProfileSTSWebIDToken: UserAgentFeatureCredentialsProfileStsWebIDToken,
|
||||
aws.CredentialSourceProfileSSO: UserAgentFeatureCredentialsProfileSso,
|
||||
aws.CredentialSourceSSO: UserAgentFeatureCredentialsSso,
|
||||
aws.CredentialSourceProfileSSOLegacy: UserAgentFeatureCredentialsProfileSsoLegacy,
|
||||
aws.CredentialSourceSSOLegacy: UserAgentFeatureCredentialsSsoLegacy,
|
||||
aws.CredentialSourceProfileProcess: UserAgentFeatureCredentialsProfileProcess,
|
||||
aws.CredentialSourceProcess: UserAgentFeatureCredentialsProcess,
|
||||
aws.CredentialSourceHTTP: UserAgentFeatureCredentialsHTTP,
|
||||
aws.CredentialSourceIMDS: UserAgentFeatureCredentialsIMDS,
|
||||
}
|
||||
|
||||
// RequestUserAgent is a build middleware that set the User-Agent for the request.
|
||||
type RequestUserAgent struct {
|
||||
sdkAgent, userAgent *smithyhttp.UserAgentBuilder
|
||||
features map[UserAgentFeature]struct{}
|
||||
}
|
||||
|
||||
// NewRequestUserAgent returns a new requestUserAgent which will set the User-Agent and X-Amz-User-Agent for the
|
||||
// request.
|
||||
//
|
||||
// User-Agent example:
|
||||
//
|
||||
// aws-sdk-go-v2/1.2.3
|
||||
//
|
||||
// X-Amz-User-Agent example:
|
||||
//
|
||||
// aws-sdk-go-v2/1.2.3 md/GOOS/linux md/GOARCH/amd64 lang/go/1.15
|
||||
func NewRequestUserAgent() *RequestUserAgent {
|
||||
userAgent, sdkAgent := smithyhttp.NewUserAgentBuilder(), smithyhttp.NewUserAgentBuilder()
|
||||
addProductName(userAgent)
|
||||
addUserAgentMetadata(userAgent)
|
||||
addProductName(sdkAgent)
|
||||
|
||||
r := &RequestUserAgent{
|
||||
sdkAgent: sdkAgent,
|
||||
userAgent: userAgent,
|
||||
features: map[UserAgentFeature]struct{}{},
|
||||
}
|
||||
|
||||
addSDKMetadata(r)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func addSDKMetadata(r *RequestUserAgent) {
|
||||
r.AddSDKAgentKey(OperatingSystemMetadata, getNormalizedOSName())
|
||||
r.AddSDKAgentKeyValue(LanguageMetadata, "go", languageVersion)
|
||||
r.AddSDKAgentKeyValue(AdditionalMetadata, "GOOS", runtime.GOOS)
|
||||
r.AddSDKAgentKeyValue(AdditionalMetadata, "GOARCH", runtime.GOARCH)
|
||||
if ev := os.Getenv(execEnvVar); len(ev) > 0 {
|
||||
r.AddSDKAgentKey(EnvironmentMetadata, ev)
|
||||
}
|
||||
}
|
||||
|
||||
func addProductName(builder *smithyhttp.UserAgentBuilder) {
|
||||
builder.AddKeyValue(aws.SDKName, aws.SDKVersion)
|
||||
}
|
||||
|
||||
func addUserAgentMetadata(builder *smithyhttp.UserAgentBuilder) {
|
||||
builder.AddKey(uaMetadata)
|
||||
}
|
||||
|
||||
// AddUserAgentKey retrieves a requestUserAgent from the provided stack, or initializes one.
|
||||
func AddUserAgentKey(key string) func(*middleware.Stack) error {
|
||||
return func(stack *middleware.Stack) error {
|
||||
requestUserAgent, err := getOrAddRequestUserAgent(stack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
requestUserAgent.AddUserAgentKey(key)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// AddUserAgentKeyValue retrieves a requestUserAgent from the provided stack, or initializes one.
|
||||
func AddUserAgentKeyValue(key, value string) func(*middleware.Stack) error {
|
||||
return func(stack *middleware.Stack) error {
|
||||
requestUserAgent, err := getOrAddRequestUserAgent(stack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
requestUserAgent.AddUserAgentKeyValue(key, value)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// AddSDKAgentKey retrieves a requestUserAgent from the provided stack, or initializes one.
|
||||
func AddSDKAgentKey(keyType SDKAgentKeyType, key string) func(*middleware.Stack) error {
|
||||
return func(stack *middleware.Stack) error {
|
||||
requestUserAgent, err := getOrAddRequestUserAgent(stack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
requestUserAgent.AddSDKAgentKey(keyType, key)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// AddSDKAgentKeyValue retrieves a requestUserAgent from the provided stack, or initializes one.
|
||||
func AddSDKAgentKeyValue(keyType SDKAgentKeyType, key, value string) func(*middleware.Stack) error {
|
||||
return func(stack *middleware.Stack) error {
|
||||
requestUserAgent, err := getOrAddRequestUserAgent(stack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
requestUserAgent.AddSDKAgentKeyValue(keyType, key, value)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// AddRequestUserAgentMiddleware registers a requestUserAgent middleware on the stack if not present.
|
||||
func AddRequestUserAgentMiddleware(stack *middleware.Stack) error {
|
||||
_, err := getOrAddRequestUserAgent(stack)
|
||||
return err
|
||||
}
|
||||
|
||||
func getOrAddRequestUserAgent(stack *middleware.Stack) (*RequestUserAgent, error) {
|
||||
id := (*RequestUserAgent)(nil).ID()
|
||||
bm, ok := stack.Build.Get(id)
|
||||
if !ok {
|
||||
bm = NewRequestUserAgent()
|
||||
err := stack.Build.Add(bm, middleware.After)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
requestUserAgent, ok := bm.(*RequestUserAgent)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%T for %s middleware did not match expected type", bm, id)
|
||||
}
|
||||
|
||||
return requestUserAgent, nil
|
||||
}
|
||||
|
||||
// AddUserAgentKey adds the component identified by name to the User-Agent string.
|
||||
func (u *RequestUserAgent) AddUserAgentKey(key string) {
|
||||
u.userAgent.AddKey(strings.Map(rules, key))
|
||||
}
|
||||
|
||||
// AddUserAgentKeyValue adds the key identified by the given name and value to the User-Agent string.
|
||||
func (u *RequestUserAgent) AddUserAgentKeyValue(key, value string) {
|
||||
u.userAgent.AddKeyValue(strings.Map(rules, key), strings.Map(rules, value))
|
||||
}
|
||||
|
||||
// AddUserAgentFeature adds the feature ID to the tracking list to be emitted
|
||||
// in the final User-Agent string.
|
||||
func (u *RequestUserAgent) AddUserAgentFeature(feature UserAgentFeature) {
|
||||
u.features[feature] = struct{}{}
|
||||
}
|
||||
|
||||
// AddSDKAgentKey adds the component identified by name to the User-Agent string.
|
||||
func (u *RequestUserAgent) AddSDKAgentKey(keyType SDKAgentKeyType, key string) {
|
||||
// TODO: should target sdkAgent
|
||||
u.userAgent.AddKey(keyType.string() + "/" + strings.Map(rules, key))
|
||||
}
|
||||
|
||||
// AddSDKAgentKeyValue adds the key identified by the given name and value to the User-Agent string.
|
||||
func (u *RequestUserAgent) AddSDKAgentKeyValue(keyType SDKAgentKeyType, key, value string) {
|
||||
// TODO: should target sdkAgent
|
||||
u.userAgent.AddKeyValue(keyType.string(), strings.Map(rules, key)+"#"+strings.Map(rules, value))
|
||||
}
|
||||
|
||||
// AddCredentialsSource adds the credential source as a feature on the User-Agent string
|
||||
func (u *RequestUserAgent) AddCredentialsSource(source aws.CredentialSource) {
|
||||
x, ok := credentialSourceToFeature[source]
|
||||
if ok {
|
||||
u.AddUserAgentFeature(x)
|
||||
}
|
||||
}
|
||||
|
||||
// ID the name of the middleware.
|
||||
func (u *RequestUserAgent) ID() string {
|
||||
return "UserAgent"
|
||||
}
|
||||
|
||||
// HandleBuild adds or appends the constructed user agent to the request.
|
||||
func (u *RequestUserAgent) HandleBuild(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) (
|
||||
out middleware.BuildOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
switch req := in.Request.(type) {
|
||||
case *smithyhttp.Request:
|
||||
u.addHTTPUserAgent(req)
|
||||
// TODO: To be re-enabled
|
||||
// u.addHTTPSDKAgent(req)
|
||||
default:
|
||||
return out, metadata, fmt.Errorf("unknown transport type %T", in)
|
||||
}
|
||||
|
||||
return next.HandleBuild(ctx, in)
|
||||
}
|
||||
|
||||
func (u *RequestUserAgent) addHTTPUserAgent(request *smithyhttp.Request) {
|
||||
const userAgent = "User-Agent"
|
||||
if len(u.features) > 0 {
|
||||
updateHTTPHeader(request, userAgent, buildFeatureMetrics(u.features))
|
||||
}
|
||||
updateHTTPHeader(request, userAgent, u.userAgent.Build())
|
||||
}
|
||||
|
||||
func (u *RequestUserAgent) addHTTPSDKAgent(request *smithyhttp.Request) {
|
||||
const sdkAgent = "X-Amz-User-Agent"
|
||||
updateHTTPHeader(request, sdkAgent, u.sdkAgent.Build())
|
||||
}
|
||||
|
||||
func updateHTTPHeader(request *smithyhttp.Request, header string, value string) {
|
||||
var current string
|
||||
if v := request.Header[header]; len(v) > 0 {
|
||||
current = v[0]
|
||||
}
|
||||
if len(current) > 0 {
|
||||
current = value + " " + current
|
||||
} else {
|
||||
current = value
|
||||
}
|
||||
request.Header[header] = append(request.Header[header][:0], current)
|
||||
}
|
||||
|
||||
func rules(r rune) rune {
|
||||
switch {
|
||||
case r >= '0' && r <= '9':
|
||||
return r
|
||||
case r >= 'A' && r <= 'Z' || r >= 'a' && r <= 'z':
|
||||
return r
|
||||
case validChars[r]:
|
||||
return r
|
||||
default:
|
||||
return '-'
|
||||
}
|
||||
}
|
||||
|
||||
func buildFeatureMetrics(features map[UserAgentFeature]struct{}) string {
|
||||
fs := make([]string, 0, len(features))
|
||||
for f := range features {
|
||||
fs = append(fs, string(f))
|
||||
}
|
||||
|
||||
sort.Strings(fs)
|
||||
return fmt.Sprintf("%s/%s", FeatureMetadata2.string(), strings.Join(fs, ","))
|
||||
}
|
||||
142
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/CHANGELOG.md
generated
vendored
Normal file
142
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
# v1.6.10 (2025-02-18)
|
||||
|
||||
* **Bug Fix**: Bump go version to 1.22
|
||||
|
||||
# v1.6.9 (2025-02-14)
|
||||
|
||||
* **Bug Fix**: Remove max limit on event stream messages
|
||||
|
||||
# v1.6.8 (2025-01-24)
|
||||
|
||||
* **Dependency Update**: Upgrade to smithy-go v1.22.2.
|
||||
|
||||
# v1.6.7 (2024-11-18)
|
||||
|
||||
* **Dependency Update**: Update to smithy-go v1.22.1.
|
||||
|
||||
# v1.6.6 (2024-10-04)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.6.5 (2024-09-20)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.6.4 (2024-08-15)
|
||||
|
||||
* **Dependency Update**: Bump minimum Go version to 1.21.
|
||||
|
||||
# v1.6.3 (2024-06-28)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.6.2 (2024-03-29)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.6.1 (2024-02-21)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.6.0 (2024-02-13)
|
||||
|
||||
* **Feature**: Bump minimum Go version to 1.20 per our language support policy.
|
||||
|
||||
# v1.5.4 (2023-12-07)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.5.3 (2023-11-30)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.5.2 (2023-11-29)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.5.1 (2023-11-15)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.5.0 (2023-10-31)
|
||||
|
||||
* **Feature**: **BREAKING CHANGE**: Bump minimum go version to 1.19 per the revised [go version support policy](https://aws.amazon.com/blogs/developer/aws-sdk-for-go-aligns-with-go-release-policy-on-supported-runtimes/).
|
||||
|
||||
# v1.4.14 (2023-10-06)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.13 (2023-08-18)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.12 (2023-08-07)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.11 (2023-07-31)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.10 (2022-12-02)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.9 (2022-10-24)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.8 (2022-09-14)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.7 (2022-09-02)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.6 (2022-08-31)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.5 (2022-08-29)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.4 (2022-08-09)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.3 (2022-06-29)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.2 (2022-06-07)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.1 (2022-03-24)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.0 (2022-03-08)
|
||||
|
||||
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||
|
||||
# v1.3.0 (2022-02-24)
|
||||
|
||||
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||
|
||||
# v1.2.0 (2022-01-14)
|
||||
|
||||
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||
|
||||
# v1.1.0 (2022-01-07)
|
||||
|
||||
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||
|
||||
# v1.0.0 (2021-11-06)
|
||||
|
||||
* **Announcement**: Support has been added for AWS EventStream APIs for Kinesis, S3, and Transcribe Streaming. Support for the Lex Runtime V2 EventStream API will be added in a future release.
|
||||
* **Release**: Protocol support has been added for AWS event stream.
|
||||
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||
|
||||
202
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/LICENSE.txt
generated
vendored
Normal file
202
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
144
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/debug.go
generated
vendored
Normal file
144
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/debug.go
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
package eventstream
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type decodedMessage struct {
|
||||
rawMessage
|
||||
Headers decodedHeaders `json:"headers"`
|
||||
}
|
||||
type jsonMessage struct {
|
||||
Length json.Number `json:"total_length"`
|
||||
HeadersLen json.Number `json:"headers_length"`
|
||||
PreludeCRC json.Number `json:"prelude_crc"`
|
||||
Headers decodedHeaders `json:"headers"`
|
||||
Payload []byte `json:"payload"`
|
||||
CRC json.Number `json:"message_crc"`
|
||||
}
|
||||
|
||||
func (d *decodedMessage) UnmarshalJSON(b []byte) (err error) {
|
||||
var jsonMsg jsonMessage
|
||||
if err = json.Unmarshal(b, &jsonMsg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Length, err = numAsUint32(jsonMsg.Length)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.HeadersLen, err = numAsUint32(jsonMsg.HeadersLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.PreludeCRC, err = numAsUint32(jsonMsg.PreludeCRC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Headers = jsonMsg.Headers
|
||||
d.Payload = jsonMsg.Payload
|
||||
d.CRC, err = numAsUint32(jsonMsg.CRC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *decodedMessage) MarshalJSON() ([]byte, error) {
|
||||
jsonMsg := jsonMessage{
|
||||
Length: json.Number(strconv.Itoa(int(d.Length))),
|
||||
HeadersLen: json.Number(strconv.Itoa(int(d.HeadersLen))),
|
||||
PreludeCRC: json.Number(strconv.Itoa(int(d.PreludeCRC))),
|
||||
Headers: d.Headers,
|
||||
Payload: d.Payload,
|
||||
CRC: json.Number(strconv.Itoa(int(d.CRC))),
|
||||
}
|
||||
|
||||
return json.Marshal(jsonMsg)
|
||||
}
|
||||
|
||||
func numAsUint32(n json.Number) (uint32, error) {
|
||||
v, err := n.Int64()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get int64 json number, %v", err)
|
||||
}
|
||||
|
||||
return uint32(v), nil
|
||||
}
|
||||
|
||||
func (d decodedMessage) Message() Message {
|
||||
return Message{
|
||||
Headers: Headers(d.Headers),
|
||||
Payload: d.Payload,
|
||||
}
|
||||
}
|
||||
|
||||
type decodedHeaders Headers
|
||||
|
||||
func (hs *decodedHeaders) UnmarshalJSON(b []byte) error {
|
||||
var jsonHeaders []struct {
|
||||
Name string `json:"name"`
|
||||
Type valueType `json:"type"`
|
||||
Value interface{} `json:"value"`
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(bytes.NewReader(b))
|
||||
decoder.UseNumber()
|
||||
if err := decoder.Decode(&jsonHeaders); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var headers Headers
|
||||
for _, h := range jsonHeaders {
|
||||
value, err := valueFromType(h.Type, h.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
headers.Set(h.Name, value)
|
||||
}
|
||||
*hs = decodedHeaders(headers)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func valueFromType(typ valueType, val interface{}) (Value, error) {
|
||||
switch typ {
|
||||
case trueValueType:
|
||||
return BoolValue(true), nil
|
||||
case falseValueType:
|
||||
return BoolValue(false), nil
|
||||
case int8ValueType:
|
||||
v, err := val.(json.Number).Int64()
|
||||
return Int8Value(int8(v)), err
|
||||
case int16ValueType:
|
||||
v, err := val.(json.Number).Int64()
|
||||
return Int16Value(int16(v)), err
|
||||
case int32ValueType:
|
||||
v, err := val.(json.Number).Int64()
|
||||
return Int32Value(int32(v)), err
|
||||
case int64ValueType:
|
||||
v, err := val.(json.Number).Int64()
|
||||
return Int64Value(v), err
|
||||
case bytesValueType:
|
||||
v, err := base64.StdEncoding.DecodeString(val.(string))
|
||||
return BytesValue(v), err
|
||||
case stringValueType:
|
||||
v, err := base64.StdEncoding.DecodeString(val.(string))
|
||||
return StringValue(string(v)), err
|
||||
case timestampValueType:
|
||||
v, err := val.(json.Number).Int64()
|
||||
return TimestampValue(timeFromEpochMilli(v)), err
|
||||
case uuidValueType:
|
||||
v, err := base64.StdEncoding.DecodeString(val.(string))
|
||||
var tv UUIDValue
|
||||
copy(tv[:], v)
|
||||
return tv, err
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown type, %s, %T", typ.String(), val))
|
||||
}
|
||||
}
|
||||
218
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/decode.go
generated
vendored
Normal file
218
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/decode.go
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
package eventstream
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/aws/smithy-go/logging"
|
||||
"hash"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
)
|
||||
|
||||
// DecoderOptions is the Decoder configuration options.
|
||||
type DecoderOptions struct {
|
||||
Logger logging.Logger
|
||||
LogMessages bool
|
||||
}
|
||||
|
||||
// Decoder provides decoding of an Event Stream messages.
|
||||
type Decoder struct {
|
||||
options DecoderOptions
|
||||
}
|
||||
|
||||
// NewDecoder initializes and returns a Decoder for decoding event
|
||||
// stream messages from the reader provided.
|
||||
func NewDecoder(optFns ...func(*DecoderOptions)) *Decoder {
|
||||
options := DecoderOptions{}
|
||||
|
||||
for _, fn := range optFns {
|
||||
fn(&options)
|
||||
}
|
||||
|
||||
return &Decoder{
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
// Decode attempts to decode a single message from the event stream reader.
|
||||
// Will return the event stream message, or error if decodeMessage fails to read
|
||||
// the message from the stream.
|
||||
//
|
||||
// payloadBuf is a byte slice that will be used in the returned Message.Payload. Callers
|
||||
// must ensure that the Message.Payload from a previous decode has been consumed before passing in the same underlying
|
||||
// payloadBuf byte slice.
|
||||
func (d *Decoder) Decode(reader io.Reader, payloadBuf []byte) (m Message, err error) {
|
||||
if d.options.Logger != nil && d.options.LogMessages {
|
||||
debugMsgBuf := bytes.NewBuffer(nil)
|
||||
reader = io.TeeReader(reader, debugMsgBuf)
|
||||
defer func() {
|
||||
logMessageDecode(d.options.Logger, debugMsgBuf, m, err)
|
||||
}()
|
||||
}
|
||||
|
||||
m, err = decodeMessage(reader, payloadBuf)
|
||||
|
||||
return m, err
|
||||
}
|
||||
|
||||
// decodeMessage attempts to decode a single message from the event stream reader.
|
||||
// Will return the event stream message, or error if decodeMessage fails to read
|
||||
// the message from the reader.
|
||||
func decodeMessage(reader io.Reader, payloadBuf []byte) (m Message, err error) {
|
||||
crc := crc32.New(crc32IEEETable)
|
||||
hashReader := io.TeeReader(reader, crc)
|
||||
|
||||
prelude, err := decodePrelude(hashReader, crc)
|
||||
if err != nil {
|
||||
return Message{}, err
|
||||
}
|
||||
|
||||
if prelude.HeadersLen > 0 {
|
||||
lr := io.LimitReader(hashReader, int64(prelude.HeadersLen))
|
||||
m.Headers, err = decodeHeaders(lr)
|
||||
if err != nil {
|
||||
return Message{}, err
|
||||
}
|
||||
}
|
||||
|
||||
if payloadLen := prelude.PayloadLen(); payloadLen > 0 {
|
||||
buf, err := decodePayload(payloadBuf, io.LimitReader(hashReader, int64(payloadLen)))
|
||||
if err != nil {
|
||||
return Message{}, err
|
||||
}
|
||||
m.Payload = buf
|
||||
}
|
||||
|
||||
msgCRC := crc.Sum32()
|
||||
if err := validateCRC(reader, msgCRC); err != nil {
|
||||
return Message{}, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func logMessageDecode(logger logging.Logger, msgBuf *bytes.Buffer, msg Message, decodeErr error) {
|
||||
w := bytes.NewBuffer(nil)
|
||||
defer func() { logger.Logf(logging.Debug, w.String()) }()
|
||||
|
||||
fmt.Fprintf(w, "Raw message:\n%s\n",
|
||||
hex.Dump(msgBuf.Bytes()))
|
||||
|
||||
if decodeErr != nil {
|
||||
fmt.Fprintf(w, "decodeMessage error: %v\n", decodeErr)
|
||||
return
|
||||
}
|
||||
|
||||
rawMsg, err := msg.rawMessage()
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "failed to create raw message, %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
decodedMsg := decodedMessage{
|
||||
rawMessage: rawMsg,
|
||||
Headers: decodedHeaders(msg.Headers),
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "Decoded message:\n")
|
||||
encoder := json.NewEncoder(w)
|
||||
if err := encoder.Encode(decodedMsg); err != nil {
|
||||
fmt.Fprintf(w, "failed to generate decoded message, %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func decodePrelude(r io.Reader, crc hash.Hash32) (messagePrelude, error) {
|
||||
var p messagePrelude
|
||||
|
||||
var err error
|
||||
p.Length, err = decodeUint32(r)
|
||||
if err != nil {
|
||||
return messagePrelude{}, err
|
||||
}
|
||||
|
||||
p.HeadersLen, err = decodeUint32(r)
|
||||
if err != nil {
|
||||
return messagePrelude{}, err
|
||||
}
|
||||
|
||||
if err := p.ValidateLens(); err != nil {
|
||||
return messagePrelude{}, err
|
||||
}
|
||||
|
||||
preludeCRC := crc.Sum32()
|
||||
if err := validateCRC(r, preludeCRC); err != nil {
|
||||
return messagePrelude{}, err
|
||||
}
|
||||
|
||||
p.PreludeCRC = preludeCRC
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func decodePayload(buf []byte, r io.Reader) ([]byte, error) {
|
||||
w := bytes.NewBuffer(buf[0:0])
|
||||
|
||||
_, err := io.Copy(w, r)
|
||||
return w.Bytes(), err
|
||||
}
|
||||
|
||||
func decodeUint8(r io.Reader) (uint8, error) {
|
||||
type byteReader interface {
|
||||
ReadByte() (byte, error)
|
||||
}
|
||||
|
||||
if br, ok := r.(byteReader); ok {
|
||||
v, err := br.ReadByte()
|
||||
return v, err
|
||||
}
|
||||
|
||||
var b [1]byte
|
||||
_, err := io.ReadFull(r, b[:])
|
||||
return b[0], err
|
||||
}
|
||||
|
||||
func decodeUint16(r io.Reader) (uint16, error) {
|
||||
var b [2]byte
|
||||
bs := b[:]
|
||||
_, err := io.ReadFull(r, bs)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return binary.BigEndian.Uint16(bs), nil
|
||||
}
|
||||
|
||||
func decodeUint32(r io.Reader) (uint32, error) {
|
||||
var b [4]byte
|
||||
bs := b[:]
|
||||
_, err := io.ReadFull(r, bs)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return binary.BigEndian.Uint32(bs), nil
|
||||
}
|
||||
|
||||
func decodeUint64(r io.Reader) (uint64, error) {
|
||||
var b [8]byte
|
||||
bs := b[:]
|
||||
_, err := io.ReadFull(r, bs)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return binary.BigEndian.Uint64(bs), nil
|
||||
}
|
||||
|
||||
func validateCRC(r io.Reader, expect uint32) error {
|
||||
msgCRC, err := decodeUint32(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if msgCRC != expect {
|
||||
return ChecksumError{}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
167
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/encode.go
generated
vendored
Normal file
167
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/encode.go
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
package eventstream
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/aws/smithy-go/logging"
|
||||
"hash"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
)
|
||||
|
||||
// EncoderOptions is the configuration options for Encoder.
|
||||
type EncoderOptions struct {
|
||||
Logger logging.Logger
|
||||
LogMessages bool
|
||||
}
|
||||
|
||||
// Encoder provides EventStream message encoding.
|
||||
type Encoder struct {
|
||||
options EncoderOptions
|
||||
|
||||
headersBuf *bytes.Buffer
|
||||
messageBuf *bytes.Buffer
|
||||
}
|
||||
|
||||
// NewEncoder initializes and returns an Encoder to encode Event Stream
|
||||
// messages.
|
||||
func NewEncoder(optFns ...func(*EncoderOptions)) *Encoder {
|
||||
o := EncoderOptions{}
|
||||
|
||||
for _, fn := range optFns {
|
||||
fn(&o)
|
||||
}
|
||||
|
||||
return &Encoder{
|
||||
options: o,
|
||||
headersBuf: bytes.NewBuffer(nil),
|
||||
messageBuf: bytes.NewBuffer(nil),
|
||||
}
|
||||
}
|
||||
|
||||
// Encode encodes a single EventStream message to the io.Writer the Encoder
|
||||
// was created with. An error is returned if writing the message fails.
|
||||
func (e *Encoder) Encode(w io.Writer, msg Message) (err error) {
|
||||
e.headersBuf.Reset()
|
||||
e.messageBuf.Reset()
|
||||
|
||||
var writer io.Writer = e.messageBuf
|
||||
if e.options.Logger != nil && e.options.LogMessages {
|
||||
encodeMsgBuf := bytes.NewBuffer(nil)
|
||||
writer = io.MultiWriter(writer, encodeMsgBuf)
|
||||
defer func() {
|
||||
logMessageEncode(e.options.Logger, encodeMsgBuf, msg, err)
|
||||
}()
|
||||
}
|
||||
|
||||
if err = EncodeHeaders(e.headersBuf, msg.Headers); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
crc := crc32.New(crc32IEEETable)
|
||||
hashWriter := io.MultiWriter(writer, crc)
|
||||
|
||||
headersLen := uint32(e.headersBuf.Len())
|
||||
payloadLen := uint32(len(msg.Payload))
|
||||
|
||||
if err = encodePrelude(hashWriter, crc, headersLen, payloadLen); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if headersLen > 0 {
|
||||
if _, err = io.Copy(hashWriter, e.headersBuf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if payloadLen > 0 {
|
||||
if _, err = hashWriter.Write(msg.Payload); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
msgCRC := crc.Sum32()
|
||||
if err := binary.Write(writer, binary.BigEndian, msgCRC); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(w, e.messageBuf)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func logMessageEncode(logger logging.Logger, msgBuf *bytes.Buffer, msg Message, encodeErr error) {
|
||||
w := bytes.NewBuffer(nil)
|
||||
defer func() { logger.Logf(logging.Debug, w.String()) }()
|
||||
|
||||
fmt.Fprintf(w, "Message to encode:\n")
|
||||
encoder := json.NewEncoder(w)
|
||||
if err := encoder.Encode(msg); err != nil {
|
||||
fmt.Fprintf(w, "Failed to get encoded message, %v\n", err)
|
||||
}
|
||||
|
||||
if encodeErr != nil {
|
||||
fmt.Fprintf(w, "Encode error: %v\n", encodeErr)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "Raw message:\n%s\n", hex.Dump(msgBuf.Bytes()))
|
||||
}
|
||||
|
||||
func encodePrelude(w io.Writer, crc hash.Hash32, headersLen, payloadLen uint32) error {
|
||||
p := messagePrelude{
|
||||
Length: minMsgLen + headersLen + payloadLen,
|
||||
HeadersLen: headersLen,
|
||||
}
|
||||
if err := p.ValidateLens(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := binaryWriteFields(w, binary.BigEndian,
|
||||
p.Length,
|
||||
p.HeadersLen,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.PreludeCRC = crc.Sum32()
|
||||
err = binary.Write(w, binary.BigEndian, p.PreludeCRC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeHeaders writes the header values to the writer encoded in the event
|
||||
// stream format. Returns an error if a header fails to encode.
|
||||
func EncodeHeaders(w io.Writer, headers Headers) error {
|
||||
for _, h := range headers {
|
||||
hn := headerName{
|
||||
Len: uint8(len(h.Name)),
|
||||
}
|
||||
copy(hn.Name[:hn.Len], h.Name)
|
||||
if err := hn.encode(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := h.Value.encode(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func binaryWriteFields(w io.Writer, order binary.ByteOrder, vs ...interface{}) error {
|
||||
for _, v := range vs {
|
||||
if err := binary.Write(w, order, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
23
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/error.go
generated
vendored
Normal file
23
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/error.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
package eventstream
|
||||
|
||||
import "fmt"
|
||||
|
||||
// LengthError provides the error for items being larger than a maximum length.
|
||||
type LengthError struct {
|
||||
Part string
|
||||
Want int
|
||||
Have int
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
func (e LengthError) Error() string {
|
||||
return fmt.Sprintf("%s length invalid, %d/%d, %v",
|
||||
e.Part, e.Want, e.Have, e.Value)
|
||||
}
|
||||
|
||||
// ChecksumError provides the error for message checksum invalidation errors.
|
||||
type ChecksumError struct{}
|
||||
|
||||
func (e ChecksumError) Error() string {
|
||||
return "message checksum mismatch"
|
||||
}
|
||||
24
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/headers.go
generated
vendored
Normal file
24
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/headers.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package eventstreamapi
|
||||
|
||||
// EventStream headers with specific meaning to async API functionality.
|
||||
const (
|
||||
ChunkSignatureHeader = `:chunk-signature` // chunk signature for message
|
||||
DateHeader = `:date` // Date header for signature
|
||||
ContentTypeHeader = ":content-type" // message payload content-type
|
||||
|
||||
// Message header and values
|
||||
MessageTypeHeader = `:message-type` // Identifies type of message.
|
||||
EventMessageType = `event`
|
||||
ErrorMessageType = `error`
|
||||
ExceptionMessageType = `exception`
|
||||
|
||||
// Message Events
|
||||
EventTypeHeader = `:event-type` // Identifies message event type e.g. "Stats".
|
||||
|
||||
// Message Error
|
||||
ErrorCodeHeader = `:error-code`
|
||||
ErrorMessageHeader = `:error-message`
|
||||
|
||||
// Message Exception
|
||||
ExceptionTypeHeader = `:exception-type`
|
||||
)
|
||||
71
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/middleware.go
generated
vendored
Normal file
71
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/middleware.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
package eventstreamapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
"io"
|
||||
)
|
||||
|
||||
type eventStreamWriterKey struct{}
|
||||
|
||||
// GetInputStreamWriter returns EventTypeHeader io.PipeWriter used for the operation's input event stream.
|
||||
func GetInputStreamWriter(ctx context.Context) io.WriteCloser {
|
||||
writeCloser, _ := middleware.GetStackValue(ctx, eventStreamWriterKey{}).(io.WriteCloser)
|
||||
return writeCloser
|
||||
}
|
||||
|
||||
func setInputStreamWriter(ctx context.Context, writeCloser io.WriteCloser) context.Context {
|
||||
return middleware.WithStackValue(ctx, eventStreamWriterKey{}, writeCloser)
|
||||
}
|
||||
|
||||
// InitializeStreamWriter is a Finalize middleware initializes an in-memory pipe for sending event stream messages
|
||||
// via the HTTP request body.
|
||||
type InitializeStreamWriter struct{}
|
||||
|
||||
// AddInitializeStreamWriter adds the InitializeStreamWriter middleware to the provided stack.
|
||||
func AddInitializeStreamWriter(stack *middleware.Stack) error {
|
||||
return stack.Finalize.Add(&InitializeStreamWriter{}, middleware.After)
|
||||
}
|
||||
|
||||
// ID returns the identifier for the middleware.
|
||||
func (i *InitializeStreamWriter) ID() string {
|
||||
return "InitializeStreamWriter"
|
||||
}
|
||||
|
||||
// HandleFinalize is the middleware implementation.
|
||||
func (i *InitializeStreamWriter) HandleFinalize(
|
||||
ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
|
||||
) (
|
||||
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
request, ok := in.Request.(*smithyhttp.Request)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("unknown transport type: %T", in.Request)
|
||||
}
|
||||
|
||||
inputReader, inputWriter := io.Pipe()
|
||||
defer func() {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
_ = inputReader.Close()
|
||||
_ = inputWriter.Close()
|
||||
}()
|
||||
|
||||
request, err = request.SetStream(inputReader)
|
||||
if err != nil {
|
||||
return out, metadata, err
|
||||
}
|
||||
in.Request = request
|
||||
|
||||
ctx = setInputStreamWriter(ctx, inputWriter)
|
||||
|
||||
out, metadata, err = next.HandleFinalize(ctx, in)
|
||||
if err != nil {
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
return out, metadata, err
|
||||
}
|
||||
13
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/transport.go
generated
vendored
Normal file
13
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/transport.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package eventstreamapi
|
||||
|
||||
import smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
|
||||
// ApplyHTTPTransportFixes applies fixes to the HTTP request for proper event stream functionality.
|
||||
//
|
||||
// This operation is a no-op for Go 1.18 and above.
|
||||
func ApplyHTTPTransportFixes(r *smithyhttp.Request) error {
|
||||
return nil
|
||||
}
|
||||
12
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/transport_go117.go
generated
vendored
Normal file
12
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/transport_go117.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
//go:build !go1.18
|
||||
// +build !go1.18
|
||||
|
||||
package eventstreamapi
|
||||
|
||||
import smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
|
||||
// ApplyHTTPTransportFixes applies fixes to the HTTP request for proper event stream functionality.
|
||||
func ApplyHTTPTransportFixes(r *smithyhttp.Request) error {
|
||||
r.Header.Set("Expect", "100-continue")
|
||||
return nil
|
||||
}
|
||||
6
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/go_module_metadata.go
generated
vendored
Normal file
6
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/go_module_metadata.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
// Code generated by internal/repotools/cmd/updatemodulemeta DO NOT EDIT.
|
||||
|
||||
package eventstream
|
||||
|
||||
// goModuleVersion is the tagged release for this module
|
||||
const goModuleVersion = "1.6.10"
|
||||
175
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/header.go
generated
vendored
Normal file
175
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/header.go
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
package eventstream
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Headers are a collection of EventStream header values.
|
||||
type Headers []Header
|
||||
|
||||
// Header is a single EventStream Key Value header pair.
|
||||
type Header struct {
|
||||
Name string
|
||||
Value Value
|
||||
}
|
||||
|
||||
// Set associates the name with a value. If the header name already exists in
|
||||
// the Headers the value will be replaced with the new one.
|
||||
func (hs *Headers) Set(name string, value Value) {
|
||||
var i int
|
||||
for ; i < len(*hs); i++ {
|
||||
if (*hs)[i].Name == name {
|
||||
(*hs)[i].Value = value
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
*hs = append(*hs, Header{
|
||||
Name: name, Value: value,
|
||||
})
|
||||
}
|
||||
|
||||
// Get returns the Value associated with the header. Nil is returned if the
|
||||
// value does not exist.
|
||||
func (hs Headers) Get(name string) Value {
|
||||
for i := 0; i < len(hs); i++ {
|
||||
if h := hs[i]; h.Name == name {
|
||||
return h.Value
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Del deletes the value in the Headers if it exists.
|
||||
func (hs *Headers) Del(name string) {
|
||||
for i := 0; i < len(*hs); i++ {
|
||||
if (*hs)[i].Name == name {
|
||||
copy((*hs)[i:], (*hs)[i+1:])
|
||||
(*hs) = (*hs)[:len(*hs)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clone returns a deep copy of the headers
|
||||
func (hs Headers) Clone() Headers {
|
||||
o := make(Headers, 0, len(hs))
|
||||
for _, h := range hs {
|
||||
o.Set(h.Name, h.Value)
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func decodeHeaders(r io.Reader) (Headers, error) {
|
||||
hs := Headers{}
|
||||
|
||||
for {
|
||||
name, err := decodeHeaderName(r)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
// EOF while getting header name means no more headers
|
||||
break
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value, err := decodeHeaderValue(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hs.Set(name, value)
|
||||
}
|
||||
|
||||
return hs, nil
|
||||
}
|
||||
|
||||
func decodeHeaderName(r io.Reader) (string, error) {
|
||||
var n headerName
|
||||
|
||||
var err error
|
||||
n.Len, err = decodeUint8(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
name := n.Name[:n.Len]
|
||||
if _, err := io.ReadFull(r, name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(name), nil
|
||||
}
|
||||
|
||||
func decodeHeaderValue(r io.Reader) (Value, error) {
|
||||
var raw rawValue
|
||||
|
||||
typ, err := decodeUint8(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
raw.Type = valueType(typ)
|
||||
|
||||
var v Value
|
||||
|
||||
switch raw.Type {
|
||||
case trueValueType:
|
||||
v = BoolValue(true)
|
||||
case falseValueType:
|
||||
v = BoolValue(false)
|
||||
case int8ValueType:
|
||||
var tv Int8Value
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
case int16ValueType:
|
||||
var tv Int16Value
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
case int32ValueType:
|
||||
var tv Int32Value
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
case int64ValueType:
|
||||
var tv Int64Value
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
case bytesValueType:
|
||||
var tv BytesValue
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
case stringValueType:
|
||||
var tv StringValue
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
case timestampValueType:
|
||||
var tv TimestampValue
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
case uuidValueType:
|
||||
var tv UUIDValue
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown value type %d", raw.Type))
|
||||
}
|
||||
|
||||
// Error could be EOF, let caller deal with it
|
||||
return v, err
|
||||
}
|
||||
|
||||
const maxHeaderNameLen = 255
|
||||
|
||||
type headerName struct {
|
||||
Len uint8
|
||||
Name [maxHeaderNameLen]byte
|
||||
}
|
||||
|
||||
func (v headerName) encode(w io.Writer) error {
|
||||
if err := binary.Write(w, binary.BigEndian, v.Len); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := w.Write(v.Name[:v.Len])
|
||||
return err
|
||||
}
|
||||
521
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/header_value.go
generated
vendored
Normal file
521
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/header_value.go
generated
vendored
Normal file
@@ -0,0 +1,521 @@
|
||||
package eventstream
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const maxHeaderValueLen = 1<<15 - 1 // 2^15-1 or 32KB - 1
|
||||
|
||||
// valueType is the EventStream header value type.
|
||||
type valueType uint8
|
||||
|
||||
// Header value types
|
||||
const (
|
||||
trueValueType valueType = iota
|
||||
falseValueType
|
||||
int8ValueType // Byte
|
||||
int16ValueType // Short
|
||||
int32ValueType // Integer
|
||||
int64ValueType // Long
|
||||
bytesValueType
|
||||
stringValueType
|
||||
timestampValueType
|
||||
uuidValueType
|
||||
)
|
||||
|
||||
func (t valueType) String() string {
|
||||
switch t {
|
||||
case trueValueType:
|
||||
return "bool"
|
||||
case falseValueType:
|
||||
return "bool"
|
||||
case int8ValueType:
|
||||
return "int8"
|
||||
case int16ValueType:
|
||||
return "int16"
|
||||
case int32ValueType:
|
||||
return "int32"
|
||||
case int64ValueType:
|
||||
return "int64"
|
||||
case bytesValueType:
|
||||
return "byte_array"
|
||||
case stringValueType:
|
||||
return "string"
|
||||
case timestampValueType:
|
||||
return "timestamp"
|
||||
case uuidValueType:
|
||||
return "uuid"
|
||||
default:
|
||||
return fmt.Sprintf("unknown value type %d", uint8(t))
|
||||
}
|
||||
}
|
||||
|
||||
type rawValue struct {
|
||||
Type valueType
|
||||
Len uint16 // Only set for variable length slices
|
||||
Value []byte // byte representation of value, BigEndian encoding.
|
||||
}
|
||||
|
||||
func (r rawValue) encodeScalar(w io.Writer, v interface{}) error {
|
||||
return binaryWriteFields(w, binary.BigEndian,
|
||||
r.Type,
|
||||
v,
|
||||
)
|
||||
}
|
||||
|
||||
func (r rawValue) encodeFixedSlice(w io.Writer, v []byte) error {
|
||||
binary.Write(w, binary.BigEndian, r.Type)
|
||||
|
||||
_, err := w.Write(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r rawValue) encodeBytes(w io.Writer, v []byte) error {
|
||||
if len(v) > maxHeaderValueLen {
|
||||
return LengthError{
|
||||
Part: "header value",
|
||||
Want: maxHeaderValueLen, Have: len(v),
|
||||
Value: v,
|
||||
}
|
||||
}
|
||||
r.Len = uint16(len(v))
|
||||
|
||||
err := binaryWriteFields(w, binary.BigEndian,
|
||||
r.Type,
|
||||
r.Len,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r rawValue) encodeString(w io.Writer, v string) error {
|
||||
if len(v) > maxHeaderValueLen {
|
||||
return LengthError{
|
||||
Part: "header value",
|
||||
Want: maxHeaderValueLen, Have: len(v),
|
||||
Value: v,
|
||||
}
|
||||
}
|
||||
r.Len = uint16(len(v))
|
||||
|
||||
type stringWriter interface {
|
||||
WriteString(string) (int, error)
|
||||
}
|
||||
|
||||
err := binaryWriteFields(w, binary.BigEndian,
|
||||
r.Type,
|
||||
r.Len,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sw, ok := w.(stringWriter); ok {
|
||||
_, err = sw.WriteString(v)
|
||||
} else {
|
||||
_, err = w.Write([]byte(v))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func decodeFixedBytesValue(r io.Reader, buf []byte) error {
|
||||
_, err := io.ReadFull(r, buf)
|
||||
return err
|
||||
}
|
||||
|
||||
func decodeBytesValue(r io.Reader) ([]byte, error) {
|
||||
var raw rawValue
|
||||
var err error
|
||||
raw.Len, err = decodeUint16(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf := make([]byte, raw.Len)
|
||||
_, err = io.ReadFull(r, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func decodeStringValue(r io.Reader) (string, error) {
|
||||
v, err := decodeBytesValue(r)
|
||||
return string(v), err
|
||||
}
|
||||
|
||||
// Value represents the abstract header value.
|
||||
type Value interface {
|
||||
Get() interface{}
|
||||
String() string
|
||||
valueType() valueType
|
||||
encode(io.Writer) error
|
||||
}
|
||||
|
||||
// An BoolValue provides eventstream encoding, and representation
|
||||
// of a Go bool value.
|
||||
type BoolValue bool
|
||||
|
||||
// Get returns the underlying type
|
||||
func (v BoolValue) Get() interface{} {
|
||||
return bool(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (v BoolValue) valueType() valueType {
|
||||
if v {
|
||||
return trueValueType
|
||||
}
|
||||
return falseValueType
|
||||
}
|
||||
|
||||
func (v BoolValue) String() string {
|
||||
return strconv.FormatBool(bool(v))
|
||||
}
|
||||
|
||||
// encode encodes the BoolValue into an eventstream binary value
|
||||
// representation.
|
||||
func (v BoolValue) encode(w io.Writer) error {
|
||||
return binary.Write(w, binary.BigEndian, v.valueType())
|
||||
}
|
||||
|
||||
// An Int8Value provides eventstream encoding, and representation of a Go
|
||||
// int8 value.
|
||||
type Int8Value int8
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v Int8Value) Get() interface{} {
|
||||
return int8(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (Int8Value) valueType() valueType {
|
||||
return int8ValueType
|
||||
}
|
||||
|
||||
func (v Int8Value) String() string {
|
||||
return fmt.Sprintf("0x%02x", int8(v))
|
||||
}
|
||||
|
||||
// encode encodes the Int8Value into an eventstream binary value
|
||||
// representation.
|
||||
func (v Int8Value) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
|
||||
return raw.encodeScalar(w, v)
|
||||
}
|
||||
|
||||
func (v *Int8Value) decode(r io.Reader) error {
|
||||
n, err := decodeUint8(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = Int8Value(n)
|
||||
return nil
|
||||
}
|
||||
|
||||
// An Int16Value provides eventstream encoding, and representation of a Go
|
||||
// int16 value.
|
||||
type Int16Value int16
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v Int16Value) Get() interface{} {
|
||||
return int16(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (Int16Value) valueType() valueType {
|
||||
return int16ValueType
|
||||
}
|
||||
|
||||
func (v Int16Value) String() string {
|
||||
return fmt.Sprintf("0x%04x", int16(v))
|
||||
}
|
||||
|
||||
// encode encodes the Int16Value into an eventstream binary value
|
||||
// representation.
|
||||
func (v Int16Value) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
return raw.encodeScalar(w, v)
|
||||
}
|
||||
|
||||
func (v *Int16Value) decode(r io.Reader) error {
|
||||
n, err := decodeUint16(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = Int16Value(n)
|
||||
return nil
|
||||
}
|
||||
|
||||
// An Int32Value provides eventstream encoding, and representation of a Go
|
||||
// int32 value.
|
||||
type Int32Value int32
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v Int32Value) Get() interface{} {
|
||||
return int32(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (Int32Value) valueType() valueType {
|
||||
return int32ValueType
|
||||
}
|
||||
|
||||
func (v Int32Value) String() string {
|
||||
return fmt.Sprintf("0x%08x", int32(v))
|
||||
}
|
||||
|
||||
// encode encodes the Int32Value into an eventstream binary value
|
||||
// representation.
|
||||
func (v Int32Value) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
return raw.encodeScalar(w, v)
|
||||
}
|
||||
|
||||
func (v *Int32Value) decode(r io.Reader) error {
|
||||
n, err := decodeUint32(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = Int32Value(n)
|
||||
return nil
|
||||
}
|
||||
|
||||
// An Int64Value provides eventstream encoding, and representation of a Go
|
||||
// int64 value.
|
||||
type Int64Value int64
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v Int64Value) Get() interface{} {
|
||||
return int64(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (Int64Value) valueType() valueType {
|
||||
return int64ValueType
|
||||
}
|
||||
|
||||
func (v Int64Value) String() string {
|
||||
return fmt.Sprintf("0x%016x", int64(v))
|
||||
}
|
||||
|
||||
// encode encodes the Int64Value into an eventstream binary value
|
||||
// representation.
|
||||
func (v Int64Value) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
return raw.encodeScalar(w, v)
|
||||
}
|
||||
|
||||
func (v *Int64Value) decode(r io.Reader) error {
|
||||
n, err := decodeUint64(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = Int64Value(n)
|
||||
return nil
|
||||
}
|
||||
|
||||
// An BytesValue provides eventstream encoding, and representation of a Go
|
||||
// byte slice.
|
||||
type BytesValue []byte
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v BytesValue) Get() interface{} {
|
||||
return []byte(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (BytesValue) valueType() valueType {
|
||||
return bytesValueType
|
||||
}
|
||||
|
||||
func (v BytesValue) String() string {
|
||||
return base64.StdEncoding.EncodeToString([]byte(v))
|
||||
}
|
||||
|
||||
// encode encodes the BytesValue into an eventstream binary value
|
||||
// representation.
|
||||
func (v BytesValue) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
|
||||
return raw.encodeBytes(w, []byte(v))
|
||||
}
|
||||
|
||||
func (v *BytesValue) decode(r io.Reader) error {
|
||||
buf, err := decodeBytesValue(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = BytesValue(buf)
|
||||
return nil
|
||||
}
|
||||
|
||||
// An StringValue provides eventstream encoding, and representation of a Go
|
||||
// string.
|
||||
type StringValue string
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v StringValue) Get() interface{} {
|
||||
return string(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (StringValue) valueType() valueType {
|
||||
return stringValueType
|
||||
}
|
||||
|
||||
func (v StringValue) String() string {
|
||||
return string(v)
|
||||
}
|
||||
|
||||
// encode encodes the StringValue into an eventstream binary value
|
||||
// representation.
|
||||
func (v StringValue) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
|
||||
return raw.encodeString(w, string(v))
|
||||
}
|
||||
|
||||
func (v *StringValue) decode(r io.Reader) error {
|
||||
s, err := decodeStringValue(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = StringValue(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
// An TimestampValue provides eventstream encoding, and representation of a Go
|
||||
// timestamp.
|
||||
type TimestampValue time.Time
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v TimestampValue) Get() interface{} {
|
||||
return time.Time(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (TimestampValue) valueType() valueType {
|
||||
return timestampValueType
|
||||
}
|
||||
|
||||
func (v TimestampValue) epochMilli() int64 {
|
||||
nano := time.Time(v).UnixNano()
|
||||
msec := nano / int64(time.Millisecond)
|
||||
return msec
|
||||
}
|
||||
|
||||
func (v TimestampValue) String() string {
|
||||
msec := v.epochMilli()
|
||||
return strconv.FormatInt(msec, 10)
|
||||
}
|
||||
|
||||
// encode encodes the TimestampValue into an eventstream binary value
|
||||
// representation.
|
||||
func (v TimestampValue) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
|
||||
msec := v.epochMilli()
|
||||
return raw.encodeScalar(w, msec)
|
||||
}
|
||||
|
||||
func (v *TimestampValue) decode(r io.Reader) error {
|
||||
n, err := decodeUint64(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = TimestampValue(timeFromEpochMilli(int64(n)))
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface
|
||||
func (v TimestampValue) MarshalJSON() ([]byte, error) {
|
||||
return []byte(v.String()), nil
|
||||
}
|
||||
|
||||
func timeFromEpochMilli(t int64) time.Time {
|
||||
secs := t / 1e3
|
||||
msec := t % 1e3
|
||||
return time.Unix(secs, msec*int64(time.Millisecond)).UTC()
|
||||
}
|
||||
|
||||
// An UUIDValue provides eventstream encoding, and representation of a UUID
|
||||
// value.
|
||||
type UUIDValue [16]byte
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v UUIDValue) Get() interface{} {
|
||||
return v[:]
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (UUIDValue) valueType() valueType {
|
||||
return uuidValueType
|
||||
}
|
||||
|
||||
func (v UUIDValue) String() string {
|
||||
var scratch [36]byte
|
||||
|
||||
const dash = '-'
|
||||
|
||||
hex.Encode(scratch[:8], v[0:4])
|
||||
scratch[8] = dash
|
||||
hex.Encode(scratch[9:13], v[4:6])
|
||||
scratch[13] = dash
|
||||
hex.Encode(scratch[14:18], v[6:8])
|
||||
scratch[18] = dash
|
||||
hex.Encode(scratch[19:23], v[8:10])
|
||||
scratch[23] = dash
|
||||
hex.Encode(scratch[24:], v[10:])
|
||||
|
||||
return string(scratch[:])
|
||||
}
|
||||
|
||||
// encode encodes the UUIDValue into an eventstream binary value
|
||||
// representation.
|
||||
func (v UUIDValue) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
|
||||
return raw.encodeFixedSlice(w, v[:])
|
||||
}
|
||||
|
||||
func (v *UUIDValue) decode(r io.Reader) error {
|
||||
tv := (*v)[:]
|
||||
return decodeFixedBytesValue(r, tv)
|
||||
}
|
||||
99
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/message.go
generated
vendored
Normal file
99
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/message.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
package eventstream
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"hash/crc32"
|
||||
)
|
||||
|
||||
const preludeLen = 8
|
||||
const preludeCRCLen = 4
|
||||
const msgCRCLen = 4
|
||||
const minMsgLen = preludeLen + preludeCRCLen + msgCRCLen
|
||||
|
||||
var crc32IEEETable = crc32.MakeTable(crc32.IEEE)
|
||||
|
||||
// A Message provides the eventstream message representation.
|
||||
type Message struct {
|
||||
Headers Headers
|
||||
Payload []byte
|
||||
}
|
||||
|
||||
func (m *Message) rawMessage() (rawMessage, error) {
|
||||
var raw rawMessage
|
||||
|
||||
if len(m.Headers) > 0 {
|
||||
var headers bytes.Buffer
|
||||
if err := EncodeHeaders(&headers, m.Headers); err != nil {
|
||||
return rawMessage{}, err
|
||||
}
|
||||
raw.Headers = headers.Bytes()
|
||||
raw.HeadersLen = uint32(len(raw.Headers))
|
||||
}
|
||||
|
||||
raw.Length = raw.HeadersLen + uint32(len(m.Payload)) + minMsgLen
|
||||
|
||||
hash := crc32.New(crc32IEEETable)
|
||||
binaryWriteFields(hash, binary.BigEndian, raw.Length, raw.HeadersLen)
|
||||
raw.PreludeCRC = hash.Sum32()
|
||||
|
||||
binaryWriteFields(hash, binary.BigEndian, raw.PreludeCRC)
|
||||
|
||||
if raw.HeadersLen > 0 {
|
||||
hash.Write(raw.Headers)
|
||||
}
|
||||
|
||||
// Read payload bytes and update hash for it as well.
|
||||
if len(m.Payload) > 0 {
|
||||
raw.Payload = m.Payload
|
||||
hash.Write(raw.Payload)
|
||||
}
|
||||
|
||||
raw.CRC = hash.Sum32()
|
||||
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
// Clone returns a deep copy of the message.
|
||||
func (m Message) Clone() Message {
|
||||
var payload []byte
|
||||
if m.Payload != nil {
|
||||
payload = make([]byte, len(m.Payload))
|
||||
copy(payload, m.Payload)
|
||||
}
|
||||
|
||||
return Message{
|
||||
Headers: m.Headers.Clone(),
|
||||
Payload: payload,
|
||||
}
|
||||
}
|
||||
|
||||
type messagePrelude struct {
|
||||
Length uint32
|
||||
HeadersLen uint32
|
||||
PreludeCRC uint32
|
||||
}
|
||||
|
||||
func (p messagePrelude) PayloadLen() uint32 {
|
||||
return p.Length - p.HeadersLen - minMsgLen
|
||||
}
|
||||
|
||||
func (p messagePrelude) ValidateLens() error {
|
||||
if p.Length == 0 {
|
||||
return LengthError{
|
||||
Part: "message prelude",
|
||||
Want: minMsgLen,
|
||||
Have: int(p.Length),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type rawMessage struct {
|
||||
messagePrelude
|
||||
|
||||
Headers []byte
|
||||
Payload []byte
|
||||
|
||||
CRC uint32
|
||||
}
|
||||
61
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/array.go
generated
vendored
Normal file
61
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/array.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Array represents the encoding of Query lists and sets. A Query array is a
|
||||
// representation of a list of values of a fixed type. A serialized array might
|
||||
// look like the following:
|
||||
//
|
||||
// ListName.member.1=foo
|
||||
// &ListName.member.2=bar
|
||||
// &Listname.member.3=baz
|
||||
type Array struct {
|
||||
// The query values to add the array to.
|
||||
values url.Values
|
||||
// The array's prefix, which includes the names of all parent structures
|
||||
// and ends with the name of the list. For example, the prefix might be
|
||||
// "ParentStructure.ListName". This prefix will be used to form the full
|
||||
// keys for each element in the list. For example, an entry might have the
|
||||
// key "ParentStructure.ListName.member.MemberName.1".
|
||||
//
|
||||
// When the array is not flat the prefix will contain the memberName otherwise the memberName is ignored
|
||||
prefix string
|
||||
// Elements are stored in values, so we keep track of the list size here.
|
||||
size int32
|
||||
// Empty lists are encoded as "<prefix>=", if we add a value later we will
|
||||
// remove this encoding
|
||||
emptyValue Value
|
||||
}
|
||||
|
||||
func newArray(values url.Values, prefix string, flat bool, memberName string) *Array {
|
||||
emptyValue := newValue(values, prefix, flat)
|
||||
emptyValue.String("")
|
||||
|
||||
if !flat {
|
||||
// This uses string concatenation in place of fmt.Sprintf as fmt.Sprintf has a much higher resource overhead
|
||||
prefix = prefix + keySeparator + memberName
|
||||
}
|
||||
|
||||
return &Array{
|
||||
values: values,
|
||||
prefix: prefix,
|
||||
emptyValue: emptyValue,
|
||||
}
|
||||
}
|
||||
|
||||
// Value adds a new element to the Query Array. Returns a Value type used to
|
||||
// encode the array element.
|
||||
func (a *Array) Value() Value {
|
||||
if a.size == 0 {
|
||||
delete(a.values, a.emptyValue.key)
|
||||
}
|
||||
|
||||
// Query lists start a 1, so adjust the size first
|
||||
a.size++
|
||||
// Lists can't have flat members
|
||||
// This uses string concatenation in place of fmt.Sprintf as fmt.Sprintf has a much higher resource overhead
|
||||
return newValue(a.values, a.prefix+keySeparator+strconv.FormatInt(int64(a.size), 10), false)
|
||||
}
|
||||
80
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/encoder.go
generated
vendored
Normal file
80
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/encoder.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/url"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Encoder is a Query encoder that supports construction of Query body
|
||||
// values using methods.
|
||||
type Encoder struct {
|
||||
// The query values that will be built up to manage encoding.
|
||||
values url.Values
|
||||
// The writer that the encoded body will be written to.
|
||||
writer io.Writer
|
||||
Value
|
||||
}
|
||||
|
||||
// NewEncoder returns a new Query body encoder
|
||||
func NewEncoder(writer io.Writer) *Encoder {
|
||||
values := url.Values{}
|
||||
return &Encoder{
|
||||
values: values,
|
||||
writer: writer,
|
||||
Value: newBaseValue(values),
|
||||
}
|
||||
}
|
||||
|
||||
// Encode returns the []byte slice representing the current
|
||||
// state of the Query encoder.
|
||||
func (e Encoder) Encode() error {
|
||||
ws, ok := e.writer.(interface{ WriteString(string) (int, error) })
|
||||
if !ok {
|
||||
// Fall back to less optimal byte slice casting if WriteString isn't available.
|
||||
ws = &wrapWriteString{writer: e.writer}
|
||||
}
|
||||
|
||||
// Get the keys and sort them to have a stable output
|
||||
keys := make([]string, 0, len(e.values))
|
||||
for k := range e.values {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
isFirstEntry := true
|
||||
for _, key := range keys {
|
||||
queryValues := e.values[key]
|
||||
escapedKey := url.QueryEscape(key)
|
||||
for _, value := range queryValues {
|
||||
if !isFirstEntry {
|
||||
if _, err := ws.WriteString(`&`); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
isFirstEntry = false
|
||||
}
|
||||
if _, err := ws.WriteString(escapedKey); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := ws.WriteString(`=`); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := ws.WriteString(url.QueryEscape(value)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// wrapWriteString wraps an io.Writer to provide a WriteString method
|
||||
// where one is not available.
|
||||
type wrapWriteString struct {
|
||||
writer io.Writer
|
||||
}
|
||||
|
||||
// WriteString writes a string to the wrapped writer by casting it to
|
||||
// a byte array first.
|
||||
func (w wrapWriteString) WriteString(v string) (int, error) {
|
||||
return w.writer.Write([]byte(v))
|
||||
}
|
||||
78
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/map.go
generated
vendored
Normal file
78
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/map.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// Map represents the encoding of Query maps. A Query map is a representation
|
||||
// of a mapping of arbitrary string keys to arbitrary values of a fixed type.
|
||||
// A Map differs from an Object in that the set of keys is not fixed, in that
|
||||
// the values must all be of the same type, and that map entries are ordered.
|
||||
// A serialized map might look like the following:
|
||||
//
|
||||
// MapName.entry.1.key=Foo
|
||||
// &MapName.entry.1.value=spam
|
||||
// &MapName.entry.2.key=Bar
|
||||
// &MapName.entry.2.value=eggs
|
||||
type Map struct {
|
||||
// The query values to add the map to.
|
||||
values url.Values
|
||||
// The map's prefix, which includes the names of all parent structures
|
||||
// and ends with the name of the object. For example, the prefix might be
|
||||
// "ParentStructure.MapName". This prefix will be used to form the full
|
||||
// keys for each key-value pair of the map. For example, a value might have
|
||||
// the key "ParentStructure.MapName.1.value".
|
||||
//
|
||||
// While this is currently represented as a string that gets added to, it
|
||||
// could also be represented as a stack that only gets condensed into a
|
||||
// string when a finalized key is created. This could potentially reduce
|
||||
// allocations.
|
||||
prefix string
|
||||
// Whether the map is flat or not. A map that is not flat will produce the
|
||||
// following entries to the url.Values for a given key-value pair:
|
||||
// MapName.entry.1.KeyLocationName=mykey
|
||||
// MapName.entry.1.ValueLocationName=myvalue
|
||||
// A map that is flat will produce the following:
|
||||
// MapName.1.KeyLocationName=mykey
|
||||
// MapName.1.ValueLocationName=myvalue
|
||||
flat bool
|
||||
// The location name of the key. In most cases this should be "key".
|
||||
keyLocationName string
|
||||
// The location name of the value. In most cases this should be "value".
|
||||
valueLocationName string
|
||||
// Elements are stored in values, so we keep track of the list size here.
|
||||
size int32
|
||||
}
|
||||
|
||||
func newMap(values url.Values, prefix string, flat bool, keyLocationName string, valueLocationName string) *Map {
|
||||
return &Map{
|
||||
values: values,
|
||||
prefix: prefix,
|
||||
flat: flat,
|
||||
keyLocationName: keyLocationName,
|
||||
valueLocationName: valueLocationName,
|
||||
}
|
||||
}
|
||||
|
||||
// Key adds the given named key to the Query map.
|
||||
// Returns a Value encoder that should be used to encode a Query value type.
|
||||
func (m *Map) Key(name string) Value {
|
||||
// Query lists start a 1, so adjust the size first
|
||||
m.size++
|
||||
var key string
|
||||
var value string
|
||||
if m.flat {
|
||||
key = fmt.Sprintf("%s.%d.%s", m.prefix, m.size, m.keyLocationName)
|
||||
value = fmt.Sprintf("%s.%d.%s", m.prefix, m.size, m.valueLocationName)
|
||||
} else {
|
||||
key = fmt.Sprintf("%s.entry.%d.%s", m.prefix, m.size, m.keyLocationName)
|
||||
value = fmt.Sprintf("%s.entry.%d.%s", m.prefix, m.size, m.valueLocationName)
|
||||
}
|
||||
|
||||
// The key can only be a string, so we just go ahead and set it here
|
||||
newValue(m.values, key, false).String(name)
|
||||
|
||||
// Maps can't have flat members
|
||||
return newValue(m.values, value, false)
|
||||
}
|
||||
62
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/middleware.go
generated
vendored
Normal file
62
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/middleware.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
)
|
||||
|
||||
// AddAsGetRequestMiddleware adds a middleware to the Serialize stack after the
|
||||
// operation serializer that will convert the query request body to a GET
|
||||
// operation with the query message in the HTTP request querystring.
|
||||
func AddAsGetRequestMiddleware(stack *middleware.Stack) error {
|
||||
return stack.Serialize.Insert(&asGetRequest{}, "OperationSerializer", middleware.After)
|
||||
}
|
||||
|
||||
type asGetRequest struct{}
|
||||
|
||||
func (*asGetRequest) ID() string { return "Query:AsGetRequest" }
|
||||
|
||||
func (m *asGetRequest) HandleSerialize(
|
||||
ctx context.Context, input middleware.SerializeInput, next middleware.SerializeHandler,
|
||||
) (
|
||||
out middleware.SerializeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
req, ok := input.Request.(*smithyhttp.Request)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("expect smithy HTTP Request, got %T", input.Request)
|
||||
}
|
||||
|
||||
req.Method = "GET"
|
||||
|
||||
// If the stream is not set, nothing else to do.
|
||||
stream := req.GetStream()
|
||||
if stream == nil {
|
||||
return next.HandleSerialize(ctx, input)
|
||||
}
|
||||
|
||||
// Clear the stream since there will not be any body.
|
||||
req.Header.Del("Content-Type")
|
||||
req, err = req.SetStream(nil)
|
||||
if err != nil {
|
||||
return out, metadata, fmt.Errorf("unable update request body %w", err)
|
||||
}
|
||||
input.Request = req
|
||||
|
||||
// Update request query with the body's query string value.
|
||||
delim := ""
|
||||
if len(req.URL.RawQuery) != 0 {
|
||||
delim = "&"
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(stream)
|
||||
if err != nil {
|
||||
return out, metadata, fmt.Errorf("unable to get request body %w", err)
|
||||
}
|
||||
req.URL.RawQuery += delim + string(b)
|
||||
|
||||
return next.HandleSerialize(ctx, input)
|
||||
}
|
||||
68
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/object.go
generated
vendored
Normal file
68
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/object.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
package query
|
||||
|
||||
import "net/url"
|
||||
|
||||
// Object represents the encoding of Query structures and unions. A Query
|
||||
// object is a representation of a mapping of string keys to arbitrary
|
||||
// values where there is a fixed set of keys whose values each have their
|
||||
// own known type. A serialized object might look like the following:
|
||||
//
|
||||
// ObjectName.Foo=value
|
||||
// &ObjectName.Bar=5
|
||||
type Object struct {
|
||||
// The query values to add the object to.
|
||||
values url.Values
|
||||
// The object's prefix, which includes the names of all parent structures
|
||||
// and ends with the name of the object. For example, the prefix might be
|
||||
// "ParentStructure.ObjectName". This prefix will be used to form the full
|
||||
// keys for each member of the object. For example, a member might have the
|
||||
// key "ParentStructure.ObjectName.MemberName".
|
||||
//
|
||||
// While this is currently represented as a string that gets added to, it
|
||||
// could also be represented as a stack that only gets condensed into a
|
||||
// string when a finalized key is created. This could potentially reduce
|
||||
// allocations.
|
||||
prefix string
|
||||
}
|
||||
|
||||
func newObject(values url.Values, prefix string) *Object {
|
||||
return &Object{
|
||||
values: values,
|
||||
prefix: prefix,
|
||||
}
|
||||
}
|
||||
|
||||
// Key adds the given named key to the Query object.
|
||||
// Returns a Value encoder that should be used to encode a Query value type.
|
||||
func (o *Object) Key(name string) Value {
|
||||
return o.key(name, false)
|
||||
}
|
||||
|
||||
// KeyWithValues adds the given named key to the Query object.
|
||||
// Returns a Value encoder that should be used to encode a Query list of values.
|
||||
func (o *Object) KeyWithValues(name string) Value {
|
||||
return o.keyWithValues(name, false)
|
||||
}
|
||||
|
||||
// FlatKey adds the given named key to the Query object.
|
||||
// Returns a Value encoder that should be used to encode a Query value type. The
|
||||
// value will be flattened if it is a map or array.
|
||||
func (o *Object) FlatKey(name string) Value {
|
||||
return o.key(name, true)
|
||||
}
|
||||
|
||||
func (o *Object) key(name string, flatValue bool) Value {
|
||||
if o.prefix != "" {
|
||||
// This uses string concatenation in place of fmt.Sprintf as fmt.Sprintf has a much higher resource overhead
|
||||
return newValue(o.values, o.prefix+keySeparator+name, flatValue)
|
||||
}
|
||||
return newValue(o.values, name, flatValue)
|
||||
}
|
||||
|
||||
func (o *Object) keyWithValues(name string, flatValue bool) Value {
|
||||
if o.prefix != "" {
|
||||
// This uses string concatenation in place of fmt.Sprintf as fmt.Sprintf has a much higher resource overhead
|
||||
return newAppendValue(o.values, o.prefix+keySeparator+name, flatValue)
|
||||
}
|
||||
return newAppendValue(o.values, name, flatValue)
|
||||
}
|
||||
117
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/value.go
generated
vendored
Normal file
117
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/value.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"net/url"
|
||||
|
||||
"github.com/aws/smithy-go/encoding/httpbinding"
|
||||
)
|
||||
|
||||
const keySeparator = "."
|
||||
|
||||
// Value represents a Query Value type.
|
||||
type Value struct {
|
||||
// The query values to add the value to.
|
||||
values url.Values
|
||||
// The value's key, which will form the prefix for complex types.
|
||||
key string
|
||||
// Whether the value should be flattened or not if it's a flattenable type.
|
||||
flat bool
|
||||
queryValue httpbinding.QueryValue
|
||||
}
|
||||
|
||||
func newValue(values url.Values, key string, flat bool) Value {
|
||||
return Value{
|
||||
values: values,
|
||||
key: key,
|
||||
flat: flat,
|
||||
queryValue: httpbinding.NewQueryValue(values, key, false),
|
||||
}
|
||||
}
|
||||
|
||||
func newAppendValue(values url.Values, key string, flat bool) Value {
|
||||
return Value{
|
||||
values: values,
|
||||
key: key,
|
||||
flat: flat,
|
||||
queryValue: httpbinding.NewQueryValue(values, key, true),
|
||||
}
|
||||
}
|
||||
|
||||
func newBaseValue(values url.Values) Value {
|
||||
return Value{
|
||||
values: values,
|
||||
queryValue: httpbinding.NewQueryValue(nil, "", false),
|
||||
}
|
||||
}
|
||||
|
||||
// Array returns a new Array encoder.
|
||||
func (qv Value) Array(locationName string) *Array {
|
||||
return newArray(qv.values, qv.key, qv.flat, locationName)
|
||||
}
|
||||
|
||||
// Object returns a new Object encoder.
|
||||
func (qv Value) Object() *Object {
|
||||
return newObject(qv.values, qv.key)
|
||||
}
|
||||
|
||||
// Map returns a new Map encoder.
|
||||
func (qv Value) Map(keyLocationName string, valueLocationName string) *Map {
|
||||
return newMap(qv.values, qv.key, qv.flat, keyLocationName, valueLocationName)
|
||||
}
|
||||
|
||||
// Base64EncodeBytes encodes v as a base64 query string value.
|
||||
// This is intended to enable compatibility with the JSON encoder.
|
||||
func (qv Value) Base64EncodeBytes(v []byte) {
|
||||
qv.queryValue.Blob(v)
|
||||
}
|
||||
|
||||
// Boolean encodes v as a query string value
|
||||
func (qv Value) Boolean(v bool) {
|
||||
qv.queryValue.Boolean(v)
|
||||
}
|
||||
|
||||
// String encodes v as a query string value
|
||||
func (qv Value) String(v string) {
|
||||
qv.queryValue.String(v)
|
||||
}
|
||||
|
||||
// Byte encodes v as a query string value
|
||||
func (qv Value) Byte(v int8) {
|
||||
qv.queryValue.Byte(v)
|
||||
}
|
||||
|
||||
// Short encodes v as a query string value
|
||||
func (qv Value) Short(v int16) {
|
||||
qv.queryValue.Short(v)
|
||||
}
|
||||
|
||||
// Integer encodes v as a query string value
|
||||
func (qv Value) Integer(v int32) {
|
||||
qv.queryValue.Integer(v)
|
||||
}
|
||||
|
||||
// Long encodes v as a query string value
|
||||
func (qv Value) Long(v int64) {
|
||||
qv.queryValue.Long(v)
|
||||
}
|
||||
|
||||
// Float encodes v as a query string value
|
||||
func (qv Value) Float(v float32) {
|
||||
qv.queryValue.Float(v)
|
||||
}
|
||||
|
||||
// Double encodes v as a query string value
|
||||
func (qv Value) Double(v float64) {
|
||||
qv.queryValue.Double(v)
|
||||
}
|
||||
|
||||
// BigInteger encodes v as a query string value
|
||||
func (qv Value) BigInteger(v *big.Int) {
|
||||
qv.queryValue.BigInteger(v)
|
||||
}
|
||||
|
||||
// BigDecimal encodes v as a query string value
|
||||
func (qv Value) BigDecimal(v *big.Float) {
|
||||
qv.queryValue.BigDecimal(v)
|
||||
}
|
||||
85
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/restjson/decoder_util.go
generated
vendored
Normal file
85
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/restjson/decoder_util.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
package restjson
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/smithy-go"
|
||||
)
|
||||
|
||||
// GetErrorInfo util looks for code, __type, and message members in the
|
||||
// json body. These members are optionally available, and the function
|
||||
// returns the value of member if it is available. This function is useful to
|
||||
// identify the error code, msg in a REST JSON error response.
|
||||
func GetErrorInfo(decoder *json.Decoder) (errorType string, message string, err error) {
|
||||
var errInfo struct {
|
||||
Code string
|
||||
Type string `json:"__type"`
|
||||
Message string
|
||||
}
|
||||
|
||||
err = decoder.Decode(&errInfo)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return errorType, message, nil
|
||||
}
|
||||
return errorType, message, err
|
||||
}
|
||||
|
||||
// assign error type
|
||||
if len(errInfo.Code) != 0 {
|
||||
errorType = errInfo.Code
|
||||
} else if len(errInfo.Type) != 0 {
|
||||
errorType = errInfo.Type
|
||||
}
|
||||
|
||||
// assign error message
|
||||
if len(errInfo.Message) != 0 {
|
||||
message = errInfo.Message
|
||||
}
|
||||
|
||||
// sanitize error
|
||||
if len(errorType) != 0 {
|
||||
errorType = SanitizeErrorCode(errorType)
|
||||
}
|
||||
|
||||
return errorType, message, nil
|
||||
}
|
||||
|
||||
// SanitizeErrorCode sanitizes the errorCode string .
|
||||
// The rule for sanitizing is if a `:` character is present, then take only the
|
||||
// contents before the first : character in the value.
|
||||
// If a # character is present, then take only the contents after the
|
||||
// first # character in the value.
|
||||
func SanitizeErrorCode(errorCode string) string {
|
||||
if strings.ContainsAny(errorCode, ":") {
|
||||
errorCode = strings.SplitN(errorCode, ":", 2)[0]
|
||||
}
|
||||
|
||||
if strings.ContainsAny(errorCode, "#") {
|
||||
errorCode = strings.SplitN(errorCode, "#", 2)[1]
|
||||
}
|
||||
|
||||
return errorCode
|
||||
}
|
||||
|
||||
// GetSmithyGenericAPIError returns smithy generic api error and an error interface.
|
||||
// Takes in json decoder, and error Code string as args. The function retrieves error message
|
||||
// and error code from the decoder body. If errorCode of length greater than 0 is passed in as
|
||||
// an argument, it is used instead.
|
||||
func GetSmithyGenericAPIError(decoder *json.Decoder, errorCode string) (*smithy.GenericAPIError, error) {
|
||||
errorType, message, err := GetErrorInfo(decoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(errorCode) == 0 {
|
||||
errorCode = errorType
|
||||
}
|
||||
|
||||
return &smithy.GenericAPIError{
|
||||
Code: errorCode,
|
||||
Message: message,
|
||||
}, nil
|
||||
}
|
||||
48
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/xml/error_utils.go
generated
vendored
Normal file
48
go/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/xml/error_utils.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
package xml
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// ErrorComponents represents the error response fields
|
||||
// that will be deserialized from an xml error response body
|
||||
type ErrorComponents struct {
|
||||
Code string
|
||||
Message string
|
||||
RequestID string
|
||||
}
|
||||
|
||||
// GetErrorResponseComponents returns the error fields from an xml error response body
|
||||
func GetErrorResponseComponents(r io.Reader, noErrorWrapping bool) (ErrorComponents, error) {
|
||||
if noErrorWrapping {
|
||||
var errResponse noWrappedErrorResponse
|
||||
if err := xml.NewDecoder(r).Decode(&errResponse); err != nil && err != io.EOF {
|
||||
return ErrorComponents{}, fmt.Errorf("error while deserializing xml error response: %w", err)
|
||||
}
|
||||
return ErrorComponents(errResponse), nil
|
||||
}
|
||||
|
||||
var errResponse wrappedErrorResponse
|
||||
if err := xml.NewDecoder(r).Decode(&errResponse); err != nil && err != io.EOF {
|
||||
return ErrorComponents{}, fmt.Errorf("error while deserializing xml error response: %w", err)
|
||||
}
|
||||
return ErrorComponents(errResponse), nil
|
||||
}
|
||||
|
||||
// noWrappedErrorResponse represents the error response body with
|
||||
// no internal Error wrapping
|
||||
type noWrappedErrorResponse struct {
|
||||
Code string `xml:"Code"`
|
||||
Message string `xml:"Message"`
|
||||
RequestID string `xml:"RequestId"`
|
||||
}
|
||||
|
||||
// wrappedErrorResponse represents the error response body
|
||||
// wrapped within Error
|
||||
type wrappedErrorResponse struct {
|
||||
Code string `xml:"Error>Code"`
|
||||
Message string `xml:"Error>Message"`
|
||||
RequestID string `xml:"RequestId"`
|
||||
}
|
||||
20
go/vendor/github.com/aws/aws-sdk-go-v2/aws/ratelimit/none.go
generated
vendored
Normal file
20
go/vendor/github.com/aws/aws-sdk-go-v2/aws/ratelimit/none.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package ratelimit
|
||||
|
||||
import "context"
|
||||
|
||||
// None implements a no-op rate limiter which effectively disables client-side
|
||||
// rate limiting (also known as "retry quotas").
|
||||
//
|
||||
// GetToken does nothing and always returns a nil error. The returned
|
||||
// token-release function does nothing, and always returns a nil error.
|
||||
//
|
||||
// AddTokens does nothing and always returns a nil error.
|
||||
var None = &none{}
|
||||
|
||||
type none struct{}
|
||||
|
||||
func (*none) GetToken(ctx context.Context, cost uint) (func() error, error) {
|
||||
return func() error { return nil }, nil
|
||||
}
|
||||
|
||||
func (*none) AddTokens(v uint) error { return nil }
|
||||
96
go/vendor/github.com/aws/aws-sdk-go-v2/aws/ratelimit/token_bucket.go
generated
vendored
Normal file
96
go/vendor/github.com/aws/aws-sdk-go-v2/aws/ratelimit/token_bucket.go
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
package ratelimit
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// TokenBucket provides a concurrency safe utility for adding and removing
|
||||
// tokens from the available token bucket.
|
||||
type TokenBucket struct {
|
||||
remainingTokens uint
|
||||
maxCapacity uint
|
||||
minCapacity uint
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// NewTokenBucket returns an initialized TokenBucket with the capacity
|
||||
// specified.
|
||||
func NewTokenBucket(i uint) *TokenBucket {
|
||||
return &TokenBucket{
|
||||
remainingTokens: i,
|
||||
maxCapacity: i,
|
||||
minCapacity: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve attempts to reduce the available tokens by the amount requested. If
|
||||
// there are tokens available true will be returned along with the number of
|
||||
// available tokens remaining. If amount requested is larger than the available
|
||||
// capacity, false will be returned along with the available capacity. If the
|
||||
// amount is less than the available capacity, the capacity will be reduced by
|
||||
// that amount, and the remaining capacity and true will be returned.
|
||||
func (t *TokenBucket) Retrieve(amount uint) (available uint, retrieved bool) {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
if amount > t.remainingTokens {
|
||||
return t.remainingTokens, false
|
||||
}
|
||||
|
||||
t.remainingTokens -= amount
|
||||
return t.remainingTokens, true
|
||||
}
|
||||
|
||||
// Refund returns the amount of tokens back to the available token bucket, up
|
||||
// to the initial capacity.
|
||||
func (t *TokenBucket) Refund(amount uint) {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
// Capacity cannot exceed max capacity.
|
||||
t.remainingTokens = uintMin(t.remainingTokens+amount, t.maxCapacity)
|
||||
}
|
||||
|
||||
// Capacity returns the maximum capacity of tokens that the bucket could
|
||||
// contain.
|
||||
func (t *TokenBucket) Capacity() uint {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
return t.maxCapacity
|
||||
}
|
||||
|
||||
// Remaining returns the number of tokens that remaining in the bucket.
|
||||
func (t *TokenBucket) Remaining() uint {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
return t.remainingTokens
|
||||
}
|
||||
|
||||
// Resize adjusts the size of the token bucket. Returns the capacity remaining.
|
||||
func (t *TokenBucket) Resize(size uint) uint {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
t.maxCapacity = uintMax(size, t.minCapacity)
|
||||
|
||||
// Capacity needs to be capped at max capacity, if max size reduced.
|
||||
t.remainingTokens = uintMin(t.remainingTokens, t.maxCapacity)
|
||||
|
||||
return t.remainingTokens
|
||||
}
|
||||
|
||||
func uintMin(a, b uint) uint {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func uintMax(a, b uint) uint {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
83
go/vendor/github.com/aws/aws-sdk-go-v2/aws/ratelimit/token_rate_limit.go
generated
vendored
Normal file
83
go/vendor/github.com/aws/aws-sdk-go-v2/aws/ratelimit/token_rate_limit.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
package ratelimit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type rateToken struct {
|
||||
tokenCost uint
|
||||
bucket *TokenBucket
|
||||
}
|
||||
|
||||
func (t rateToken) release() error {
|
||||
t.bucket.Refund(t.tokenCost)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TokenRateLimit provides a Token Bucket RateLimiter implementation
|
||||
// that limits the overall number of retry attempts that can be made across
|
||||
// operation invocations.
|
||||
type TokenRateLimit struct {
|
||||
bucket *TokenBucket
|
||||
}
|
||||
|
||||
// NewTokenRateLimit returns an TokenRateLimit with default values.
|
||||
// Functional options can configure the retry rate limiter.
|
||||
func NewTokenRateLimit(tokens uint) *TokenRateLimit {
|
||||
return &TokenRateLimit{
|
||||
bucket: NewTokenBucket(tokens),
|
||||
}
|
||||
}
|
||||
|
||||
type canceledError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
func (c canceledError) CanceledError() bool { return true }
|
||||
func (c canceledError) Unwrap() error { return c.Err }
|
||||
func (c canceledError) Error() string {
|
||||
return fmt.Sprintf("canceled, %v", c.Err)
|
||||
}
|
||||
|
||||
// GetToken may cause a available pool of retry quota to be
|
||||
// decremented. Will return an error if the decremented value can not be
|
||||
// reduced from the retry quota.
|
||||
func (l *TokenRateLimit) GetToken(ctx context.Context, cost uint) (func() error, error) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, canceledError{Err: ctx.Err()}
|
||||
default:
|
||||
}
|
||||
if avail, ok := l.bucket.Retrieve(cost); !ok {
|
||||
return nil, QuotaExceededError{Available: avail, Requested: cost}
|
||||
}
|
||||
|
||||
return rateToken{
|
||||
tokenCost: cost,
|
||||
bucket: l.bucket,
|
||||
}.release, nil
|
||||
}
|
||||
|
||||
// AddTokens increments the token bucket by a fixed amount.
|
||||
func (l *TokenRateLimit) AddTokens(v uint) error {
|
||||
l.bucket.Refund(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remaining returns the number of remaining tokens in the bucket.
|
||||
func (l *TokenRateLimit) Remaining() uint {
|
||||
return l.bucket.Remaining()
|
||||
}
|
||||
|
||||
// QuotaExceededError provides the SDK error when the retries for a given
|
||||
// token bucket have been exhausted.
|
||||
type QuotaExceededError struct {
|
||||
Available uint
|
||||
Requested uint
|
||||
}
|
||||
|
||||
func (e QuotaExceededError) Error() string {
|
||||
return fmt.Sprintf("retry quota exceeded, %d available, %d requested",
|
||||
e.Available, e.Requested)
|
||||
}
|
||||
25
go/vendor/github.com/aws/aws-sdk-go-v2/aws/request.go
generated
vendored
Normal file
25
go/vendor/github.com/aws/aws-sdk-go-v2/aws/request.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// TODO remove replace with smithy.CanceledError
|
||||
|
||||
// RequestCanceledError is the error that will be returned by an API request
|
||||
// that was canceled. Requests given a Context may return this error when
|
||||
// canceled.
|
||||
type RequestCanceledError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
// CanceledError returns true to satisfy interfaces checking for canceled errors.
|
||||
func (*RequestCanceledError) CanceledError() bool { return true }
|
||||
|
||||
// Unwrap returns the underlying error, if there was one.
|
||||
func (e *RequestCanceledError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
func (e *RequestCanceledError) Error() string {
|
||||
return fmt.Sprintf("request canceled, %v", e.Err)
|
||||
}
|
||||
156
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/adaptive.go
generated
vendored
Normal file
156
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/adaptive.go
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
package retry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultRequestCost is the cost of a single request from the adaptive
|
||||
// rate limited token bucket.
|
||||
DefaultRequestCost uint = 1
|
||||
)
|
||||
|
||||
// DefaultThrottles provides the set of errors considered throttle errors that
|
||||
// are checked by default.
|
||||
var DefaultThrottles = []IsErrorThrottle{
|
||||
ThrottleErrorCode{
|
||||
Codes: DefaultThrottleErrorCodes,
|
||||
},
|
||||
}
|
||||
|
||||
// AdaptiveModeOptions provides the functional options for configuring the
|
||||
// adaptive retry mode, and delay behavior.
|
||||
type AdaptiveModeOptions struct {
|
||||
// If the adaptive token bucket is empty, when an attempt will be made
|
||||
// AdaptiveMode will sleep until a token is available. This can occur when
|
||||
// attempts fail with throttle errors. Use this option to disable the sleep
|
||||
// until token is available, and return error immediately.
|
||||
FailOnNoAttemptTokens bool
|
||||
|
||||
// The cost of an attempt from the AdaptiveMode's adaptive token bucket.
|
||||
RequestCost uint
|
||||
|
||||
// Set of strategies to determine if the attempt failed due to a throttle
|
||||
// error.
|
||||
//
|
||||
// It is safe to append to this list in NewAdaptiveMode's functional options.
|
||||
Throttles []IsErrorThrottle
|
||||
|
||||
// Set of options for standard retry mode that AdaptiveMode is built on top
|
||||
// of. AdaptiveMode may apply its own defaults to Standard retry mode that
|
||||
// are different than the defaults of NewStandard. Use these options to
|
||||
// override the default options.
|
||||
StandardOptions []func(*StandardOptions)
|
||||
}
|
||||
|
||||
// AdaptiveMode provides an experimental retry strategy that expands on the
|
||||
// Standard retry strategy, adding client attempt rate limits. The attempt rate
|
||||
// limit is initially unrestricted, but becomes restricted when the attempt
|
||||
// fails with for a throttle error. When restricted AdaptiveMode may need to
|
||||
// sleep before an attempt is made, if too many throttles have been received.
|
||||
// AdaptiveMode's sleep can be canceled with context cancel. Set
|
||||
// AdaptiveModeOptions FailOnNoAttemptTokens to change the behavior from sleep,
|
||||
// to fail fast.
|
||||
//
|
||||
// Eventually unrestricted attempt rate limit will be restored once attempts no
|
||||
// longer are failing due to throttle errors.
|
||||
type AdaptiveMode struct {
|
||||
options AdaptiveModeOptions
|
||||
throttles IsErrorThrottles
|
||||
|
||||
retryer aws.RetryerV2
|
||||
rateLimit *adaptiveRateLimit
|
||||
}
|
||||
|
||||
// NewAdaptiveMode returns an initialized AdaptiveMode retry strategy.
|
||||
func NewAdaptiveMode(optFns ...func(*AdaptiveModeOptions)) *AdaptiveMode {
|
||||
o := AdaptiveModeOptions{
|
||||
RequestCost: DefaultRequestCost,
|
||||
Throttles: append([]IsErrorThrottle{}, DefaultThrottles...),
|
||||
}
|
||||
for _, fn := range optFns {
|
||||
fn(&o)
|
||||
}
|
||||
|
||||
return &AdaptiveMode{
|
||||
options: o,
|
||||
throttles: IsErrorThrottles(o.Throttles),
|
||||
retryer: NewStandard(o.StandardOptions...),
|
||||
rateLimit: newAdaptiveRateLimit(),
|
||||
}
|
||||
}
|
||||
|
||||
// IsErrorRetryable returns if the failed attempt is retryable. This check
|
||||
// should determine if the error can be retried, or if the error is
|
||||
// terminal.
|
||||
func (a *AdaptiveMode) IsErrorRetryable(err error) bool {
|
||||
return a.retryer.IsErrorRetryable(err)
|
||||
}
|
||||
|
||||
// MaxAttempts returns the maximum number of attempts that can be made for
|
||||
// an attempt before failing. A value of 0 implies that the attempt should
|
||||
// be retried until it succeeds if the errors are retryable.
|
||||
func (a *AdaptiveMode) MaxAttempts() int {
|
||||
return a.retryer.MaxAttempts()
|
||||
}
|
||||
|
||||
// RetryDelay returns the delay that should be used before retrying the
|
||||
// attempt. Will return error if the if the delay could not be determined.
|
||||
func (a *AdaptiveMode) RetryDelay(attempt int, opErr error) (
|
||||
time.Duration, error,
|
||||
) {
|
||||
return a.retryer.RetryDelay(attempt, opErr)
|
||||
}
|
||||
|
||||
// GetRetryToken attempts to deduct the retry cost from the retry token pool.
|
||||
// Returning the token release function, or error.
|
||||
func (a *AdaptiveMode) GetRetryToken(ctx context.Context, opErr error) (
|
||||
releaseToken func(error) error, err error,
|
||||
) {
|
||||
return a.retryer.GetRetryToken(ctx, opErr)
|
||||
}
|
||||
|
||||
// GetInitialToken returns the initial attempt token that can increment the
|
||||
// retry token pool if the attempt is successful.
|
||||
//
|
||||
// Deprecated: This method does not provide a way to block using Context,
|
||||
// nor can it return an error. Use RetryerV2, and GetAttemptToken instead. Only
|
||||
// present to implement Retryer interface.
|
||||
func (a *AdaptiveMode) GetInitialToken() (releaseToken func(error) error) {
|
||||
return nopRelease
|
||||
}
|
||||
|
||||
// GetAttemptToken returns the attempt token that can be used to rate limit
|
||||
// attempt calls. Will be used by the SDK's retry package's Attempt
|
||||
// middleware to get an attempt token prior to calling the temp and releasing
|
||||
// the attempt token after the attempt has been made.
|
||||
func (a *AdaptiveMode) GetAttemptToken(ctx context.Context) (func(error) error, error) {
|
||||
for {
|
||||
acquiredToken, waitTryAgain := a.rateLimit.AcquireToken(a.options.RequestCost)
|
||||
if acquiredToken {
|
||||
break
|
||||
}
|
||||
if a.options.FailOnNoAttemptTokens {
|
||||
return nil, fmt.Errorf(
|
||||
"unable to get attempt token, and FailOnNoAttemptTokens enables")
|
||||
}
|
||||
|
||||
if err := sdk.SleepWithContext(ctx, waitTryAgain); err != nil {
|
||||
return nil, fmt.Errorf("failed to wait for token to be available, %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return a.handleResponse, nil
|
||||
}
|
||||
|
||||
func (a *AdaptiveMode) handleResponse(opErr error) error {
|
||||
throttled := a.throttles.IsErrorThrottle(opErr).Bool()
|
||||
|
||||
a.rateLimit.Update(throttled)
|
||||
return nil
|
||||
}
|
||||
158
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/adaptive_ratelimit.go
generated
vendored
Normal file
158
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/adaptive_ratelimit.go
generated
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
package retry
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
||||
)
|
||||
|
||||
type adaptiveRateLimit struct {
|
||||
tokenBucketEnabled bool
|
||||
|
||||
smooth float64
|
||||
beta float64
|
||||
scaleConstant float64
|
||||
minFillRate float64
|
||||
|
||||
fillRate float64
|
||||
calculatedRate float64
|
||||
lastRefilled time.Time
|
||||
measuredTxRate float64
|
||||
lastTxRateBucket float64
|
||||
requestCount int64
|
||||
lastMaxRate float64
|
||||
lastThrottleTime time.Time
|
||||
timeWindow float64
|
||||
|
||||
tokenBucket *adaptiveTokenBucket
|
||||
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func newAdaptiveRateLimit() *adaptiveRateLimit {
|
||||
now := sdk.NowTime()
|
||||
return &adaptiveRateLimit{
|
||||
smooth: 0.8,
|
||||
beta: 0.7,
|
||||
scaleConstant: 0.4,
|
||||
|
||||
minFillRate: 0.5,
|
||||
|
||||
lastTxRateBucket: math.Floor(timeFloat64Seconds(now)),
|
||||
lastThrottleTime: now,
|
||||
|
||||
tokenBucket: newAdaptiveTokenBucket(0),
|
||||
}
|
||||
}
|
||||
|
||||
func (a *adaptiveRateLimit) Enable(v bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
a.tokenBucketEnabled = v
|
||||
}
|
||||
|
||||
func (a *adaptiveRateLimit) AcquireToken(amount uint) (
|
||||
tokenAcquired bool, waitTryAgain time.Duration,
|
||||
) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
if !a.tokenBucketEnabled {
|
||||
return true, 0
|
||||
}
|
||||
|
||||
a.tokenBucketRefill()
|
||||
|
||||
available, ok := a.tokenBucket.Retrieve(float64(amount))
|
||||
if !ok {
|
||||
waitDur := float64Seconds((float64(amount) - available) / a.fillRate)
|
||||
return false, waitDur
|
||||
}
|
||||
|
||||
return true, 0
|
||||
}
|
||||
|
||||
func (a *adaptiveRateLimit) Update(throttled bool) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
a.updateMeasuredRate()
|
||||
|
||||
if throttled {
|
||||
rateToUse := a.measuredTxRate
|
||||
if a.tokenBucketEnabled {
|
||||
rateToUse = math.Min(a.measuredTxRate, a.fillRate)
|
||||
}
|
||||
|
||||
a.lastMaxRate = rateToUse
|
||||
a.calculateTimeWindow()
|
||||
a.lastThrottleTime = sdk.NowTime()
|
||||
a.calculatedRate = a.cubicThrottle(rateToUse)
|
||||
a.tokenBucketEnabled = true
|
||||
} else {
|
||||
a.calculateTimeWindow()
|
||||
a.calculatedRate = a.cubicSuccess(sdk.NowTime())
|
||||
}
|
||||
|
||||
newRate := math.Min(a.calculatedRate, 2*a.measuredTxRate)
|
||||
a.tokenBucketUpdateRate(newRate)
|
||||
}
|
||||
|
||||
func (a *adaptiveRateLimit) cubicSuccess(t time.Time) float64 {
|
||||
dt := secondsFloat64(t.Sub(a.lastThrottleTime))
|
||||
return (a.scaleConstant * math.Pow(dt-a.timeWindow, 3)) + a.lastMaxRate
|
||||
}
|
||||
|
||||
func (a *adaptiveRateLimit) cubicThrottle(rateToUse float64) float64 {
|
||||
return rateToUse * a.beta
|
||||
}
|
||||
|
||||
func (a *adaptiveRateLimit) calculateTimeWindow() {
|
||||
a.timeWindow = math.Pow((a.lastMaxRate*(1.-a.beta))/a.scaleConstant, 1./3.)
|
||||
}
|
||||
|
||||
func (a *adaptiveRateLimit) tokenBucketUpdateRate(newRPS float64) {
|
||||
a.tokenBucketRefill()
|
||||
a.fillRate = math.Max(newRPS, a.minFillRate)
|
||||
a.tokenBucket.Resize(newRPS)
|
||||
}
|
||||
|
||||
func (a *adaptiveRateLimit) updateMeasuredRate() {
|
||||
now := sdk.NowTime()
|
||||
timeBucket := math.Floor(timeFloat64Seconds(now)*2.) / 2.
|
||||
a.requestCount++
|
||||
|
||||
if timeBucket > a.lastTxRateBucket {
|
||||
currentRate := float64(a.requestCount) / (timeBucket - a.lastTxRateBucket)
|
||||
a.measuredTxRate = (currentRate * a.smooth) + (a.measuredTxRate * (1. - a.smooth))
|
||||
a.requestCount = 0
|
||||
a.lastTxRateBucket = timeBucket
|
||||
}
|
||||
}
|
||||
|
||||
func (a *adaptiveRateLimit) tokenBucketRefill() {
|
||||
now := sdk.NowTime()
|
||||
if a.lastRefilled.IsZero() {
|
||||
a.lastRefilled = now
|
||||
return
|
||||
}
|
||||
|
||||
fillAmount := secondsFloat64(now.Sub(a.lastRefilled)) * a.fillRate
|
||||
a.tokenBucket.Refund(fillAmount)
|
||||
a.lastRefilled = now
|
||||
}
|
||||
|
||||
func float64Seconds(v float64) time.Duration {
|
||||
return time.Duration(v * float64(time.Second))
|
||||
}
|
||||
|
||||
func secondsFloat64(v time.Duration) float64 {
|
||||
return float64(v) / float64(time.Second)
|
||||
}
|
||||
|
||||
func timeFloat64Seconds(v time.Time) float64 {
|
||||
return float64(v.UnixNano()) / float64(time.Second)
|
||||
}
|
||||
83
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/adaptive_token_bucket.go
generated
vendored
Normal file
83
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/adaptive_token_bucket.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
package retry
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// adaptiveTokenBucket provides a concurrency safe utility for adding and
|
||||
// removing tokens from the available token bucket.
|
||||
type adaptiveTokenBucket struct {
|
||||
remainingTokens float64
|
||||
maxCapacity float64
|
||||
minCapacity float64
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// newAdaptiveTokenBucket returns an initialized adaptiveTokenBucket with the
|
||||
// capacity specified.
|
||||
func newAdaptiveTokenBucket(i float64) *adaptiveTokenBucket {
|
||||
return &adaptiveTokenBucket{
|
||||
remainingTokens: i,
|
||||
maxCapacity: i,
|
||||
minCapacity: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve attempts to reduce the available tokens by the amount requested. If
|
||||
// there are tokens available true will be returned along with the number of
|
||||
// available tokens remaining. If amount requested is larger than the available
|
||||
// capacity, false will be returned along with the available capacity. If the
|
||||
// amount is less than the available capacity, the capacity will be reduced by
|
||||
// that amount, and the remaining capacity and true will be returned.
|
||||
func (t *adaptiveTokenBucket) Retrieve(amount float64) (available float64, retrieved bool) {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
if amount > t.remainingTokens {
|
||||
return t.remainingTokens, false
|
||||
}
|
||||
|
||||
t.remainingTokens -= amount
|
||||
return t.remainingTokens, true
|
||||
}
|
||||
|
||||
// Refund returns the amount of tokens back to the available token bucket, up
|
||||
// to the initial capacity.
|
||||
func (t *adaptiveTokenBucket) Refund(amount float64) {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
// Capacity cannot exceed max capacity.
|
||||
t.remainingTokens = math.Min(t.remainingTokens+amount, t.maxCapacity)
|
||||
}
|
||||
|
||||
// Capacity returns the maximum capacity of tokens that the bucket could
|
||||
// contain.
|
||||
func (t *adaptiveTokenBucket) Capacity() float64 {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
return t.maxCapacity
|
||||
}
|
||||
|
||||
// Remaining returns the number of tokens that remaining in the bucket.
|
||||
func (t *adaptiveTokenBucket) Remaining() float64 {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
return t.remainingTokens
|
||||
}
|
||||
|
||||
// Resize adjusts the size of the token bucket. Returns the capacity remaining.
|
||||
func (t *adaptiveTokenBucket) Resize(size float64) float64 {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
t.maxCapacity = math.Max(size, t.minCapacity)
|
||||
|
||||
// Capacity needs to be capped at max capacity, if max size reduced.
|
||||
t.remainingTokens = math.Min(t.remainingTokens, t.maxCapacity)
|
||||
|
||||
return t.remainingTokens
|
||||
}
|
||||
51
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/attempt_metrics.go
generated
vendored
Normal file
51
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/attempt_metrics.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package retry
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/aws/smithy-go/metrics"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
)
|
||||
|
||||
type attemptMetrics struct {
|
||||
Attempts metrics.Int64Counter
|
||||
Errors metrics.Int64Counter
|
||||
|
||||
AttemptDuration metrics.Float64Histogram
|
||||
}
|
||||
|
||||
func newAttemptMetrics(meter metrics.Meter) (*attemptMetrics, error) {
|
||||
m := &attemptMetrics{}
|
||||
var err error
|
||||
|
||||
m.Attempts, err = meter.Int64Counter("client.call.attempts", func(o *metrics.InstrumentOptions) {
|
||||
o.UnitLabel = "{attempt}"
|
||||
o.Description = "The number of attempts for an individual operation"
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.Errors, err = meter.Int64Counter("client.call.errors", func(o *metrics.InstrumentOptions) {
|
||||
o.UnitLabel = "{error}"
|
||||
o.Description = "The number of errors for an operation"
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.AttemptDuration, err = meter.Float64Histogram("client.call.attempt_duration", func(o *metrics.InstrumentOptions) {
|
||||
o.UnitLabel = "s"
|
||||
o.Description = "The time it takes to connect to the service, send the request, and get back HTTP status code and headers (including time queued waiting to be sent)"
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func withOperationMetadata(ctx context.Context) metrics.RecordMetricOption {
|
||||
return func(o *metrics.RecordMetricOptions) {
|
||||
o.Properties.Set("rpc.service", middleware.GetServiceID(ctx))
|
||||
o.Properties.Set("rpc.method", middleware.GetOperationName(ctx))
|
||||
}
|
||||
}
|
||||
80
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/doc.go
generated
vendored
Normal file
80
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/doc.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
// Package retry provides interfaces and implementations for SDK request retry behavior.
|
||||
//
|
||||
// # Retryer Interface and Implementations
|
||||
//
|
||||
// This package defines Retryer interface that is used to either implement custom retry behavior
|
||||
// or to extend the existing retry implementations provided by the SDK. This package provides a single
|
||||
// retry implementation: Standard.
|
||||
//
|
||||
// # Standard
|
||||
//
|
||||
// Standard is the default retryer implementation used by service clients. The standard retryer is a rate limited
|
||||
// retryer that has a configurable max attempts to limit the number of retry attempts when a retryable error occurs.
|
||||
// In addition, the retryer uses a configurable token bucket to rate limit the retry attempts across the client,
|
||||
// and uses an additional delay policy to limit the time between a requests subsequent attempts.
|
||||
//
|
||||
// By default the standard retryer uses the DefaultRetryables slice of IsErrorRetryable types to determine whether
|
||||
// a given error is retryable. By default this list of retryables includes the following:
|
||||
// - Retrying errors that implement the RetryableError method, and return true.
|
||||
// - Connection Errors
|
||||
// - Errors that implement a ConnectionError, Temporary, or Timeout method that return true.
|
||||
// - Connection Reset Errors.
|
||||
// - net.OpErr types that are dialing errors or are temporary.
|
||||
// - HTTP Status Codes: 500, 502, 503, and 504.
|
||||
// - API Error Codes
|
||||
// - RequestTimeout, RequestTimeoutException
|
||||
// - Throttling, ThrottlingException, ThrottledException, RequestThrottledException, TooManyRequestsException,
|
||||
// RequestThrottled, SlowDown, EC2ThrottledException
|
||||
// - ProvisionedThroughputExceededException, RequestLimitExceeded, BandwidthLimitExceeded, LimitExceededException
|
||||
// - TransactionInProgressException, PriorRequestNotComplete
|
||||
//
|
||||
// The standard retryer will not retry a request in the event if the context associated with the request
|
||||
// has been cancelled. Applications must handle this case explicitly if they wish to retry with a different context
|
||||
// value.
|
||||
//
|
||||
// You can configure the standard retryer implementation to fit your applications by constructing a standard retryer
|
||||
// using the NewStandard function, and providing one more functional argument that mutate the StandardOptions
|
||||
// structure. StandardOptions provides the ability to modify the token bucket rate limiter, retryable error conditions,
|
||||
// and the retry delay policy.
|
||||
//
|
||||
// For example to modify the default retry attempts for the standard retryer:
|
||||
//
|
||||
// // configure the custom retryer
|
||||
// customRetry := retry.NewStandard(func(o *retry.StandardOptions) {
|
||||
// o.MaxAttempts = 5
|
||||
// })
|
||||
//
|
||||
// // create a service client with the retryer
|
||||
// s3.NewFromConfig(cfg, func(o *s3.Options) {
|
||||
// o.Retryer = customRetry
|
||||
// })
|
||||
//
|
||||
// # Utilities
|
||||
//
|
||||
// A number of package functions have been provided to easily wrap retryer implementations in an implementation agnostic
|
||||
// way. These are:
|
||||
//
|
||||
// AddWithErrorCodes - Provides the ability to add additional API error codes that should be considered retryable
|
||||
// in addition to those considered retryable by the provided retryer.
|
||||
//
|
||||
// AddWithMaxAttempts - Provides the ability to set the max number of attempts for retrying a request by wrapping
|
||||
// a retryer implementation.
|
||||
//
|
||||
// AddWithMaxBackoffDelay - Provides the ability to set the max back off delay that can occur before retrying a
|
||||
// request by wrapping a retryer implementation.
|
||||
//
|
||||
// The following package functions have been provided to easily satisfy different retry interfaces to further customize
|
||||
// a given retryer's behavior:
|
||||
//
|
||||
// BackoffDelayerFunc - Can be used to wrap a function to satisfy the BackoffDelayer interface. For example,
|
||||
// you can use this method to easily create custom back off policies to be used with the
|
||||
// standard retryer.
|
||||
//
|
||||
// IsErrorRetryableFunc - Can be used to wrap a function to satisfy the IsErrorRetryable interface. For example,
|
||||
// this can be used to extend the standard retryer to add additional logic to determine if an
|
||||
// error should be retried.
|
||||
//
|
||||
// IsErrorTimeoutFunc - Can be used to wrap a function to satisfy IsErrorTimeout interface. For example,
|
||||
// this can be used to extend the standard retryer to add additional logic to determine if an
|
||||
// error should be considered a timeout.
|
||||
package retry
|
||||
20
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/errors.go
generated
vendored
Normal file
20
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/errors.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package retry
|
||||
|
||||
import "fmt"
|
||||
|
||||
// MaxAttemptsError provides the error when the maximum number of attempts have
|
||||
// been exceeded.
|
||||
type MaxAttemptsError struct {
|
||||
Attempt int
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *MaxAttemptsError) Error() string {
|
||||
return fmt.Sprintf("exceeded maximum number of attempts, %d, %v", e.Attempt, e.Err)
|
||||
}
|
||||
|
||||
// Unwrap returns the nested error causing the max attempts error. Provides the
|
||||
// implementation for errors.Is and errors.As to unwrap nested errors.
|
||||
func (e *MaxAttemptsError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
49
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/jitter_backoff.go
generated
vendored
Normal file
49
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/jitter_backoff.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package retry
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/internal/rand"
|
||||
"github.com/aws/aws-sdk-go-v2/internal/timeconv"
|
||||
)
|
||||
|
||||
// ExponentialJitterBackoff provides backoff delays with jitter based on the
|
||||
// number of attempts.
|
||||
type ExponentialJitterBackoff struct {
|
||||
maxBackoff time.Duration
|
||||
// precomputed number of attempts needed to reach max backoff.
|
||||
maxBackoffAttempts float64
|
||||
|
||||
randFloat64 func() (float64, error)
|
||||
}
|
||||
|
||||
// NewExponentialJitterBackoff returns an ExponentialJitterBackoff configured
|
||||
// for the max backoff.
|
||||
func NewExponentialJitterBackoff(maxBackoff time.Duration) *ExponentialJitterBackoff {
|
||||
return &ExponentialJitterBackoff{
|
||||
maxBackoff: maxBackoff,
|
||||
maxBackoffAttempts: math.Log2(
|
||||
float64(maxBackoff) / float64(time.Second)),
|
||||
randFloat64: rand.CryptoRandFloat64,
|
||||
}
|
||||
}
|
||||
|
||||
// BackoffDelay returns the duration to wait before the next attempt should be
|
||||
// made. Returns an error if unable get a duration.
|
||||
func (j *ExponentialJitterBackoff) BackoffDelay(attempt int, err error) (time.Duration, error) {
|
||||
if attempt > int(j.maxBackoffAttempts) {
|
||||
return j.maxBackoff, nil
|
||||
}
|
||||
|
||||
b, err := j.randFloat64()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// [0.0, 1.0) * 2 ^ attempts
|
||||
ri := int64(1 << uint64(attempt))
|
||||
delaySeconds := b * float64(ri)
|
||||
|
||||
return timeconv.FloatSecondsDur(delaySeconds), nil
|
||||
}
|
||||
52
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/metadata.go
generated
vendored
Normal file
52
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/metadata.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package retry
|
||||
|
||||
import (
|
||||
awsmiddle "github.com/aws/aws-sdk-go-v2/aws/middleware"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
)
|
||||
|
||||
// attemptResultsKey is a metadata accessor key to retrieve metadata
|
||||
// for all request attempts.
|
||||
type attemptResultsKey struct {
|
||||
}
|
||||
|
||||
// GetAttemptResults retrieves attempts results from middleware metadata.
|
||||
func GetAttemptResults(metadata middleware.Metadata) (AttemptResults, bool) {
|
||||
m, ok := metadata.Get(attemptResultsKey{}).(AttemptResults)
|
||||
return m, ok
|
||||
}
|
||||
|
||||
// AttemptResults represents struct containing metadata returned by all request attempts.
|
||||
type AttemptResults struct {
|
||||
|
||||
// Results is a slice consisting attempt result from all request attempts.
|
||||
// Results are stored in order request attempt is made.
|
||||
Results []AttemptResult
|
||||
}
|
||||
|
||||
// AttemptResult represents attempt result returned by a single request attempt.
|
||||
type AttemptResult struct {
|
||||
|
||||
// Err is the error if received for the request attempt.
|
||||
Err error
|
||||
|
||||
// Retryable denotes if request may be retried. This states if an
|
||||
// error is considered retryable.
|
||||
Retryable bool
|
||||
|
||||
// Retried indicates if this request was retried.
|
||||
Retried bool
|
||||
|
||||
// ResponseMetadata is any existing metadata passed via the response middlewares.
|
||||
ResponseMetadata middleware.Metadata
|
||||
}
|
||||
|
||||
// addAttemptResults adds attempt results to middleware metadata
|
||||
func addAttemptResults(metadata *middleware.Metadata, v AttemptResults) {
|
||||
metadata.Set(attemptResultsKey{}, v)
|
||||
}
|
||||
|
||||
// GetRawResponse returns raw response recorded for the attempt result
|
||||
func (a AttemptResult) GetRawResponse() interface{} {
|
||||
return awsmiddle.GetRawResponse(a.ResponseMetadata)
|
||||
}
|
||||
418
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/middleware.go
generated
vendored
Normal file
418
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/middleware.go
generated
vendored
Normal file
@@ -0,0 +1,418 @@
|
||||
package retry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
internalcontext "github.com/aws/aws-sdk-go-v2/internal/context"
|
||||
"github.com/aws/smithy-go"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
awsmiddle "github.com/aws/aws-sdk-go-v2/aws/middleware"
|
||||
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
||||
"github.com/aws/smithy-go/logging"
|
||||
"github.com/aws/smithy-go/metrics"
|
||||
smithymiddle "github.com/aws/smithy-go/middleware"
|
||||
"github.com/aws/smithy-go/tracing"
|
||||
"github.com/aws/smithy-go/transport/http"
|
||||
)
|
||||
|
||||
// RequestCloner is a function that can take an input request type and clone
|
||||
// the request for use in a subsequent retry attempt.
|
||||
type RequestCloner func(interface{}) interface{}
|
||||
|
||||
type retryMetadata struct {
|
||||
AttemptNum int
|
||||
AttemptTime time.Time
|
||||
MaxAttempts int
|
||||
AttemptClockSkew time.Duration
|
||||
}
|
||||
|
||||
// Attempt is a Smithy Finalize middleware that handles retry attempts using
|
||||
// the provided Retryer implementation.
|
||||
type Attempt struct {
|
||||
// Enable the logging of retry attempts performed by the SDK. This will
|
||||
// include logging retry attempts, unretryable errors, and when max
|
||||
// attempts are reached.
|
||||
LogAttempts bool
|
||||
|
||||
// A Meter instance for recording retry-related metrics.
|
||||
OperationMeter metrics.Meter
|
||||
|
||||
retryer aws.RetryerV2
|
||||
requestCloner RequestCloner
|
||||
}
|
||||
|
||||
// define the threshold at which we will consider certain kind of errors to be probably
|
||||
// caused by clock skew
|
||||
const skewThreshold = 4 * time.Minute
|
||||
|
||||
// NewAttemptMiddleware returns a new Attempt retry middleware.
|
||||
func NewAttemptMiddleware(retryer aws.Retryer, requestCloner RequestCloner, optFns ...func(*Attempt)) *Attempt {
|
||||
m := &Attempt{
|
||||
retryer: wrapAsRetryerV2(retryer),
|
||||
requestCloner: requestCloner,
|
||||
}
|
||||
for _, fn := range optFns {
|
||||
fn(m)
|
||||
}
|
||||
if m.OperationMeter == nil {
|
||||
m.OperationMeter = metrics.NopMeterProvider{}.Meter("")
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// ID returns the middleware identifier
|
||||
func (r *Attempt) ID() string { return "Retry" }
|
||||
|
||||
func (r Attempt) logf(logger logging.Logger, classification logging.Classification, format string, v ...interface{}) {
|
||||
if !r.LogAttempts {
|
||||
return
|
||||
}
|
||||
logger.Logf(classification, format, v...)
|
||||
}
|
||||
|
||||
// HandleFinalize utilizes the provider Retryer implementation to attempt
|
||||
// retries over the next handler
|
||||
func (r *Attempt) HandleFinalize(ctx context.Context, in smithymiddle.FinalizeInput, next smithymiddle.FinalizeHandler) (
|
||||
out smithymiddle.FinalizeOutput, metadata smithymiddle.Metadata, err error,
|
||||
) {
|
||||
var attemptNum int
|
||||
var attemptClockSkew time.Duration
|
||||
var attemptResults AttemptResults
|
||||
|
||||
maxAttempts := r.retryer.MaxAttempts()
|
||||
releaseRetryToken := nopRelease
|
||||
|
||||
retryMetrics, err := newAttemptMetrics(r.OperationMeter)
|
||||
if err != nil {
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
for {
|
||||
attemptNum++
|
||||
attemptInput := in
|
||||
attemptInput.Request = r.requestCloner(attemptInput.Request)
|
||||
|
||||
// Record the metadata for the for attempt being started.
|
||||
attemptCtx := setRetryMetadata(ctx, retryMetadata{
|
||||
AttemptNum: attemptNum,
|
||||
AttemptTime: sdk.NowTime().UTC(),
|
||||
MaxAttempts: maxAttempts,
|
||||
AttemptClockSkew: attemptClockSkew,
|
||||
})
|
||||
|
||||
// Setting clock skew to be used on other context (like signing)
|
||||
ctx = internalcontext.SetAttemptSkewContext(ctx, attemptClockSkew)
|
||||
|
||||
var attemptResult AttemptResult
|
||||
|
||||
attemptCtx, span := tracing.StartSpan(attemptCtx, "Attempt", func(o *tracing.SpanOptions) {
|
||||
o.Properties.Set("operation.attempt", attemptNum)
|
||||
})
|
||||
retryMetrics.Attempts.Add(ctx, 1, withOperationMetadata(ctx))
|
||||
|
||||
start := sdk.NowTime()
|
||||
out, attemptResult, releaseRetryToken, err = r.handleAttempt(attemptCtx, attemptInput, releaseRetryToken, next)
|
||||
elapsed := sdk.NowTime().Sub(start)
|
||||
|
||||
retryMetrics.AttemptDuration.Record(ctx, float64(elapsed)/1e9, withOperationMetadata(ctx))
|
||||
if err != nil {
|
||||
retryMetrics.Errors.Add(ctx, 1, withOperationMetadata(ctx), func(o *metrics.RecordMetricOptions) {
|
||||
o.Properties.Set("exception.type", errorType(err))
|
||||
})
|
||||
}
|
||||
|
||||
span.End()
|
||||
|
||||
attemptClockSkew, _ = awsmiddle.GetAttemptSkew(attemptResult.ResponseMetadata)
|
||||
|
||||
// AttemptResult Retried states that the attempt was not successful, and
|
||||
// should be retried.
|
||||
shouldRetry := attemptResult.Retried
|
||||
|
||||
// Add attempt metadata to list of all attempt metadata
|
||||
attemptResults.Results = append(attemptResults.Results, attemptResult)
|
||||
|
||||
if !shouldRetry {
|
||||
// Ensure the last response's metadata is used as the bases for result
|
||||
// metadata returned by the stack. The Slice of attempt results
|
||||
// will be added to this cloned metadata.
|
||||
metadata = attemptResult.ResponseMetadata.Clone()
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
addAttemptResults(&metadata, attemptResults)
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
// handleAttempt handles an individual request attempt.
|
||||
func (r *Attempt) handleAttempt(
|
||||
ctx context.Context, in smithymiddle.FinalizeInput, releaseRetryToken func(error) error, next smithymiddle.FinalizeHandler,
|
||||
) (
|
||||
out smithymiddle.FinalizeOutput, attemptResult AttemptResult, _ func(error) error, err error,
|
||||
) {
|
||||
defer func() {
|
||||
attemptResult.Err = err
|
||||
}()
|
||||
|
||||
// Short circuit if this attempt never can succeed because the context is
|
||||
// canceled. This reduces the chance of token pools being modified for
|
||||
// attempts that will not be made
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return out, attemptResult, nopRelease, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
//------------------------------
|
||||
// Get Attempt Token
|
||||
//------------------------------
|
||||
releaseAttemptToken, err := r.retryer.GetAttemptToken(ctx)
|
||||
if err != nil {
|
||||
return out, attemptResult, nopRelease, fmt.Errorf(
|
||||
"failed to get retry Send token, %w", err)
|
||||
}
|
||||
|
||||
//------------------------------
|
||||
// Send Attempt
|
||||
//------------------------------
|
||||
logger := smithymiddle.GetLogger(ctx)
|
||||
service, operation := awsmiddle.GetServiceID(ctx), awsmiddle.GetOperationName(ctx)
|
||||
retryMetadata, _ := getRetryMetadata(ctx)
|
||||
attemptNum := retryMetadata.AttemptNum
|
||||
maxAttempts := retryMetadata.MaxAttempts
|
||||
|
||||
// Following attempts must ensure the request payload stream starts in a
|
||||
// rewound state.
|
||||
if attemptNum > 1 {
|
||||
if rewindable, ok := in.Request.(interface{ RewindStream() error }); ok {
|
||||
if rewindErr := rewindable.RewindStream(); rewindErr != nil {
|
||||
return out, attemptResult, nopRelease, fmt.Errorf(
|
||||
"failed to rewind transport stream for retry, %w", rewindErr)
|
||||
}
|
||||
}
|
||||
|
||||
r.logf(logger, logging.Debug, "retrying request %s/%s, attempt %d",
|
||||
service, operation, attemptNum)
|
||||
}
|
||||
|
||||
var metadata smithymiddle.Metadata
|
||||
out, metadata, err = next.HandleFinalize(ctx, in)
|
||||
attemptResult.ResponseMetadata = metadata
|
||||
|
||||
//------------------------------
|
||||
// Bookkeeping
|
||||
//------------------------------
|
||||
// Release the retry token based on the state of the attempt's error (if any).
|
||||
if releaseError := releaseRetryToken(err); releaseError != nil && err != nil {
|
||||
return out, attemptResult, nopRelease, fmt.Errorf(
|
||||
"failed to release retry token after request error, %w", err)
|
||||
}
|
||||
// Release the attempt token based on the state of the attempt's error (if any).
|
||||
if releaseError := releaseAttemptToken(err); releaseError != nil && err != nil {
|
||||
return out, attemptResult, nopRelease, fmt.Errorf(
|
||||
"failed to release initial token after request error, %w", err)
|
||||
}
|
||||
// If there was no error making the attempt, nothing further to do. There
|
||||
// will be nothing to retry.
|
||||
if err == nil {
|
||||
return out, attemptResult, nopRelease, err
|
||||
}
|
||||
|
||||
err = wrapAsClockSkew(ctx, err)
|
||||
|
||||
//------------------------------
|
||||
// Is Retryable and Should Retry
|
||||
//------------------------------
|
||||
// If the attempt failed with an unretryable error, nothing further to do
|
||||
// but return, and inform the caller about the terminal failure.
|
||||
retryable := r.retryer.IsErrorRetryable(err)
|
||||
if !retryable {
|
||||
r.logf(logger, logging.Debug, "request failed with unretryable error %v", err)
|
||||
return out, attemptResult, nopRelease, err
|
||||
}
|
||||
|
||||
// set retryable to true
|
||||
attemptResult.Retryable = true
|
||||
|
||||
// Once the maximum number of attempts have been exhausted there is nothing
|
||||
// further to do other than inform the caller about the terminal failure.
|
||||
if maxAttempts > 0 && attemptNum >= maxAttempts {
|
||||
r.logf(logger, logging.Debug, "max retry attempts exhausted, max %d", maxAttempts)
|
||||
err = &MaxAttemptsError{
|
||||
Attempt: attemptNum,
|
||||
Err: err,
|
||||
}
|
||||
return out, attemptResult, nopRelease, err
|
||||
}
|
||||
|
||||
//------------------------------
|
||||
// Get Retry (aka Retry Quota) Token
|
||||
//------------------------------
|
||||
// Get a retry token that will be released after the
|
||||
releaseRetryToken, retryTokenErr := r.retryer.GetRetryToken(ctx, err)
|
||||
if retryTokenErr != nil {
|
||||
return out, attemptResult, nopRelease, retryTokenErr
|
||||
}
|
||||
|
||||
//------------------------------
|
||||
// Retry Delay and Sleep
|
||||
//------------------------------
|
||||
// Get the retry delay before another attempt can be made, and sleep for
|
||||
// that time. Potentially early exist if the sleep is canceled via the
|
||||
// context.
|
||||
retryDelay, reqErr := r.retryer.RetryDelay(attemptNum, err)
|
||||
if reqErr != nil {
|
||||
return out, attemptResult, releaseRetryToken, reqErr
|
||||
}
|
||||
if reqErr = sdk.SleepWithContext(ctx, retryDelay); reqErr != nil {
|
||||
err = &aws.RequestCanceledError{Err: reqErr}
|
||||
return out, attemptResult, releaseRetryToken, err
|
||||
}
|
||||
|
||||
// The request should be re-attempted.
|
||||
attemptResult.Retried = true
|
||||
|
||||
return out, attemptResult, releaseRetryToken, err
|
||||
}
|
||||
|
||||
// errors that, if detected when we know there's a clock skew,
|
||||
// can be retried and have a high chance of success
|
||||
var possibleSkewCodes = map[string]struct{}{
|
||||
"InvalidSignatureException": {},
|
||||
"SignatureDoesNotMatch": {},
|
||||
"AuthFailure": {},
|
||||
}
|
||||
|
||||
var definiteSkewCodes = map[string]struct{}{
|
||||
"RequestExpired": {},
|
||||
"RequestInTheFuture": {},
|
||||
"RequestTimeTooSkewed": {},
|
||||
}
|
||||
|
||||
// wrapAsClockSkew checks if this error could be related to a clock skew
|
||||
// error and if so, wrap the error.
|
||||
func wrapAsClockSkew(ctx context.Context, err error) error {
|
||||
var v interface{ ErrorCode() string }
|
||||
if !errors.As(err, &v) {
|
||||
return err
|
||||
}
|
||||
if _, ok := definiteSkewCodes[v.ErrorCode()]; ok {
|
||||
return &retryableClockSkewError{Err: err}
|
||||
}
|
||||
_, isPossibleSkewCode := possibleSkewCodes[v.ErrorCode()]
|
||||
if skew := internalcontext.GetAttemptSkewContext(ctx); skew > skewThreshold && isPossibleSkewCode {
|
||||
return &retryableClockSkewError{Err: err}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// MetricsHeader attaches SDK request metric header for retries to the transport
|
||||
type MetricsHeader struct{}
|
||||
|
||||
// ID returns the middleware identifier
|
||||
func (r *MetricsHeader) ID() string {
|
||||
return "RetryMetricsHeader"
|
||||
}
|
||||
|
||||
// HandleFinalize attaches the SDK request metric header to the transport layer
|
||||
func (r MetricsHeader) HandleFinalize(ctx context.Context, in smithymiddle.FinalizeInput, next smithymiddle.FinalizeHandler) (
|
||||
out smithymiddle.FinalizeOutput, metadata smithymiddle.Metadata, err error,
|
||||
) {
|
||||
retryMetadata, _ := getRetryMetadata(ctx)
|
||||
|
||||
const retryMetricHeader = "Amz-Sdk-Request"
|
||||
var parts []string
|
||||
|
||||
parts = append(parts, "attempt="+strconv.Itoa(retryMetadata.AttemptNum))
|
||||
if retryMetadata.MaxAttempts != 0 {
|
||||
parts = append(parts, "max="+strconv.Itoa(retryMetadata.MaxAttempts))
|
||||
}
|
||||
|
||||
var ttl time.Time
|
||||
if deadline, ok := ctx.Deadline(); ok {
|
||||
ttl = deadline
|
||||
}
|
||||
|
||||
// Only append the TTL if it can be determined.
|
||||
if !ttl.IsZero() && retryMetadata.AttemptClockSkew > 0 {
|
||||
const unixTimeFormat = "20060102T150405Z"
|
||||
ttl = ttl.Add(retryMetadata.AttemptClockSkew)
|
||||
parts = append(parts, "ttl="+ttl.Format(unixTimeFormat))
|
||||
}
|
||||
|
||||
switch req := in.Request.(type) {
|
||||
case *http.Request:
|
||||
req.Header[retryMetricHeader] = append(req.Header[retryMetricHeader][:0], strings.Join(parts, "; "))
|
||||
default:
|
||||
return out, metadata, fmt.Errorf("unknown transport type %T", req)
|
||||
}
|
||||
|
||||
return next.HandleFinalize(ctx, in)
|
||||
}
|
||||
|
||||
type retryMetadataKey struct{}
|
||||
|
||||
// getRetryMetadata retrieves retryMetadata from the context and a bool
|
||||
// indicating if it was set.
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
func getRetryMetadata(ctx context.Context) (metadata retryMetadata, ok bool) {
|
||||
metadata, ok = smithymiddle.GetStackValue(ctx, retryMetadataKey{}).(retryMetadata)
|
||||
return metadata, ok
|
||||
}
|
||||
|
||||
// setRetryMetadata sets the retryMetadata on the context.
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
func setRetryMetadata(ctx context.Context, metadata retryMetadata) context.Context {
|
||||
return smithymiddle.WithStackValue(ctx, retryMetadataKey{}, metadata)
|
||||
}
|
||||
|
||||
// AddRetryMiddlewaresOptions is the set of options that can be passed to
|
||||
// AddRetryMiddlewares for configuring retry associated middleware.
|
||||
type AddRetryMiddlewaresOptions struct {
|
||||
Retryer aws.Retryer
|
||||
|
||||
// Enable the logging of retry attempts performed by the SDK. This will
|
||||
// include logging retry attempts, unretryable errors, and when max
|
||||
// attempts are reached.
|
||||
LogRetryAttempts bool
|
||||
}
|
||||
|
||||
// AddRetryMiddlewares adds retry middleware to operation middleware stack
|
||||
func AddRetryMiddlewares(stack *smithymiddle.Stack, options AddRetryMiddlewaresOptions) error {
|
||||
attempt := NewAttemptMiddleware(options.Retryer, http.RequestCloner, func(middleware *Attempt) {
|
||||
middleware.LogAttempts = options.LogRetryAttempts
|
||||
})
|
||||
|
||||
// index retry to before signing, if signing exists
|
||||
if err := stack.Finalize.Insert(attempt, "Signing", smithymiddle.Before); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := stack.Finalize.Insert(&MetricsHeader{}, attempt.ID(), smithymiddle.After); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Determines the value of exception.type for metrics purposes. We prefer an
|
||||
// API-specific error code, otherwise it's just the Go type for the value.
|
||||
func errorType(err error) string {
|
||||
var terr smithy.APIError
|
||||
if errors.As(err, &terr) {
|
||||
return terr.ErrorCode()
|
||||
}
|
||||
return fmt.Sprintf("%T", err)
|
||||
}
|
||||
90
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/retry.go
generated
vendored
Normal file
90
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/retry.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
package retry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
)
|
||||
|
||||
// AddWithErrorCodes returns a Retryer with additional error codes considered
|
||||
// for determining if the error should be retried.
|
||||
func AddWithErrorCodes(r aws.Retryer, codes ...string) aws.Retryer {
|
||||
retryable := &RetryableErrorCode{
|
||||
Codes: map[string]struct{}{},
|
||||
}
|
||||
for _, c := range codes {
|
||||
retryable.Codes[c] = struct{}{}
|
||||
}
|
||||
|
||||
return &withIsErrorRetryable{
|
||||
RetryerV2: wrapAsRetryerV2(r),
|
||||
Retryable: retryable,
|
||||
}
|
||||
}
|
||||
|
||||
type withIsErrorRetryable struct {
|
||||
aws.RetryerV2
|
||||
Retryable IsErrorRetryable
|
||||
}
|
||||
|
||||
func (r *withIsErrorRetryable) IsErrorRetryable(err error) bool {
|
||||
if v := r.Retryable.IsErrorRetryable(err); v != aws.UnknownTernary {
|
||||
return v.Bool()
|
||||
}
|
||||
return r.RetryerV2.IsErrorRetryable(err)
|
||||
}
|
||||
|
||||
// AddWithMaxAttempts returns a Retryer with MaxAttempts set to the value
|
||||
// specified.
|
||||
func AddWithMaxAttempts(r aws.Retryer, max int) aws.Retryer {
|
||||
return &withMaxAttempts{
|
||||
RetryerV2: wrapAsRetryerV2(r),
|
||||
Max: max,
|
||||
}
|
||||
}
|
||||
|
||||
type withMaxAttempts struct {
|
||||
aws.RetryerV2
|
||||
Max int
|
||||
}
|
||||
|
||||
func (w *withMaxAttempts) MaxAttempts() int {
|
||||
return w.Max
|
||||
}
|
||||
|
||||
// AddWithMaxBackoffDelay returns a retryer wrapping the passed in retryer
|
||||
// overriding the RetryDelay behavior for a alternate minimum initial backoff
|
||||
// delay.
|
||||
func AddWithMaxBackoffDelay(r aws.Retryer, delay time.Duration) aws.Retryer {
|
||||
return &withMaxBackoffDelay{
|
||||
RetryerV2: wrapAsRetryerV2(r),
|
||||
backoff: NewExponentialJitterBackoff(delay),
|
||||
}
|
||||
}
|
||||
|
||||
type withMaxBackoffDelay struct {
|
||||
aws.RetryerV2
|
||||
backoff *ExponentialJitterBackoff
|
||||
}
|
||||
|
||||
func (r *withMaxBackoffDelay) RetryDelay(attempt int, err error) (time.Duration, error) {
|
||||
return r.backoff.BackoffDelay(attempt, err)
|
||||
}
|
||||
|
||||
type wrappedAsRetryerV2 struct {
|
||||
aws.Retryer
|
||||
}
|
||||
|
||||
func wrapAsRetryerV2(r aws.Retryer) aws.RetryerV2 {
|
||||
v, ok := r.(aws.RetryerV2)
|
||||
if !ok {
|
||||
v = wrappedAsRetryerV2{Retryer: r}
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func (w wrappedAsRetryerV2) GetAttemptToken(context.Context) (func(error) error, error) {
|
||||
return w.Retryer.GetInitialToken(), nil
|
||||
}
|
||||
228
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/retryable_error.go
generated
vendored
Normal file
228
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/retryable_error.go
generated
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
package retry
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
)
|
||||
|
||||
// IsErrorRetryable provides the interface of an implementation to determine if
|
||||
// a error as the result of an operation is retryable.
|
||||
type IsErrorRetryable interface {
|
||||
IsErrorRetryable(error) aws.Ternary
|
||||
}
|
||||
|
||||
// IsErrorRetryables is a collection of checks to determine of the error is
|
||||
// retryable. Iterates through the checks and returns the state of retryable
|
||||
// if any check returns something other than unknown.
|
||||
type IsErrorRetryables []IsErrorRetryable
|
||||
|
||||
// IsErrorRetryable returns if the error is retryable if any of the checks in
|
||||
// the list return a value other than unknown.
|
||||
func (r IsErrorRetryables) IsErrorRetryable(err error) aws.Ternary {
|
||||
for _, re := range r {
|
||||
if v := re.IsErrorRetryable(err); v != aws.UnknownTernary {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return aws.UnknownTernary
|
||||
}
|
||||
|
||||
// IsErrorRetryableFunc wraps a function with the IsErrorRetryable interface.
|
||||
type IsErrorRetryableFunc func(error) aws.Ternary
|
||||
|
||||
// IsErrorRetryable returns if the error is retryable.
|
||||
func (fn IsErrorRetryableFunc) IsErrorRetryable(err error) aws.Ternary {
|
||||
return fn(err)
|
||||
}
|
||||
|
||||
// RetryableError is an IsErrorRetryable implementation which uses the
|
||||
// optional interface Retryable on the error value to determine if the error is
|
||||
// retryable.
|
||||
type RetryableError struct{}
|
||||
|
||||
// IsErrorRetryable returns if the error is retryable if it satisfies the
|
||||
// Retryable interface, and returns if the attempt should be retried.
|
||||
func (RetryableError) IsErrorRetryable(err error) aws.Ternary {
|
||||
var v interface{ RetryableError() bool }
|
||||
|
||||
if !errors.As(err, &v) {
|
||||
return aws.UnknownTernary
|
||||
}
|
||||
|
||||
return aws.BoolTernary(v.RetryableError())
|
||||
}
|
||||
|
||||
// NoRetryCanceledError detects if the error was an request canceled error and
|
||||
// returns if so.
|
||||
type NoRetryCanceledError struct{}
|
||||
|
||||
// IsErrorRetryable returns the error is not retryable if the request was
|
||||
// canceled.
|
||||
func (NoRetryCanceledError) IsErrorRetryable(err error) aws.Ternary {
|
||||
var v interface{ CanceledError() bool }
|
||||
|
||||
if !errors.As(err, &v) {
|
||||
return aws.UnknownTernary
|
||||
}
|
||||
|
||||
if v.CanceledError() {
|
||||
return aws.FalseTernary
|
||||
}
|
||||
return aws.UnknownTernary
|
||||
}
|
||||
|
||||
// RetryableConnectionError determines if the underlying error is an HTTP
|
||||
// connection and returns if it should be retried.
|
||||
//
|
||||
// Includes errors such as connection reset, connection refused, net dial,
|
||||
// temporary, and timeout errors.
|
||||
type RetryableConnectionError struct{}
|
||||
|
||||
// IsErrorRetryable returns if the error is caused by and HTTP connection
|
||||
// error, and should be retried.
|
||||
func (r RetryableConnectionError) IsErrorRetryable(err error) aws.Ternary {
|
||||
if err == nil {
|
||||
return aws.UnknownTernary
|
||||
}
|
||||
var retryable bool
|
||||
|
||||
var conErr interface{ ConnectionError() bool }
|
||||
var tempErr interface{ Temporary() bool }
|
||||
var timeoutErr interface{ Timeout() bool }
|
||||
var urlErr *url.Error
|
||||
var netOpErr *net.OpError
|
||||
var dnsError *net.DNSError
|
||||
|
||||
if errors.As(err, &dnsError) {
|
||||
// NXDOMAIN errors should not be retried
|
||||
if dnsError.IsNotFound {
|
||||
return aws.BoolTernary(false)
|
||||
}
|
||||
|
||||
// if !dnsError.Temporary(), error may or may not be temporary,
|
||||
// (i.e. !Temporary() =/=> !retryable) so we should fall through to
|
||||
// remaining checks
|
||||
if dnsError.Temporary() {
|
||||
return aws.BoolTernary(true)
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case errors.As(err, &conErr) && conErr.ConnectionError():
|
||||
retryable = true
|
||||
|
||||
case strings.Contains(err.Error(), "use of closed network connection"):
|
||||
fallthrough
|
||||
case strings.Contains(err.Error(), "connection reset"):
|
||||
// The errors "connection reset" and "use of closed network connection"
|
||||
// are effectively the same. It appears to be the difference between
|
||||
// sync and async read of TCP RST in the stdlib's net.Conn read loop.
|
||||
// see #2737
|
||||
retryable = true
|
||||
|
||||
case errors.As(err, &urlErr):
|
||||
// Refused connections should be retried as the service may not yet be
|
||||
// running on the port. Go TCP dial considers refused connections as
|
||||
// not temporary.
|
||||
if strings.Contains(urlErr.Error(), "connection refused") {
|
||||
retryable = true
|
||||
} else {
|
||||
return r.IsErrorRetryable(errors.Unwrap(urlErr))
|
||||
}
|
||||
|
||||
case errors.As(err, &netOpErr):
|
||||
// Network dial, or temporary network errors are always retryable.
|
||||
if strings.EqualFold(netOpErr.Op, "dial") || netOpErr.Temporary() {
|
||||
retryable = true
|
||||
} else {
|
||||
return r.IsErrorRetryable(errors.Unwrap(netOpErr))
|
||||
}
|
||||
|
||||
case errors.As(err, &tempErr) && tempErr.Temporary():
|
||||
// Fallback to the generic temporary check, with temporary errors
|
||||
// retryable.
|
||||
retryable = true
|
||||
|
||||
case errors.As(err, &timeoutErr) && timeoutErr.Timeout():
|
||||
// Fallback to the generic timeout check, with timeout errors
|
||||
// retryable.
|
||||
retryable = true
|
||||
|
||||
default:
|
||||
return aws.UnknownTernary
|
||||
}
|
||||
|
||||
return aws.BoolTernary(retryable)
|
||||
|
||||
}
|
||||
|
||||
// RetryableHTTPStatusCode provides a IsErrorRetryable based on HTTP status
|
||||
// codes.
|
||||
type RetryableHTTPStatusCode struct {
|
||||
Codes map[int]struct{}
|
||||
}
|
||||
|
||||
// IsErrorRetryable return if the passed in error is retryable based on the
|
||||
// HTTP status code.
|
||||
func (r RetryableHTTPStatusCode) IsErrorRetryable(err error) aws.Ternary {
|
||||
var v interface{ HTTPStatusCode() int }
|
||||
|
||||
if !errors.As(err, &v) {
|
||||
return aws.UnknownTernary
|
||||
}
|
||||
|
||||
_, ok := r.Codes[v.HTTPStatusCode()]
|
||||
if !ok {
|
||||
return aws.UnknownTernary
|
||||
}
|
||||
|
||||
return aws.TrueTernary
|
||||
}
|
||||
|
||||
// RetryableErrorCode determines if an attempt should be retried based on the
|
||||
// API error code.
|
||||
type RetryableErrorCode struct {
|
||||
Codes map[string]struct{}
|
||||
}
|
||||
|
||||
// IsErrorRetryable return if the error is retryable based on the error codes.
|
||||
// Returns unknown if the error doesn't have a code or it is unknown.
|
||||
func (r RetryableErrorCode) IsErrorRetryable(err error) aws.Ternary {
|
||||
var v interface{ ErrorCode() string }
|
||||
|
||||
if !errors.As(err, &v) {
|
||||
return aws.UnknownTernary
|
||||
}
|
||||
|
||||
_, ok := r.Codes[v.ErrorCode()]
|
||||
if !ok {
|
||||
return aws.UnknownTernary
|
||||
}
|
||||
|
||||
return aws.TrueTernary
|
||||
}
|
||||
|
||||
// retryableClockSkewError marks errors that can be caused by clock skew
|
||||
// (difference between server time and client time).
|
||||
// This is returned when there's certain confidence that adjusting the client time
|
||||
// could allow a retry to succeed
|
||||
type retryableClockSkewError struct{ Err error }
|
||||
|
||||
func (e *retryableClockSkewError) Error() string {
|
||||
return fmt.Sprintf("Probable clock skew error: %v", e.Err)
|
||||
}
|
||||
|
||||
// Unwrap returns the wrapped error.
|
||||
func (e *retryableClockSkewError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// RetryableError allows the retryer to retry this request
|
||||
func (e *retryableClockSkewError) RetryableError() bool {
|
||||
return true
|
||||
}
|
||||
269
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/standard.go
generated
vendored
Normal file
269
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/standard.go
generated
vendored
Normal file
@@ -0,0 +1,269 @@
|
||||
package retry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws/ratelimit"
|
||||
)
|
||||
|
||||
// BackoffDelayer provides the interface for determining the delay to before
|
||||
// another request attempt, that previously failed.
|
||||
type BackoffDelayer interface {
|
||||
BackoffDelay(attempt int, err error) (time.Duration, error)
|
||||
}
|
||||
|
||||
// BackoffDelayerFunc provides a wrapper around a function to determine the
|
||||
// backoff delay of an attempt retry.
|
||||
type BackoffDelayerFunc func(int, error) (time.Duration, error)
|
||||
|
||||
// BackoffDelay returns the delay before attempt to retry a request.
|
||||
func (fn BackoffDelayerFunc) BackoffDelay(attempt int, err error) (time.Duration, error) {
|
||||
return fn(attempt, err)
|
||||
}
|
||||
|
||||
const (
|
||||
// DefaultMaxAttempts is the maximum of attempts for an API request
|
||||
DefaultMaxAttempts int = 3
|
||||
|
||||
// DefaultMaxBackoff is the maximum back off delay between attempts
|
||||
DefaultMaxBackoff time.Duration = 20 * time.Second
|
||||
)
|
||||
|
||||
// Default retry token quota values.
|
||||
const (
|
||||
DefaultRetryRateTokens uint = 500
|
||||
DefaultRetryCost uint = 5
|
||||
DefaultRetryTimeoutCost uint = 10
|
||||
DefaultNoRetryIncrement uint = 1
|
||||
)
|
||||
|
||||
// DefaultRetryableHTTPStatusCodes is the default set of HTTP status codes the SDK
|
||||
// should consider as retryable errors.
|
||||
var DefaultRetryableHTTPStatusCodes = map[int]struct{}{
|
||||
500: {},
|
||||
502: {},
|
||||
503: {},
|
||||
504: {},
|
||||
}
|
||||
|
||||
// DefaultRetryableErrorCodes provides the set of API error codes that should
|
||||
// be retried.
|
||||
var DefaultRetryableErrorCodes = map[string]struct{}{
|
||||
"RequestTimeout": {},
|
||||
"RequestTimeoutException": {},
|
||||
}
|
||||
|
||||
// DefaultThrottleErrorCodes provides the set of API error codes that are
|
||||
// considered throttle errors.
|
||||
var DefaultThrottleErrorCodes = map[string]struct{}{
|
||||
"Throttling": {},
|
||||
"ThrottlingException": {},
|
||||
"ThrottledException": {},
|
||||
"RequestThrottledException": {},
|
||||
"TooManyRequestsException": {},
|
||||
"ProvisionedThroughputExceededException": {},
|
||||
"TransactionInProgressException": {},
|
||||
"RequestLimitExceeded": {},
|
||||
"BandwidthLimitExceeded": {},
|
||||
"LimitExceededException": {},
|
||||
"RequestThrottled": {},
|
||||
"SlowDown": {},
|
||||
"PriorRequestNotComplete": {},
|
||||
"EC2ThrottledException": {},
|
||||
}
|
||||
|
||||
// DefaultRetryables provides the set of retryable checks that are used by
|
||||
// default.
|
||||
var DefaultRetryables = []IsErrorRetryable{
|
||||
NoRetryCanceledError{},
|
||||
RetryableError{},
|
||||
RetryableConnectionError{},
|
||||
RetryableHTTPStatusCode{
|
||||
Codes: DefaultRetryableHTTPStatusCodes,
|
||||
},
|
||||
RetryableErrorCode{
|
||||
Codes: DefaultRetryableErrorCodes,
|
||||
},
|
||||
RetryableErrorCode{
|
||||
Codes: DefaultThrottleErrorCodes,
|
||||
},
|
||||
}
|
||||
|
||||
// DefaultTimeouts provides the set of timeout checks that are used by default.
|
||||
var DefaultTimeouts = []IsErrorTimeout{
|
||||
TimeouterError{},
|
||||
}
|
||||
|
||||
// StandardOptions provides the functional options for configuring the standard
|
||||
// retryable, and delay behavior.
|
||||
type StandardOptions struct {
|
||||
// Maximum number of attempts that should be made.
|
||||
MaxAttempts int
|
||||
|
||||
// MaxBackoff duration between retried attempts.
|
||||
MaxBackoff time.Duration
|
||||
|
||||
// Provides the backoff strategy the retryer will use to determine the
|
||||
// delay between retry attempts.
|
||||
Backoff BackoffDelayer
|
||||
|
||||
// Set of strategies to determine if the attempt should be retried based on
|
||||
// the error response received.
|
||||
//
|
||||
// It is safe to append to this list in NewStandard's functional options.
|
||||
Retryables []IsErrorRetryable
|
||||
|
||||
// Set of strategies to determine if the attempt failed due to a timeout
|
||||
// error.
|
||||
//
|
||||
// It is safe to append to this list in NewStandard's functional options.
|
||||
Timeouts []IsErrorTimeout
|
||||
|
||||
// Provides the rate limiting strategy for rate limiting attempt retries
|
||||
// across all attempts the retryer is being used with.
|
||||
//
|
||||
// A RateLimiter operates as a token bucket with a set capacity, where
|
||||
// attempt failures events consume tokens. A retry attempt that attempts to
|
||||
// consume more tokens than what's available results in operation failure.
|
||||
// The default implementation is parameterized as follows:
|
||||
// - a capacity of 500 (DefaultRetryRateTokens)
|
||||
// - a retry caused by a timeout costs 10 tokens (DefaultRetryCost)
|
||||
// - a retry caused by other errors costs 5 tokens (DefaultRetryTimeoutCost)
|
||||
// - an operation that succeeds on the 1st attempt adds 1 token (DefaultNoRetryIncrement)
|
||||
//
|
||||
// You can disable rate limiting by setting this field to ratelimit.None.
|
||||
RateLimiter RateLimiter
|
||||
|
||||
// The cost to deduct from the RateLimiter's token bucket per retry.
|
||||
RetryCost uint
|
||||
|
||||
// The cost to deduct from the RateLimiter's token bucket per retry caused
|
||||
// by timeout error.
|
||||
RetryTimeoutCost uint
|
||||
|
||||
// The cost to payback to the RateLimiter's token bucket for successful
|
||||
// attempts.
|
||||
NoRetryIncrement uint
|
||||
}
|
||||
|
||||
// RateLimiter provides the interface for limiting the rate of attempt retries
|
||||
// allowed by the retryer.
|
||||
type RateLimiter interface {
|
||||
GetToken(ctx context.Context, cost uint) (releaseToken func() error, err error)
|
||||
AddTokens(uint) error
|
||||
}
|
||||
|
||||
// Standard is the standard retry pattern for the SDK. It uses a set of
|
||||
// retryable checks to determine of the failed attempt should be retried, and
|
||||
// what retry delay should be used.
|
||||
type Standard struct {
|
||||
options StandardOptions
|
||||
|
||||
timeout IsErrorTimeout
|
||||
retryable IsErrorRetryable
|
||||
backoff BackoffDelayer
|
||||
}
|
||||
|
||||
// NewStandard initializes a standard retry behavior with defaults that can be
|
||||
// overridden via functional options.
|
||||
func NewStandard(fnOpts ...func(*StandardOptions)) *Standard {
|
||||
o := StandardOptions{
|
||||
MaxAttempts: DefaultMaxAttempts,
|
||||
MaxBackoff: DefaultMaxBackoff,
|
||||
Retryables: append([]IsErrorRetryable{}, DefaultRetryables...),
|
||||
Timeouts: append([]IsErrorTimeout{}, DefaultTimeouts...),
|
||||
|
||||
RateLimiter: ratelimit.NewTokenRateLimit(DefaultRetryRateTokens),
|
||||
RetryCost: DefaultRetryCost,
|
||||
RetryTimeoutCost: DefaultRetryTimeoutCost,
|
||||
NoRetryIncrement: DefaultNoRetryIncrement,
|
||||
}
|
||||
for _, fn := range fnOpts {
|
||||
fn(&o)
|
||||
}
|
||||
if o.MaxAttempts <= 0 {
|
||||
o.MaxAttempts = DefaultMaxAttempts
|
||||
}
|
||||
|
||||
backoff := o.Backoff
|
||||
if backoff == nil {
|
||||
backoff = NewExponentialJitterBackoff(o.MaxBackoff)
|
||||
}
|
||||
|
||||
return &Standard{
|
||||
options: o,
|
||||
backoff: backoff,
|
||||
retryable: IsErrorRetryables(o.Retryables),
|
||||
timeout: IsErrorTimeouts(o.Timeouts),
|
||||
}
|
||||
}
|
||||
|
||||
// MaxAttempts returns the maximum number of attempts that can be made for a
|
||||
// request before failing.
|
||||
func (s *Standard) MaxAttempts() int {
|
||||
return s.options.MaxAttempts
|
||||
}
|
||||
|
||||
// IsErrorRetryable returns if the error is can be retried or not. Should not
|
||||
// consider the number of attempts made.
|
||||
func (s *Standard) IsErrorRetryable(err error) bool {
|
||||
return s.retryable.IsErrorRetryable(err).Bool()
|
||||
}
|
||||
|
||||
// RetryDelay returns the delay to use before another request attempt is made.
|
||||
func (s *Standard) RetryDelay(attempt int, err error) (time.Duration, error) {
|
||||
return s.backoff.BackoffDelay(attempt, err)
|
||||
}
|
||||
|
||||
// GetAttemptToken returns the token to be released after then attempt completes.
|
||||
// The release token will add NoRetryIncrement to the RateLimiter token pool if
|
||||
// the attempt was successful. If the attempt failed, nothing will be done.
|
||||
func (s *Standard) GetAttemptToken(context.Context) (func(error) error, error) {
|
||||
return s.GetInitialToken(), nil
|
||||
}
|
||||
|
||||
// GetInitialToken returns a token for adding the NoRetryIncrement to the
|
||||
// RateLimiter token if the attempt completed successfully without error.
|
||||
//
|
||||
// InitialToken applies to result of the each attempt, including the first.
|
||||
// Whereas the RetryToken applies to the result of subsequent attempts.
|
||||
//
|
||||
// Deprecated: use GetAttemptToken instead.
|
||||
func (s *Standard) GetInitialToken() func(error) error {
|
||||
return releaseToken(s.noRetryIncrement).release
|
||||
}
|
||||
|
||||
func (s *Standard) noRetryIncrement() error {
|
||||
return s.options.RateLimiter.AddTokens(s.options.NoRetryIncrement)
|
||||
}
|
||||
|
||||
// GetRetryToken attempts to deduct the retry cost from the retry token pool.
|
||||
// Returning the token release function, or error.
|
||||
func (s *Standard) GetRetryToken(ctx context.Context, opErr error) (func(error) error, error) {
|
||||
cost := s.options.RetryCost
|
||||
|
||||
if s.timeout.IsErrorTimeout(opErr).Bool() {
|
||||
cost = s.options.RetryTimeoutCost
|
||||
}
|
||||
|
||||
fn, err := s.options.RateLimiter.GetToken(ctx, cost)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get rate limit token, %w", err)
|
||||
}
|
||||
|
||||
return releaseToken(fn).release, nil
|
||||
}
|
||||
|
||||
func nopRelease(error) error { return nil }
|
||||
|
||||
type releaseToken func() error
|
||||
|
||||
func (f releaseToken) release(err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return f()
|
||||
}
|
||||
60
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/throttle_error.go
generated
vendored
Normal file
60
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/throttle_error.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package retry
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
)
|
||||
|
||||
// IsErrorThrottle provides the interface of an implementation to determine if
|
||||
// a error response from an operation is a throttling error.
|
||||
type IsErrorThrottle interface {
|
||||
IsErrorThrottle(error) aws.Ternary
|
||||
}
|
||||
|
||||
// IsErrorThrottles is a collection of checks to determine of the error a
|
||||
// throttle error. Iterates through the checks and returns the state of
|
||||
// throttle if any check returns something other than unknown.
|
||||
type IsErrorThrottles []IsErrorThrottle
|
||||
|
||||
// IsErrorThrottle returns if the error is a throttle error if any of the
|
||||
// checks in the list return a value other than unknown.
|
||||
func (r IsErrorThrottles) IsErrorThrottle(err error) aws.Ternary {
|
||||
for _, re := range r {
|
||||
if v := re.IsErrorThrottle(err); v != aws.UnknownTernary {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return aws.UnknownTernary
|
||||
}
|
||||
|
||||
// IsErrorThrottleFunc wraps a function with the IsErrorThrottle interface.
|
||||
type IsErrorThrottleFunc func(error) aws.Ternary
|
||||
|
||||
// IsErrorThrottle returns if the error is a throttle error.
|
||||
func (fn IsErrorThrottleFunc) IsErrorThrottle(err error) aws.Ternary {
|
||||
return fn(err)
|
||||
}
|
||||
|
||||
// ThrottleErrorCode determines if an attempt should be retried based on the
|
||||
// API error code.
|
||||
type ThrottleErrorCode struct {
|
||||
Codes map[string]struct{}
|
||||
}
|
||||
|
||||
// IsErrorThrottle return if the error is a throttle error based on the error
|
||||
// codes. Returns unknown if the error doesn't have a code or it is unknown.
|
||||
func (r ThrottleErrorCode) IsErrorThrottle(err error) aws.Ternary {
|
||||
var v interface{ ErrorCode() string }
|
||||
|
||||
if !errors.As(err, &v) {
|
||||
return aws.UnknownTernary
|
||||
}
|
||||
|
||||
_, ok := r.Codes[v.ErrorCode()]
|
||||
if !ok {
|
||||
return aws.UnknownTernary
|
||||
}
|
||||
|
||||
return aws.TrueTernary
|
||||
}
|
||||
52
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/timeout_error.go
generated
vendored
Normal file
52
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/timeout_error.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package retry
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
)
|
||||
|
||||
// IsErrorTimeout provides the interface of an implementation to determine if
|
||||
// a error matches.
|
||||
type IsErrorTimeout interface {
|
||||
IsErrorTimeout(err error) aws.Ternary
|
||||
}
|
||||
|
||||
// IsErrorTimeouts is a collection of checks to determine of the error is
|
||||
// retryable. Iterates through the checks and returns the state of retryable
|
||||
// if any check returns something other than unknown.
|
||||
type IsErrorTimeouts []IsErrorTimeout
|
||||
|
||||
// IsErrorTimeout returns if the error is retryable if any of the checks in
|
||||
// the list return a value other than unknown.
|
||||
func (ts IsErrorTimeouts) IsErrorTimeout(err error) aws.Ternary {
|
||||
for _, t := range ts {
|
||||
if v := t.IsErrorTimeout(err); v != aws.UnknownTernary {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return aws.UnknownTernary
|
||||
}
|
||||
|
||||
// IsErrorTimeoutFunc wraps a function with the IsErrorTimeout interface.
|
||||
type IsErrorTimeoutFunc func(error) aws.Ternary
|
||||
|
||||
// IsErrorTimeout returns if the error is retryable.
|
||||
func (fn IsErrorTimeoutFunc) IsErrorTimeout(err error) aws.Ternary {
|
||||
return fn(err)
|
||||
}
|
||||
|
||||
// TimeouterError provides the IsErrorTimeout implementation for determining if
|
||||
// an error is a timeout based on type with the Timeout method.
|
||||
type TimeouterError struct{}
|
||||
|
||||
// IsErrorTimeout returns if the error is a timeout error.
|
||||
func (t TimeouterError) IsErrorTimeout(err error) aws.Ternary {
|
||||
var v interface{ Timeout() bool }
|
||||
|
||||
if !errors.As(err, &v) {
|
||||
return aws.UnknownTernary
|
||||
}
|
||||
|
||||
return aws.BoolTernary(v.Timeout())
|
||||
}
|
||||
127
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retryer.go
generated
vendored
Normal file
127
go/vendor/github.com/aws/aws-sdk-go-v2/aws/retryer.go
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
package aws
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RetryMode provides the mode the API client will use to create a retryer
|
||||
// based on.
|
||||
type RetryMode string
|
||||
|
||||
const (
|
||||
// RetryModeStandard model provides rate limited retry attempts with
|
||||
// exponential backoff delay.
|
||||
RetryModeStandard RetryMode = "standard"
|
||||
|
||||
// RetryModeAdaptive model provides attempt send rate limiting on throttle
|
||||
// responses in addition to standard mode's retry rate limiting.
|
||||
//
|
||||
// Adaptive retry mode is experimental and is subject to change in the
|
||||
// future.
|
||||
RetryModeAdaptive RetryMode = "adaptive"
|
||||
)
|
||||
|
||||
// ParseRetryMode attempts to parse a RetryMode from the given string.
|
||||
// Returning error if the value is not a known RetryMode.
|
||||
func ParseRetryMode(v string) (mode RetryMode, err error) {
|
||||
switch v {
|
||||
case "standard":
|
||||
return RetryModeStandard, nil
|
||||
case "adaptive":
|
||||
return RetryModeAdaptive, nil
|
||||
default:
|
||||
return mode, fmt.Errorf("unknown RetryMode, %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func (m RetryMode) String() string { return string(m) }
|
||||
|
||||
// Retryer is an interface to determine if a given error from a
|
||||
// attempt should be retried, and if so what backoff delay to apply. The
|
||||
// default implementation used by most services is the retry package's Standard
|
||||
// type. Which contains basic retry logic using exponential backoff.
|
||||
type Retryer interface {
|
||||
// IsErrorRetryable returns if the failed attempt is retryable. This check
|
||||
// should determine if the error can be retried, or if the error is
|
||||
// terminal.
|
||||
IsErrorRetryable(error) bool
|
||||
|
||||
// MaxAttempts returns the maximum number of attempts that can be made for
|
||||
// an attempt before failing. A value of 0 implies that the attempt should
|
||||
// be retried until it succeeds if the errors are retryable.
|
||||
MaxAttempts() int
|
||||
|
||||
// RetryDelay returns the delay that should be used before retrying the
|
||||
// attempt. Will return error if the delay could not be determined.
|
||||
RetryDelay(attempt int, opErr error) (time.Duration, error)
|
||||
|
||||
// GetRetryToken attempts to deduct the retry cost from the retry token pool.
|
||||
// Returning the token release function, or error.
|
||||
GetRetryToken(ctx context.Context, opErr error) (releaseToken func(error) error, err error)
|
||||
|
||||
// GetInitialToken returns the initial attempt token that can increment the
|
||||
// retry token pool if the attempt is successful.
|
||||
GetInitialToken() (releaseToken func(error) error)
|
||||
}
|
||||
|
||||
// RetryerV2 is an interface to determine if a given error from an attempt
|
||||
// should be retried, and if so what backoff delay to apply. The default
|
||||
// implementation used by most services is the retry package's Standard type.
|
||||
// Which contains basic retry logic using exponential backoff.
|
||||
//
|
||||
// RetryerV2 replaces the Retryer interface, deprecating the GetInitialToken
|
||||
// method in favor of GetAttemptToken which takes a context, and can return an error.
|
||||
//
|
||||
// The SDK's retry package's Attempt middleware, and utilities will always
|
||||
// wrap a Retryer as a RetryerV2. Delegating to GetInitialToken, only if
|
||||
// GetAttemptToken is not implemented.
|
||||
type RetryerV2 interface {
|
||||
Retryer
|
||||
|
||||
// GetInitialToken returns the initial attempt token that can increment the
|
||||
// retry token pool if the attempt is successful.
|
||||
//
|
||||
// Deprecated: This method does not provide a way to block using Context,
|
||||
// nor can it return an error. Use RetryerV2, and GetAttemptToken instead.
|
||||
GetInitialToken() (releaseToken func(error) error)
|
||||
|
||||
// GetAttemptToken returns the send token that can be used to rate limit
|
||||
// attempt calls. Will be used by the SDK's retry package's Attempt
|
||||
// middleware to get a send token prior to calling the temp and releasing
|
||||
// the send token after the attempt has been made.
|
||||
GetAttemptToken(context.Context) (func(error) error, error)
|
||||
}
|
||||
|
||||
// NopRetryer provides a RequestRetryDecider implementation that will flag
|
||||
// all attempt errors as not retryable, with a max attempts of 1.
|
||||
type NopRetryer struct{}
|
||||
|
||||
// IsErrorRetryable returns false for all error values.
|
||||
func (NopRetryer) IsErrorRetryable(error) bool { return false }
|
||||
|
||||
// MaxAttempts always returns 1 for the original attempt.
|
||||
func (NopRetryer) MaxAttempts() int { return 1 }
|
||||
|
||||
// RetryDelay is not valid for the NopRetryer. Will always return error.
|
||||
func (NopRetryer) RetryDelay(int, error) (time.Duration, error) {
|
||||
return 0, fmt.Errorf("not retrying any attempt errors")
|
||||
}
|
||||
|
||||
// GetRetryToken returns a stub function that does nothing.
|
||||
func (NopRetryer) GetRetryToken(context.Context, error) (func(error) error, error) {
|
||||
return nopReleaseToken, nil
|
||||
}
|
||||
|
||||
// GetInitialToken returns a stub function that does nothing.
|
||||
func (NopRetryer) GetInitialToken() func(error) error {
|
||||
return nopReleaseToken
|
||||
}
|
||||
|
||||
// GetAttemptToken returns a stub function that does nothing.
|
||||
func (NopRetryer) GetAttemptToken(context.Context) (func(error) error, error) {
|
||||
return nopReleaseToken, nil
|
||||
}
|
||||
|
||||
func nopReleaseToken(error) error { return nil }
|
||||
14
go/vendor/github.com/aws/aws-sdk-go-v2/aws/runtime.go
generated
vendored
Normal file
14
go/vendor/github.com/aws/aws-sdk-go-v2/aws/runtime.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
package aws
|
||||
|
||||
// ExecutionEnvironmentID is the AWS execution environment runtime identifier.
|
||||
type ExecutionEnvironmentID string
|
||||
|
||||
// RuntimeEnvironment is a collection of values that are determined at runtime
|
||||
// based on the environment that the SDK is executing in. Some of these values
|
||||
// may or may not be present based on the executing environment and certain SDK
|
||||
// configuration properties that drive whether these values are populated..
|
||||
type RuntimeEnvironment struct {
|
||||
EnvironmentIdentifier ExecutionEnvironmentID
|
||||
Region string
|
||||
EC2InstanceMetadataRegion string
|
||||
}
|
||||
115
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/cache.go
generated
vendored
Normal file
115
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/cache.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
package v4
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
)
|
||||
|
||||
func lookupKey(service, region string) string {
|
||||
var s strings.Builder
|
||||
s.Grow(len(region) + len(service) + 3)
|
||||
s.WriteString(region)
|
||||
s.WriteRune('/')
|
||||
s.WriteString(service)
|
||||
return s.String()
|
||||
}
|
||||
|
||||
type derivedKey struct {
|
||||
AccessKey string
|
||||
Date time.Time
|
||||
Credential []byte
|
||||
}
|
||||
|
||||
type derivedKeyCache struct {
|
||||
values map[string]derivedKey
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
func newDerivedKeyCache() derivedKeyCache {
|
||||
return derivedKeyCache{
|
||||
values: make(map[string]derivedKey),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *derivedKeyCache) Get(credentials aws.Credentials, service, region string, signingTime SigningTime) []byte {
|
||||
key := lookupKey(service, region)
|
||||
s.mutex.RLock()
|
||||
if cred, ok := s.get(key, credentials, signingTime.Time); ok {
|
||||
s.mutex.RUnlock()
|
||||
return cred
|
||||
}
|
||||
s.mutex.RUnlock()
|
||||
|
||||
s.mutex.Lock()
|
||||
if cred, ok := s.get(key, credentials, signingTime.Time); ok {
|
||||
s.mutex.Unlock()
|
||||
return cred
|
||||
}
|
||||
cred := deriveKey(credentials.SecretAccessKey, service, region, signingTime)
|
||||
entry := derivedKey{
|
||||
AccessKey: credentials.AccessKeyID,
|
||||
Date: signingTime.Time,
|
||||
Credential: cred,
|
||||
}
|
||||
s.values[key] = entry
|
||||
s.mutex.Unlock()
|
||||
|
||||
return cred
|
||||
}
|
||||
|
||||
func (s *derivedKeyCache) get(key string, credentials aws.Credentials, signingTime time.Time) ([]byte, bool) {
|
||||
cacheEntry, ok := s.retrieveFromCache(key)
|
||||
if ok && cacheEntry.AccessKey == credentials.AccessKeyID && isSameDay(signingTime, cacheEntry.Date) {
|
||||
return cacheEntry.Credential, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (s *derivedKeyCache) retrieveFromCache(key string) (derivedKey, bool) {
|
||||
if v, ok := s.values[key]; ok {
|
||||
return v, true
|
||||
}
|
||||
return derivedKey{}, false
|
||||
}
|
||||
|
||||
// SigningKeyDeriver derives a signing key from a set of credentials
|
||||
type SigningKeyDeriver struct {
|
||||
cache derivedKeyCache
|
||||
}
|
||||
|
||||
// NewSigningKeyDeriver returns a new SigningKeyDeriver
|
||||
func NewSigningKeyDeriver() *SigningKeyDeriver {
|
||||
return &SigningKeyDeriver{
|
||||
cache: newDerivedKeyCache(),
|
||||
}
|
||||
}
|
||||
|
||||
// DeriveKey returns a derived signing key from the given credentials to be used with SigV4 signing.
|
||||
func (k *SigningKeyDeriver) DeriveKey(credential aws.Credentials, service, region string, signingTime SigningTime) []byte {
|
||||
return k.cache.Get(credential, service, region, signingTime)
|
||||
}
|
||||
|
||||
func deriveKey(secret, service, region string, t SigningTime) []byte {
|
||||
hmacDate := HMACSHA256([]byte("AWS4"+secret), []byte(t.ShortTimeFormat()))
|
||||
hmacRegion := HMACSHA256(hmacDate, []byte(region))
|
||||
hmacService := HMACSHA256(hmacRegion, []byte(service))
|
||||
return HMACSHA256(hmacService, []byte("aws4_request"))
|
||||
}
|
||||
|
||||
func isSameDay(x, y time.Time) bool {
|
||||
xYear, xMonth, xDay := x.Date()
|
||||
yYear, yMonth, yDay := y.Date()
|
||||
|
||||
if xYear != yYear {
|
||||
return false
|
||||
}
|
||||
|
||||
if xMonth != yMonth {
|
||||
return false
|
||||
}
|
||||
|
||||
return xDay == yDay
|
||||
}
|
||||
40
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/const.go
generated
vendored
Normal file
40
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/const.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package v4
|
||||
|
||||
// Signature Version 4 (SigV4) Constants
|
||||
const (
|
||||
// EmptyStringSHA256 is the hex encoded sha256 value of an empty string
|
||||
EmptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`
|
||||
|
||||
// UnsignedPayload indicates that the request payload body is unsigned
|
||||
UnsignedPayload = "UNSIGNED-PAYLOAD"
|
||||
|
||||
// AmzAlgorithmKey indicates the signing algorithm
|
||||
AmzAlgorithmKey = "X-Amz-Algorithm"
|
||||
|
||||
// AmzSecurityTokenKey indicates the security token to be used with temporary credentials
|
||||
AmzSecurityTokenKey = "X-Amz-Security-Token"
|
||||
|
||||
// AmzDateKey is the UTC timestamp for the request in the format YYYYMMDD'T'HHMMSS'Z'
|
||||
AmzDateKey = "X-Amz-Date"
|
||||
|
||||
// AmzCredentialKey is the access key ID and credential scope
|
||||
AmzCredentialKey = "X-Amz-Credential"
|
||||
|
||||
// AmzSignedHeadersKey is the set of headers signed for the request
|
||||
AmzSignedHeadersKey = "X-Amz-SignedHeaders"
|
||||
|
||||
// AmzSignatureKey is the query parameter to store the SigV4 signature
|
||||
AmzSignatureKey = "X-Amz-Signature"
|
||||
|
||||
// TimeFormat is the time format to be used in the X-Amz-Date header or query parameter
|
||||
TimeFormat = "20060102T150405Z"
|
||||
|
||||
// ShortTimeFormat is the shorten time format used in the credential scope
|
||||
ShortTimeFormat = "20060102"
|
||||
|
||||
// ContentSHAKey is the SHA256 of request body
|
||||
ContentSHAKey = "X-Amz-Content-Sha256"
|
||||
|
||||
// StreamingEventsPayload indicates that the request payload body is a signed event stream.
|
||||
StreamingEventsPayload = "STREAMING-AWS4-HMAC-SHA256-EVENTS"
|
||||
)
|
||||
82
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/header_rules.go
generated
vendored
Normal file
82
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/header_rules.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
package v4
|
||||
|
||||
import (
|
||||
sdkstrings "github.com/aws/aws-sdk-go-v2/internal/strings"
|
||||
)
|
||||
|
||||
// Rules houses a set of Rule needed for validation of a
|
||||
// string value
|
||||
type Rules []Rule
|
||||
|
||||
// Rule interface allows for more flexible rules and just simply
|
||||
// checks whether or not a value adheres to that Rule
|
||||
type Rule interface {
|
||||
IsValid(value string) bool
|
||||
}
|
||||
|
||||
// IsValid will iterate through all rules and see if any rules
|
||||
// apply to the value and supports nested rules
|
||||
func (r Rules) IsValid(value string) bool {
|
||||
for _, rule := range r {
|
||||
if rule.IsValid(value) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// MapRule generic Rule for maps
|
||||
type MapRule map[string]struct{}
|
||||
|
||||
// IsValid for the map Rule satisfies whether it exists in the map
|
||||
func (m MapRule) IsValid(value string) bool {
|
||||
_, ok := m[value]
|
||||
return ok
|
||||
}
|
||||
|
||||
// AllowList is a generic Rule for include listing
|
||||
type AllowList struct {
|
||||
Rule
|
||||
}
|
||||
|
||||
// IsValid for AllowList checks if the value is within the AllowList
|
||||
func (w AllowList) IsValid(value string) bool {
|
||||
return w.Rule.IsValid(value)
|
||||
}
|
||||
|
||||
// ExcludeList is a generic Rule for exclude listing
|
||||
type ExcludeList struct {
|
||||
Rule
|
||||
}
|
||||
|
||||
// IsValid for AllowList checks if the value is within the AllowList
|
||||
func (b ExcludeList) IsValid(value string) bool {
|
||||
return !b.Rule.IsValid(value)
|
||||
}
|
||||
|
||||
// Patterns is a list of strings to match against
|
||||
type Patterns []string
|
||||
|
||||
// IsValid for Patterns checks each pattern and returns if a match has
|
||||
// been found
|
||||
func (p Patterns) IsValid(value string) bool {
|
||||
for _, pattern := range p {
|
||||
if sdkstrings.HasPrefixFold(value, pattern) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// InclusiveRules rules allow for rules to depend on one another
|
||||
type InclusiveRules []Rule
|
||||
|
||||
// IsValid will return true if all rules are true
|
||||
func (r InclusiveRules) IsValid(value string) bool {
|
||||
for _, rule := range r {
|
||||
if !rule.IsValid(value) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
70
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/headers.go
generated
vendored
Normal file
70
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/headers.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
package v4
|
||||
|
||||
// IgnoredHeaders is a list of headers that are ignored during signing
|
||||
var IgnoredHeaders = Rules{
|
||||
ExcludeList{
|
||||
MapRule{
|
||||
"Authorization": struct{}{},
|
||||
"User-Agent": struct{}{},
|
||||
"X-Amzn-Trace-Id": struct{}{},
|
||||
"Expect": struct{}{},
|
||||
"Transfer-Encoding": struct{}{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// RequiredSignedHeaders is a allow list for Build canonical headers.
|
||||
var RequiredSignedHeaders = Rules{
|
||||
AllowList{
|
||||
MapRule{
|
||||
"Cache-Control": struct{}{},
|
||||
"Content-Disposition": struct{}{},
|
||||
"Content-Encoding": struct{}{},
|
||||
"Content-Language": struct{}{},
|
||||
"Content-Md5": struct{}{},
|
||||
"Content-Type": struct{}{},
|
||||
"Expires": struct{}{},
|
||||
"If-Match": struct{}{},
|
||||
"If-Modified-Since": struct{}{},
|
||||
"If-None-Match": struct{}{},
|
||||
"If-Unmodified-Since": struct{}{},
|
||||
"Range": struct{}{},
|
||||
"X-Amz-Acl": struct{}{},
|
||||
"X-Amz-Copy-Source": struct{}{},
|
||||
"X-Amz-Copy-Source-If-Match": struct{}{},
|
||||
"X-Amz-Copy-Source-If-Modified-Since": struct{}{},
|
||||
"X-Amz-Copy-Source-If-None-Match": struct{}{},
|
||||
"X-Amz-Copy-Source-If-Unmodified-Since": struct{}{},
|
||||
"X-Amz-Copy-Source-Range": struct{}{},
|
||||
"X-Amz-Copy-Source-Server-Side-Encryption-Customer-Algorithm": struct{}{},
|
||||
"X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key": struct{}{},
|
||||
"X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-Md5": struct{}{},
|
||||
"X-Amz-Grant-Full-control": struct{}{},
|
||||
"X-Amz-Grant-Read": struct{}{},
|
||||
"X-Amz-Grant-Read-Acp": struct{}{},
|
||||
"X-Amz-Grant-Write": struct{}{},
|
||||
"X-Amz-Grant-Write-Acp": struct{}{},
|
||||
"X-Amz-Metadata-Directive": struct{}{},
|
||||
"X-Amz-Mfa": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption-Context": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption-Customer-Algorithm": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption-Customer-Key": struct{}{},
|
||||
"X-Amz-Server-Side-Encryption-Customer-Key-Md5": struct{}{},
|
||||
"X-Amz-Storage-Class": struct{}{},
|
||||
"X-Amz-Website-Redirect-Location": struct{}{},
|
||||
"X-Amz-Content-Sha256": struct{}{},
|
||||
"X-Amz-Tagging": struct{}{},
|
||||
},
|
||||
},
|
||||
Patterns{"X-Amz-Object-Lock-"},
|
||||
Patterns{"X-Amz-Meta-"},
|
||||
}
|
||||
|
||||
// AllowedQueryHoisting is a allowed list for Build query headers. The boolean value
|
||||
// represents whether or not it is a pattern.
|
||||
var AllowedQueryHoisting = InclusiveRules{
|
||||
ExcludeList{RequiredSignedHeaders},
|
||||
Patterns{"X-Amz-"},
|
||||
}
|
||||
13
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/hmac.go
generated
vendored
Normal file
13
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/hmac.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package v4
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
)
|
||||
|
||||
// HMACSHA256 computes a HMAC-SHA256 of data given the provided key.
|
||||
func HMACSHA256(key []byte, data []byte) []byte {
|
||||
hash := hmac.New(sha256.New, key)
|
||||
hash.Write(data)
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
75
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/host.go
generated
vendored
Normal file
75
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/host.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
package v4
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SanitizeHostForHeader removes default port from host and updates request.Host
|
||||
func SanitizeHostForHeader(r *http.Request) {
|
||||
host := getHost(r)
|
||||
port := portOnly(host)
|
||||
if port != "" && isDefaultPort(r.URL.Scheme, port) {
|
||||
r.Host = stripPort(host)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns host from request
|
||||
func getHost(r *http.Request) string {
|
||||
if r.Host != "" {
|
||||
return r.Host
|
||||
}
|
||||
|
||||
return r.URL.Host
|
||||
}
|
||||
|
||||
// Hostname returns u.Host, without any port number.
|
||||
//
|
||||
// If Host is an IPv6 literal with a port number, Hostname returns the
|
||||
// IPv6 literal without the square brackets. IPv6 literals may include
|
||||
// a zone identifier.
|
||||
//
|
||||
// Copied from the Go 1.8 standard library (net/url)
|
||||
func stripPort(hostport string) string {
|
||||
colon := strings.IndexByte(hostport, ':')
|
||||
if colon == -1 {
|
||||
return hostport
|
||||
}
|
||||
if i := strings.IndexByte(hostport, ']'); i != -1 {
|
||||
return strings.TrimPrefix(hostport[:i], "[")
|
||||
}
|
||||
return hostport[:colon]
|
||||
}
|
||||
|
||||
// Port returns the port part of u.Host, without the leading colon.
|
||||
// If u.Host doesn't contain a port, Port returns an empty string.
|
||||
//
|
||||
// Copied from the Go 1.8 standard library (net/url)
|
||||
func portOnly(hostport string) string {
|
||||
colon := strings.IndexByte(hostport, ':')
|
||||
if colon == -1 {
|
||||
return ""
|
||||
}
|
||||
if i := strings.Index(hostport, "]:"); i != -1 {
|
||||
return hostport[i+len("]:"):]
|
||||
}
|
||||
if strings.Contains(hostport, "]") {
|
||||
return ""
|
||||
}
|
||||
return hostport[colon+len(":"):]
|
||||
}
|
||||
|
||||
// Returns true if the specified URI is using the standard port
|
||||
// (i.e. port 80 for HTTP URIs or 443 for HTTPS URIs)
|
||||
func isDefaultPort(scheme, port string) bool {
|
||||
if port == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
lowerCaseScheme := strings.ToLower(scheme)
|
||||
if (lowerCaseScheme == "http" && port == "80") || (lowerCaseScheme == "https" && port == "443") {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
13
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/scope.go
generated
vendored
Normal file
13
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/scope.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package v4
|
||||
|
||||
import "strings"
|
||||
|
||||
// BuildCredentialScope builds the Signature Version 4 (SigV4) signing scope
|
||||
func BuildCredentialScope(signingTime SigningTime, region, service string) string {
|
||||
return strings.Join([]string{
|
||||
signingTime.ShortTimeFormat(),
|
||||
region,
|
||||
service,
|
||||
"aws4_request",
|
||||
}, "/")
|
||||
}
|
||||
36
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/time.go
generated
vendored
Normal file
36
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/time.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package v4
|
||||
|
||||
import "time"
|
||||
|
||||
// SigningTime provides a wrapper around a time.Time which provides cached values for SigV4 signing.
|
||||
type SigningTime struct {
|
||||
time.Time
|
||||
timeFormat string
|
||||
shortTimeFormat string
|
||||
}
|
||||
|
||||
// NewSigningTime creates a new SigningTime given a time.Time
|
||||
func NewSigningTime(t time.Time) SigningTime {
|
||||
return SigningTime{
|
||||
Time: t,
|
||||
}
|
||||
}
|
||||
|
||||
// TimeFormat provides a time formatted in the X-Amz-Date format.
|
||||
func (m *SigningTime) TimeFormat() string {
|
||||
return m.format(&m.timeFormat, TimeFormat)
|
||||
}
|
||||
|
||||
// ShortTimeFormat provides a time formatted of 20060102.
|
||||
func (m *SigningTime) ShortTimeFormat() string {
|
||||
return m.format(&m.shortTimeFormat, ShortTimeFormat)
|
||||
}
|
||||
|
||||
func (m *SigningTime) format(target *string, format string) string {
|
||||
if len(*target) > 0 {
|
||||
return *target
|
||||
}
|
||||
v := m.Time.Format(format)
|
||||
*target = v
|
||||
return v
|
||||
}
|
||||
80
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/util.go
generated
vendored
Normal file
80
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/util.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
package v4
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const doubleSpace = " "
|
||||
|
||||
// StripExcessSpaces will rewrite the passed in slice's string values to not
|
||||
// contain multiple side-by-side spaces.
|
||||
func StripExcessSpaces(str string) string {
|
||||
var j, k, l, m, spaces int
|
||||
// Trim trailing spaces
|
||||
for j = len(str) - 1; j >= 0 && str[j] == ' '; j-- {
|
||||
}
|
||||
|
||||
// Trim leading spaces
|
||||
for k = 0; k < j && str[k] == ' '; k++ {
|
||||
}
|
||||
str = str[k : j+1]
|
||||
|
||||
// Strip multiple spaces.
|
||||
j = strings.Index(str, doubleSpace)
|
||||
if j < 0 {
|
||||
return str
|
||||
}
|
||||
|
||||
buf := []byte(str)
|
||||
for k, m, l = j, j, len(buf); k < l; k++ {
|
||||
if buf[k] == ' ' {
|
||||
if spaces == 0 {
|
||||
// First space.
|
||||
buf[m] = buf[k]
|
||||
m++
|
||||
}
|
||||
spaces++
|
||||
} else {
|
||||
// End of multiple spaces.
|
||||
spaces = 0
|
||||
buf[m] = buf[k]
|
||||
m++
|
||||
}
|
||||
}
|
||||
|
||||
return string(buf[:m])
|
||||
}
|
||||
|
||||
// GetURIPath returns the escaped URI component from the provided URL.
|
||||
func GetURIPath(u *url.URL) string {
|
||||
var uriPath string
|
||||
|
||||
if len(u.Opaque) > 0 {
|
||||
const schemeSep, pathSep, queryStart = "//", "/", "?"
|
||||
|
||||
opaque := u.Opaque
|
||||
// Cut off the query string if present.
|
||||
if idx := strings.Index(opaque, queryStart); idx >= 0 {
|
||||
opaque = opaque[:idx]
|
||||
}
|
||||
|
||||
// Cutout the scheme separator if present.
|
||||
if strings.Index(opaque, schemeSep) == 0 {
|
||||
opaque = opaque[len(schemeSep):]
|
||||
}
|
||||
|
||||
// capture URI path starting with first path separator.
|
||||
if idx := strings.Index(opaque, pathSep); idx >= 0 {
|
||||
uriPath = opaque[idx:]
|
||||
}
|
||||
} else {
|
||||
uriPath = u.EscapedPath()
|
||||
}
|
||||
|
||||
if len(uriPath) == 0 {
|
||||
uriPath = "/"
|
||||
}
|
||||
|
||||
return uriPath
|
||||
}
|
||||
420
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/middleware.go
generated
vendored
Normal file
420
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/middleware.go
generated
vendored
Normal file
@@ -0,0 +1,420 @@
|
||||
package v4
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
|
||||
v4Internal "github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4"
|
||||
internalauth "github.com/aws/aws-sdk-go-v2/internal/auth"
|
||||
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
"github.com/aws/smithy-go/tracing"
|
||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
)
|
||||
|
||||
const computePayloadHashMiddlewareID = "ComputePayloadHash"
|
||||
|
||||
// HashComputationError indicates an error occurred while computing the signing hash
|
||||
type HashComputationError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
// Error is the error message
|
||||
func (e *HashComputationError) Error() string {
|
||||
return fmt.Sprintf("failed to compute payload hash: %v", e.Err)
|
||||
}
|
||||
|
||||
// Unwrap returns the underlying error if one is set
|
||||
func (e *HashComputationError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// SigningError indicates an error condition occurred while performing SigV4 signing
|
||||
type SigningError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *SigningError) Error() string {
|
||||
return fmt.Sprintf("failed to sign request: %v", e.Err)
|
||||
}
|
||||
|
||||
// Unwrap returns the underlying error cause
|
||||
func (e *SigningError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// UseDynamicPayloadSigningMiddleware swaps the compute payload sha256 middleware with a resolver middleware that
|
||||
// switches between unsigned and signed payload based on TLS state for request.
|
||||
// This middleware should not be used for AWS APIs that do not support unsigned payload signing auth.
|
||||
// By default, SDK uses this middleware for known AWS APIs that support such TLS based auth selection .
|
||||
//
|
||||
// Usage example -
|
||||
// S3 PutObject API allows unsigned payload signing auth usage when TLS is enabled, and uses this middleware to
|
||||
// dynamically switch between unsigned and signed payload based on TLS state for request.
|
||||
func UseDynamicPayloadSigningMiddleware(stack *middleware.Stack) error {
|
||||
_, err := stack.Finalize.Swap(computePayloadHashMiddlewareID, &dynamicPayloadSigningMiddleware{})
|
||||
return err
|
||||
}
|
||||
|
||||
// dynamicPayloadSigningMiddleware dynamically resolves the middleware that computes and set payload sha256 middleware.
|
||||
type dynamicPayloadSigningMiddleware struct {
|
||||
}
|
||||
|
||||
// ID returns the resolver identifier
|
||||
func (m *dynamicPayloadSigningMiddleware) ID() string {
|
||||
return computePayloadHashMiddlewareID
|
||||
}
|
||||
|
||||
// HandleFinalize delegates SHA256 computation according to whether the request
|
||||
// is TLS-enabled.
|
||||
func (m *dynamicPayloadSigningMiddleware) HandleFinalize(
|
||||
ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
|
||||
) (
|
||||
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
req, ok := in.Request.(*smithyhttp.Request)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("unknown transport type %T", in.Request)
|
||||
}
|
||||
|
||||
if req.IsHTTPS() {
|
||||
return (&UnsignedPayload{}).HandleFinalize(ctx, in, next)
|
||||
}
|
||||
return (&ComputePayloadSHA256{}).HandleFinalize(ctx, in, next)
|
||||
}
|
||||
|
||||
// UnsignedPayload sets the SigV4 request payload hash to unsigned.
|
||||
//
|
||||
// Will not set the Unsigned Payload magic SHA value, if a SHA has already been
|
||||
// stored in the context. (e.g. application pre-computed SHA256 before making
|
||||
// API call).
|
||||
//
|
||||
// This middleware does not check the X-Amz-Content-Sha256 header, if that
|
||||
// header is serialized a middleware must translate it into the context.
|
||||
type UnsignedPayload struct{}
|
||||
|
||||
// AddUnsignedPayloadMiddleware adds unsignedPayload to the operation
|
||||
// middleware stack
|
||||
func AddUnsignedPayloadMiddleware(stack *middleware.Stack) error {
|
||||
return stack.Finalize.Insert(&UnsignedPayload{}, "ResolveEndpointV2", middleware.After)
|
||||
}
|
||||
|
||||
// ID returns the unsignedPayload identifier
|
||||
func (m *UnsignedPayload) ID() string {
|
||||
return computePayloadHashMiddlewareID
|
||||
}
|
||||
|
||||
// HandleFinalize sets the payload hash magic value to the unsigned sentinel.
|
||||
func (m *UnsignedPayload) HandleFinalize(
|
||||
ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
|
||||
) (
|
||||
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
if GetPayloadHash(ctx) == "" {
|
||||
ctx = SetPayloadHash(ctx, v4Internal.UnsignedPayload)
|
||||
}
|
||||
return next.HandleFinalize(ctx, in)
|
||||
}
|
||||
|
||||
// ComputePayloadSHA256 computes SHA256 payload hash to sign.
|
||||
//
|
||||
// Will not set the Unsigned Payload magic SHA value, if a SHA has already been
|
||||
// stored in the context. (e.g. application pre-computed SHA256 before making
|
||||
// API call).
|
||||
//
|
||||
// This middleware does not check the X-Amz-Content-Sha256 header, if that
|
||||
// header is serialized a middleware must translate it into the context.
|
||||
type ComputePayloadSHA256 struct{}
|
||||
|
||||
// AddComputePayloadSHA256Middleware adds computePayloadSHA256 to the
|
||||
// operation middleware stack
|
||||
func AddComputePayloadSHA256Middleware(stack *middleware.Stack) error {
|
||||
return stack.Finalize.Insert(&ComputePayloadSHA256{}, "ResolveEndpointV2", middleware.After)
|
||||
}
|
||||
|
||||
// RemoveComputePayloadSHA256Middleware removes computePayloadSHA256 from the
|
||||
// operation middleware stack
|
||||
func RemoveComputePayloadSHA256Middleware(stack *middleware.Stack) error {
|
||||
_, err := stack.Finalize.Remove(computePayloadHashMiddlewareID)
|
||||
return err
|
||||
}
|
||||
|
||||
// ID is the middleware name
|
||||
func (m *ComputePayloadSHA256) ID() string {
|
||||
return computePayloadHashMiddlewareID
|
||||
}
|
||||
|
||||
// HandleFinalize computes the payload hash for the request, storing it to the
|
||||
// context. This is a no-op if a caller has previously set that value.
|
||||
func (m *ComputePayloadSHA256) HandleFinalize(
|
||||
ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
|
||||
) (
|
||||
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
if GetPayloadHash(ctx) != "" {
|
||||
return next.HandleFinalize(ctx, in)
|
||||
}
|
||||
|
||||
_, span := tracing.StartSpan(ctx, "ComputePayloadSHA256")
|
||||
defer span.End()
|
||||
|
||||
req, ok := in.Request.(*smithyhttp.Request)
|
||||
if !ok {
|
||||
return out, metadata, &HashComputationError{
|
||||
Err: fmt.Errorf("unexpected request middleware type %T", in.Request),
|
||||
}
|
||||
}
|
||||
|
||||
hash := sha256.New()
|
||||
if stream := req.GetStream(); stream != nil {
|
||||
_, err = io.Copy(hash, stream)
|
||||
if err != nil {
|
||||
return out, metadata, &HashComputationError{
|
||||
Err: fmt.Errorf("failed to compute payload hash, %w", err),
|
||||
}
|
||||
}
|
||||
|
||||
if err := req.RewindStream(); err != nil {
|
||||
return out, metadata, &HashComputationError{
|
||||
Err: fmt.Errorf("failed to seek body to start, %w", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx = SetPayloadHash(ctx, hex.EncodeToString(hash.Sum(nil)))
|
||||
|
||||
span.End()
|
||||
return next.HandleFinalize(ctx, in)
|
||||
}
|
||||
|
||||
// SwapComputePayloadSHA256ForUnsignedPayloadMiddleware replaces the
|
||||
// ComputePayloadSHA256 middleware with the UnsignedPayload middleware.
|
||||
//
|
||||
// Use this to disable computing the Payload SHA256 checksum and instead use
|
||||
// UNSIGNED-PAYLOAD for the SHA256 value.
|
||||
func SwapComputePayloadSHA256ForUnsignedPayloadMiddleware(stack *middleware.Stack) error {
|
||||
_, err := stack.Finalize.Swap(computePayloadHashMiddlewareID, &UnsignedPayload{})
|
||||
return err
|
||||
}
|
||||
|
||||
// ContentSHA256Header sets the X-Amz-Content-Sha256 header value to
|
||||
// the Payload hash stored in the context.
|
||||
type ContentSHA256Header struct{}
|
||||
|
||||
// AddContentSHA256HeaderMiddleware adds ContentSHA256Header to the
|
||||
// operation middleware stack
|
||||
func AddContentSHA256HeaderMiddleware(stack *middleware.Stack) error {
|
||||
return stack.Finalize.Insert(&ContentSHA256Header{}, computePayloadHashMiddlewareID, middleware.After)
|
||||
}
|
||||
|
||||
// RemoveContentSHA256HeaderMiddleware removes contentSHA256Header middleware
|
||||
// from the operation middleware stack
|
||||
func RemoveContentSHA256HeaderMiddleware(stack *middleware.Stack) error {
|
||||
_, err := stack.Finalize.Remove((*ContentSHA256Header)(nil).ID())
|
||||
return err
|
||||
}
|
||||
|
||||
// ID returns the ContentSHA256HeaderMiddleware identifier
|
||||
func (m *ContentSHA256Header) ID() string {
|
||||
return "SigV4ContentSHA256Header"
|
||||
}
|
||||
|
||||
// HandleFinalize sets the X-Amz-Content-Sha256 header value to the Payload hash
|
||||
// stored in the context.
|
||||
func (m *ContentSHA256Header) HandleFinalize(
|
||||
ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
|
||||
) (
|
||||
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
req, ok := in.Request.(*smithyhttp.Request)
|
||||
if !ok {
|
||||
return out, metadata, &HashComputationError{Err: fmt.Errorf("unexpected request middleware type %T", in.Request)}
|
||||
}
|
||||
|
||||
req.Header.Set(v4Internal.ContentSHAKey, GetPayloadHash(ctx))
|
||||
return next.HandleFinalize(ctx, in)
|
||||
}
|
||||
|
||||
// SignHTTPRequestMiddlewareOptions is the configuration options for
|
||||
// [SignHTTPRequestMiddleware].
|
||||
//
|
||||
// Deprecated: [SignHTTPRequestMiddleware] is deprecated.
|
||||
type SignHTTPRequestMiddlewareOptions struct {
|
||||
CredentialsProvider aws.CredentialsProvider
|
||||
Signer HTTPSigner
|
||||
LogSigning bool
|
||||
}
|
||||
|
||||
// SignHTTPRequestMiddleware is a `FinalizeMiddleware` implementation for SigV4
|
||||
// HTTP Signing.
|
||||
//
|
||||
// Deprecated: AWS service clients no longer use this middleware. Signing as an
|
||||
// SDK operation is now performed through an internal per-service middleware
|
||||
// which opaquely selects and uses the signer from the resolved auth scheme.
|
||||
type SignHTTPRequestMiddleware struct {
|
||||
credentialsProvider aws.CredentialsProvider
|
||||
signer HTTPSigner
|
||||
logSigning bool
|
||||
}
|
||||
|
||||
// NewSignHTTPRequestMiddleware constructs a [SignHTTPRequestMiddleware] using
|
||||
// the given [Signer] for signing requests.
|
||||
//
|
||||
// Deprecated: SignHTTPRequestMiddleware is deprecated.
|
||||
func NewSignHTTPRequestMiddleware(options SignHTTPRequestMiddlewareOptions) *SignHTTPRequestMiddleware {
|
||||
return &SignHTTPRequestMiddleware{
|
||||
credentialsProvider: options.CredentialsProvider,
|
||||
signer: options.Signer,
|
||||
logSigning: options.LogSigning,
|
||||
}
|
||||
}
|
||||
|
||||
// ID is the SignHTTPRequestMiddleware identifier.
|
||||
//
|
||||
// Deprecated: SignHTTPRequestMiddleware is deprecated.
|
||||
func (s *SignHTTPRequestMiddleware) ID() string {
|
||||
return "Signing"
|
||||
}
|
||||
|
||||
// HandleFinalize will take the provided input and sign the request using the
|
||||
// SigV4 authentication scheme.
|
||||
//
|
||||
// Deprecated: SignHTTPRequestMiddleware is deprecated.
|
||||
func (s *SignHTTPRequestMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (
|
||||
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
if !haveCredentialProvider(s.credentialsProvider) {
|
||||
return next.HandleFinalize(ctx, in)
|
||||
}
|
||||
|
||||
req, ok := in.Request.(*smithyhttp.Request)
|
||||
if !ok {
|
||||
return out, metadata, &SigningError{Err: fmt.Errorf("unexpected request middleware type %T", in.Request)}
|
||||
}
|
||||
|
||||
signingName, signingRegion := awsmiddleware.GetSigningName(ctx), awsmiddleware.GetSigningRegion(ctx)
|
||||
payloadHash := GetPayloadHash(ctx)
|
||||
if len(payloadHash) == 0 {
|
||||
return out, metadata, &SigningError{Err: fmt.Errorf("computed payload hash missing from context")}
|
||||
}
|
||||
|
||||
credentials, err := s.credentialsProvider.Retrieve(ctx)
|
||||
if err != nil {
|
||||
return out, metadata, &SigningError{Err: fmt.Errorf("failed to retrieve credentials: %w", err)}
|
||||
}
|
||||
|
||||
signerOptions := []func(o *SignerOptions){
|
||||
func(o *SignerOptions) {
|
||||
o.Logger = middleware.GetLogger(ctx)
|
||||
o.LogSigning = s.logSigning
|
||||
},
|
||||
}
|
||||
|
||||
// existing DisableURIPathEscaping is equivalent in purpose
|
||||
// to authentication scheme property DisableDoubleEncoding
|
||||
disableDoubleEncoding, overridden := internalauth.GetDisableDoubleEncoding(ctx)
|
||||
if overridden {
|
||||
signerOptions = append(signerOptions, func(o *SignerOptions) {
|
||||
o.DisableURIPathEscaping = disableDoubleEncoding
|
||||
})
|
||||
}
|
||||
|
||||
err = s.signer.SignHTTP(ctx, credentials, req.Request, payloadHash, signingName, signingRegion, sdk.NowTime(), signerOptions...)
|
||||
if err != nil {
|
||||
return out, metadata, &SigningError{Err: fmt.Errorf("failed to sign http request, %w", err)}
|
||||
}
|
||||
|
||||
ctx = awsmiddleware.SetSigningCredentials(ctx, credentials)
|
||||
|
||||
return next.HandleFinalize(ctx, in)
|
||||
}
|
||||
|
||||
// StreamingEventsPayload signs input event stream messages.
|
||||
type StreamingEventsPayload struct{}
|
||||
|
||||
// AddStreamingEventsPayload adds the streamingEventsPayload middleware to the stack.
|
||||
func AddStreamingEventsPayload(stack *middleware.Stack) error {
|
||||
return stack.Finalize.Add(&StreamingEventsPayload{}, middleware.Before)
|
||||
}
|
||||
|
||||
// ID identifies the middleware.
|
||||
func (s *StreamingEventsPayload) ID() string {
|
||||
return computePayloadHashMiddlewareID
|
||||
}
|
||||
|
||||
// HandleFinalize marks the input stream to be signed with SigV4.
|
||||
func (s *StreamingEventsPayload) HandleFinalize(
|
||||
ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
|
||||
) (
|
||||
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
contentSHA := GetPayloadHash(ctx)
|
||||
if len(contentSHA) == 0 {
|
||||
contentSHA = v4Internal.StreamingEventsPayload
|
||||
}
|
||||
|
||||
ctx = SetPayloadHash(ctx, contentSHA)
|
||||
|
||||
return next.HandleFinalize(ctx, in)
|
||||
}
|
||||
|
||||
// GetSignedRequestSignature attempts to extract the signature of the request.
|
||||
// Returning an error if the request is unsigned, or unable to extract the
|
||||
// signature.
|
||||
func GetSignedRequestSignature(r *http.Request) ([]byte, error) {
|
||||
const authHeaderSignatureElem = "Signature="
|
||||
|
||||
if auth := r.Header.Get(authorizationHeader); len(auth) != 0 {
|
||||
ps := strings.Split(auth, ",")
|
||||
for _, p := range ps {
|
||||
p = strings.TrimSpace(p)
|
||||
if idx := strings.Index(p, authHeaderSignatureElem); idx >= 0 {
|
||||
sig := p[len(authHeaderSignatureElem):]
|
||||
if len(sig) == 0 {
|
||||
return nil, fmt.Errorf("invalid request signature authorization header")
|
||||
}
|
||||
return hex.DecodeString(sig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if sig := r.URL.Query().Get("X-Amz-Signature"); len(sig) != 0 {
|
||||
return hex.DecodeString(sig)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("request not signed")
|
||||
}
|
||||
|
||||
func haveCredentialProvider(p aws.CredentialsProvider) bool {
|
||||
if p == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return !aws.IsCredentialsProvider(p, (*aws.AnonymousCredentials)(nil))
|
||||
}
|
||||
|
||||
type payloadHashKey struct{}
|
||||
|
||||
// GetPayloadHash retrieves the payload hash to use for signing
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
func GetPayloadHash(ctx context.Context) (v string) {
|
||||
v, _ = middleware.GetStackValue(ctx, payloadHashKey{}).(string)
|
||||
return v
|
||||
}
|
||||
|
||||
// SetPayloadHash sets the payload hash to be used for signing the request
|
||||
//
|
||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||
// to clear all stack values.
|
||||
func SetPayloadHash(ctx context.Context, hash string) context.Context {
|
||||
return middleware.WithStackValue(ctx, payloadHashKey{}, hash)
|
||||
}
|
||||
127
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/presign_middleware.go
generated
vendored
Normal file
127
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/presign_middleware.go
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
package v4
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
|
||||
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
smithyHTTP "github.com/aws/smithy-go/transport/http"
|
||||
)
|
||||
|
||||
// HTTPPresigner is an interface to a SigV4 signer that can sign create a
|
||||
// presigned URL for a HTTP requests.
|
||||
type HTTPPresigner interface {
|
||||
PresignHTTP(
|
||||
ctx context.Context, credentials aws.Credentials, r *http.Request,
|
||||
payloadHash string, service string, region string, signingTime time.Time,
|
||||
optFns ...func(*SignerOptions),
|
||||
) (url string, signedHeader http.Header, err error)
|
||||
}
|
||||
|
||||
// PresignedHTTPRequest provides the URL and signed headers that are included
|
||||
// in the presigned URL.
|
||||
type PresignedHTTPRequest struct {
|
||||
URL string
|
||||
Method string
|
||||
SignedHeader http.Header
|
||||
}
|
||||
|
||||
// PresignHTTPRequestMiddlewareOptions is the options for the PresignHTTPRequestMiddleware middleware.
|
||||
type PresignHTTPRequestMiddlewareOptions struct {
|
||||
CredentialsProvider aws.CredentialsProvider
|
||||
Presigner HTTPPresigner
|
||||
LogSigning bool
|
||||
}
|
||||
|
||||
// PresignHTTPRequestMiddleware provides the Finalize middleware for creating a
|
||||
// presigned URL for an HTTP request.
|
||||
//
|
||||
// Will short circuit the middleware stack and not forward onto the next
|
||||
// Finalize handler.
|
||||
type PresignHTTPRequestMiddleware struct {
|
||||
credentialsProvider aws.CredentialsProvider
|
||||
presigner HTTPPresigner
|
||||
logSigning bool
|
||||
}
|
||||
|
||||
// NewPresignHTTPRequestMiddleware returns a new PresignHTTPRequestMiddleware
|
||||
// initialized with the presigner.
|
||||
func NewPresignHTTPRequestMiddleware(options PresignHTTPRequestMiddlewareOptions) *PresignHTTPRequestMiddleware {
|
||||
return &PresignHTTPRequestMiddleware{
|
||||
credentialsProvider: options.CredentialsProvider,
|
||||
presigner: options.Presigner,
|
||||
logSigning: options.LogSigning,
|
||||
}
|
||||
}
|
||||
|
||||
// ID provides the middleware ID.
|
||||
func (*PresignHTTPRequestMiddleware) ID() string { return "PresignHTTPRequest" }
|
||||
|
||||
// HandleFinalize will take the provided input and create a presigned url for
|
||||
// the http request using the SigV4 presign authentication scheme.
|
||||
//
|
||||
// Since the signed request is not a valid HTTP request
|
||||
func (s *PresignHTTPRequestMiddleware) HandleFinalize(
|
||||
ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
|
||||
) (
|
||||
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
req, ok := in.Request.(*smithyHTTP.Request)
|
||||
if !ok {
|
||||
return out, metadata, &SigningError{
|
||||
Err: fmt.Errorf("unexpected request middleware type %T", in.Request),
|
||||
}
|
||||
}
|
||||
|
||||
httpReq := req.Build(ctx)
|
||||
if !haveCredentialProvider(s.credentialsProvider) {
|
||||
out.Result = &PresignedHTTPRequest{
|
||||
URL: httpReq.URL.String(),
|
||||
Method: httpReq.Method,
|
||||
SignedHeader: http.Header{},
|
||||
}
|
||||
|
||||
return out, metadata, nil
|
||||
}
|
||||
|
||||
signingName := awsmiddleware.GetSigningName(ctx)
|
||||
signingRegion := awsmiddleware.GetSigningRegion(ctx)
|
||||
payloadHash := GetPayloadHash(ctx)
|
||||
if len(payloadHash) == 0 {
|
||||
return out, metadata, &SigningError{
|
||||
Err: fmt.Errorf("computed payload hash missing from context"),
|
||||
}
|
||||
}
|
||||
|
||||
credentials, err := s.credentialsProvider.Retrieve(ctx)
|
||||
if err != nil {
|
||||
return out, metadata, &SigningError{
|
||||
Err: fmt.Errorf("failed to retrieve credentials: %w", err),
|
||||
}
|
||||
}
|
||||
|
||||
u, h, err := s.presigner.PresignHTTP(ctx, credentials,
|
||||
httpReq, payloadHash, signingName, signingRegion, sdk.NowTime(),
|
||||
func(o *SignerOptions) {
|
||||
o.Logger = middleware.GetLogger(ctx)
|
||||
o.LogSigning = s.logSigning
|
||||
})
|
||||
if err != nil {
|
||||
return out, metadata, &SigningError{
|
||||
Err: fmt.Errorf("failed to sign http request, %w", err),
|
||||
}
|
||||
}
|
||||
|
||||
out.Result = &PresignedHTTPRequest{
|
||||
URL: u,
|
||||
Method: httpReq.Method,
|
||||
SignedHeader: h,
|
||||
}
|
||||
|
||||
return out, metadata, nil
|
||||
}
|
||||
86
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/stream.go
generated
vendored
Normal file
86
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/stream.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
package v4
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
v4Internal "github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// EventStreamSigner is an AWS EventStream protocol signer.
|
||||
type EventStreamSigner interface {
|
||||
GetSignature(ctx context.Context, headers, payload []byte, signingTime time.Time, optFns ...func(*StreamSignerOptions)) ([]byte, error)
|
||||
}
|
||||
|
||||
// StreamSignerOptions is the configuration options for StreamSigner.
|
||||
type StreamSignerOptions struct{}
|
||||
|
||||
// StreamSigner implements Signature Version 4 (SigV4) signing of event stream encoded payloads.
|
||||
type StreamSigner struct {
|
||||
options StreamSignerOptions
|
||||
|
||||
credentials aws.Credentials
|
||||
service string
|
||||
region string
|
||||
|
||||
prevSignature []byte
|
||||
|
||||
signingKeyDeriver *v4Internal.SigningKeyDeriver
|
||||
}
|
||||
|
||||
// NewStreamSigner returns a new AWS EventStream protocol signer.
|
||||
func NewStreamSigner(credentials aws.Credentials, service, region string, seedSignature []byte, optFns ...func(*StreamSignerOptions)) *StreamSigner {
|
||||
o := StreamSignerOptions{}
|
||||
|
||||
for _, fn := range optFns {
|
||||
fn(&o)
|
||||
}
|
||||
|
||||
return &StreamSigner{
|
||||
options: o,
|
||||
credentials: credentials,
|
||||
service: service,
|
||||
region: region,
|
||||
signingKeyDeriver: v4Internal.NewSigningKeyDeriver(),
|
||||
prevSignature: seedSignature,
|
||||
}
|
||||
}
|
||||
|
||||
// GetSignature signs the provided header and payload bytes.
|
||||
func (s *StreamSigner) GetSignature(ctx context.Context, headers, payload []byte, signingTime time.Time, optFns ...func(*StreamSignerOptions)) ([]byte, error) {
|
||||
options := s.options
|
||||
|
||||
for _, fn := range optFns {
|
||||
fn(&options)
|
||||
}
|
||||
|
||||
prevSignature := s.prevSignature
|
||||
|
||||
st := v4Internal.NewSigningTime(signingTime.UTC())
|
||||
|
||||
sigKey := s.signingKeyDeriver.DeriveKey(s.credentials, s.service, s.region, st)
|
||||
|
||||
scope := v4Internal.BuildCredentialScope(st, s.region, s.service)
|
||||
|
||||
stringToSign := s.buildEventStreamStringToSign(headers, payload, prevSignature, scope, &st)
|
||||
|
||||
signature := v4Internal.HMACSHA256(sigKey, []byte(stringToSign))
|
||||
s.prevSignature = signature
|
||||
|
||||
return signature, nil
|
||||
}
|
||||
|
||||
func (s *StreamSigner) buildEventStreamStringToSign(headers, payload, previousSignature []byte, credentialScope string, signingTime *v4Internal.SigningTime) string {
|
||||
hash := sha256.New()
|
||||
return strings.Join([]string{
|
||||
"AWS4-HMAC-SHA256-PAYLOAD",
|
||||
signingTime.TimeFormat(),
|
||||
credentialScope,
|
||||
hex.EncodeToString(previousSignature),
|
||||
hex.EncodeToString(makeHash(hash, headers)),
|
||||
hex.EncodeToString(makeHash(hash, payload)),
|
||||
}, "\n")
|
||||
}
|
||||
564
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/v4.go
generated
vendored
Normal file
564
go/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/v4.go
generated
vendored
Normal file
@@ -0,0 +1,564 @@
|
||||
// Package v4 implements the AWS signature version 4 algorithm (commonly known
|
||||
// as SigV4).
|
||||
//
|
||||
// For more information about SigV4, see [Signing AWS API requests] in the IAM
|
||||
// user guide.
|
||||
//
|
||||
// While this implementation CAN work in an external context, it is developed
|
||||
// primarily for SDK use and you may encounter fringe behaviors around header
|
||||
// canonicalization.
|
||||
//
|
||||
// # Pre-escaping a request URI
|
||||
//
|
||||
// AWS v4 signature validation requires that the canonical string's URI path
|
||||
// component must be the escaped form of the HTTP request's path.
|
||||
//
|
||||
// The Go HTTP client will perform escaping automatically on the HTTP request.
|
||||
// This may cause signature validation errors because the request differs from
|
||||
// the URI path or query from which the signature was generated.
|
||||
//
|
||||
// Because of this, we recommend that you explicitly escape the request when
|
||||
// using this signer outside of the SDK to prevent possible signature mismatch.
|
||||
// This can be done by setting URL.Opaque on the request. The signer will
|
||||
// prefer that value, falling back to the return of URL.EscapedPath if unset.
|
||||
//
|
||||
// When setting URL.Opaque you must do so in the form of:
|
||||
//
|
||||
// "//<hostname>/<path>"
|
||||
//
|
||||
// // e.g.
|
||||
// "//example.com/some/path"
|
||||
//
|
||||
// The leading "//" and hostname are required or the escaping will not work
|
||||
// correctly.
|
||||
//
|
||||
// The TestStandaloneSign unit test provides a complete example of using the
|
||||
// signer outside of the SDK and pre-escaping the URI path.
|
||||
//
|
||||
// [Signing AWS API requests]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-signing.html
|
||||
package v4
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"hash"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
v4Internal "github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4"
|
||||
"github.com/aws/smithy-go/encoding/httpbinding"
|
||||
"github.com/aws/smithy-go/logging"
|
||||
)
|
||||
|
||||
const (
|
||||
signingAlgorithm = "AWS4-HMAC-SHA256"
|
||||
authorizationHeader = "Authorization"
|
||||
|
||||
// Version of signing v4
|
||||
Version = "SigV4"
|
||||
)
|
||||
|
||||
// HTTPSigner is an interface to a SigV4 signer that can sign HTTP requests
|
||||
type HTTPSigner interface {
|
||||
SignHTTP(ctx context.Context, credentials aws.Credentials, r *http.Request, payloadHash string, service string, region string, signingTime time.Time, optFns ...func(*SignerOptions)) error
|
||||
}
|
||||
|
||||
type keyDerivator interface {
|
||||
DeriveKey(credential aws.Credentials, service, region string, signingTime v4Internal.SigningTime) []byte
|
||||
}
|
||||
|
||||
// SignerOptions is the SigV4 Signer options.
|
||||
type SignerOptions struct {
|
||||
// Disables the Signer's moving HTTP header key/value pairs from the HTTP
|
||||
// request header to the request's query string. This is most commonly used
|
||||
// with pre-signed requests preventing headers from being added to the
|
||||
// request's query string.
|
||||
DisableHeaderHoisting bool
|
||||
|
||||
// Disables the automatic escaping of the URI path of the request for the
|
||||
// siganture's canonical string's path. For services that do not need additional
|
||||
// escaping then use this to disable the signer escaping the path.
|
||||
//
|
||||
// S3 is an example of a service that does not need additional escaping.
|
||||
//
|
||||
// http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
||||
DisableURIPathEscaping bool
|
||||
|
||||
// The logger to send log messages to.
|
||||
Logger logging.Logger
|
||||
|
||||
// Enable logging of signed requests.
|
||||
// This will enable logging of the canonical request, the string to sign, and for presigning the subsequent
|
||||
// presigned URL.
|
||||
LogSigning bool
|
||||
|
||||
// Disables setting the session token on the request as part of signing
|
||||
// through X-Amz-Security-Token. This is needed for variations of v4 that
|
||||
// present the token elsewhere.
|
||||
DisableSessionToken bool
|
||||
}
|
||||
|
||||
// Signer applies AWS v4 signing to given request. Use this to sign requests
|
||||
// that need to be signed with AWS V4 Signatures.
|
||||
type Signer struct {
|
||||
options SignerOptions
|
||||
keyDerivator keyDerivator
|
||||
}
|
||||
|
||||
// NewSigner returns a new SigV4 Signer
|
||||
func NewSigner(optFns ...func(signer *SignerOptions)) *Signer {
|
||||
options := SignerOptions{}
|
||||
|
||||
for _, fn := range optFns {
|
||||
fn(&options)
|
||||
}
|
||||
|
||||
return &Signer{options: options, keyDerivator: v4Internal.NewSigningKeyDeriver()}
|
||||
}
|
||||
|
||||
type httpSigner struct {
|
||||
Request *http.Request
|
||||
ServiceName string
|
||||
Region string
|
||||
Time v4Internal.SigningTime
|
||||
Credentials aws.Credentials
|
||||
KeyDerivator keyDerivator
|
||||
IsPreSign bool
|
||||
|
||||
PayloadHash string
|
||||
|
||||
DisableHeaderHoisting bool
|
||||
DisableURIPathEscaping bool
|
||||
DisableSessionToken bool
|
||||
}
|
||||
|
||||
func (s *httpSigner) Build() (signedRequest, error) {
|
||||
req := s.Request
|
||||
|
||||
query := req.URL.Query()
|
||||
headers := req.Header
|
||||
|
||||
s.setRequiredSigningFields(headers, query)
|
||||
|
||||
// Sort Each Query Key's Values
|
||||
for key := range query {
|
||||
sort.Strings(query[key])
|
||||
}
|
||||
|
||||
v4Internal.SanitizeHostForHeader(req)
|
||||
|
||||
credentialScope := s.buildCredentialScope()
|
||||
credentialStr := s.Credentials.AccessKeyID + "/" + credentialScope
|
||||
if s.IsPreSign {
|
||||
query.Set(v4Internal.AmzCredentialKey, credentialStr)
|
||||
}
|
||||
|
||||
unsignedHeaders := headers
|
||||
if s.IsPreSign && !s.DisableHeaderHoisting {
|
||||
var urlValues url.Values
|
||||
urlValues, unsignedHeaders = buildQuery(v4Internal.AllowedQueryHoisting, headers)
|
||||
for k := range urlValues {
|
||||
query[k] = urlValues[k]
|
||||
}
|
||||
}
|
||||
|
||||
host := req.URL.Host
|
||||
if len(req.Host) > 0 {
|
||||
host = req.Host
|
||||
}
|
||||
|
||||
signedHeaders, signedHeadersStr, canonicalHeaderStr := s.buildCanonicalHeaders(host, v4Internal.IgnoredHeaders, unsignedHeaders, s.Request.ContentLength)
|
||||
|
||||
if s.IsPreSign {
|
||||
query.Set(v4Internal.AmzSignedHeadersKey, signedHeadersStr)
|
||||
}
|
||||
|
||||
var rawQuery strings.Builder
|
||||
rawQuery.WriteString(strings.Replace(query.Encode(), "+", "%20", -1))
|
||||
|
||||
canonicalURI := v4Internal.GetURIPath(req.URL)
|
||||
if !s.DisableURIPathEscaping {
|
||||
canonicalURI = httpbinding.EscapePath(canonicalURI, false)
|
||||
}
|
||||
|
||||
canonicalString := s.buildCanonicalString(
|
||||
req.Method,
|
||||
canonicalURI,
|
||||
rawQuery.String(),
|
||||
signedHeadersStr,
|
||||
canonicalHeaderStr,
|
||||
)
|
||||
|
||||
strToSign := s.buildStringToSign(credentialScope, canonicalString)
|
||||
signingSignature, err := s.buildSignature(strToSign)
|
||||
if err != nil {
|
||||
return signedRequest{}, err
|
||||
}
|
||||
|
||||
if s.IsPreSign {
|
||||
rawQuery.WriteString("&X-Amz-Signature=")
|
||||
rawQuery.WriteString(signingSignature)
|
||||
} else {
|
||||
headers[authorizationHeader] = append(headers[authorizationHeader][:0], buildAuthorizationHeader(credentialStr, signedHeadersStr, signingSignature))
|
||||
}
|
||||
|
||||
req.URL.RawQuery = rawQuery.String()
|
||||
|
||||
return signedRequest{
|
||||
Request: req,
|
||||
SignedHeaders: signedHeaders,
|
||||
CanonicalString: canonicalString,
|
||||
StringToSign: strToSign,
|
||||
PreSigned: s.IsPreSign,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func buildAuthorizationHeader(credentialStr, signedHeadersStr, signingSignature string) string {
|
||||
const credential = "Credential="
|
||||
const signedHeaders = "SignedHeaders="
|
||||
const signature = "Signature="
|
||||
const commaSpace = ", "
|
||||
|
||||
var parts strings.Builder
|
||||
parts.Grow(len(signingAlgorithm) + 1 +
|
||||
len(credential) + len(credentialStr) + 2 +
|
||||
len(signedHeaders) + len(signedHeadersStr) + 2 +
|
||||
len(signature) + len(signingSignature),
|
||||
)
|
||||
parts.WriteString(signingAlgorithm)
|
||||
parts.WriteRune(' ')
|
||||
parts.WriteString(credential)
|
||||
parts.WriteString(credentialStr)
|
||||
parts.WriteString(commaSpace)
|
||||
parts.WriteString(signedHeaders)
|
||||
parts.WriteString(signedHeadersStr)
|
||||
parts.WriteString(commaSpace)
|
||||
parts.WriteString(signature)
|
||||
parts.WriteString(signingSignature)
|
||||
return parts.String()
|
||||
}
|
||||
|
||||
// SignHTTP signs AWS v4 requests with the provided payload hash, service name, region the
|
||||
// request is made to, and time the request is signed at. The signTime allows
|
||||
// you to specify that a request is signed for the future, and cannot be
|
||||
// used until then.
|
||||
//
|
||||
// The payloadHash is the hex encoded SHA-256 hash of the request payload, and
|
||||
// must be provided. Even if the request has no payload (aka body). If the
|
||||
// request has no payload you should use the hex encoded SHA-256 of an empty
|
||||
// string as the payloadHash value.
|
||||
//
|
||||
// "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
//
|
||||
// Some services such as Amazon S3 accept alternative values for the payload
|
||||
// hash, such as "UNSIGNED-PAYLOAD" for requests where the body will not be
|
||||
// included in the request signature.
|
||||
//
|
||||
// https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html
|
||||
//
|
||||
// Sign differs from Presign in that it will sign the request using HTTP
|
||||
// header values. This type of signing is intended for http.Request values that
|
||||
// will not be shared, or are shared in a way the header values on the request
|
||||
// will not be lost.
|
||||
//
|
||||
// The passed in request will be modified in place.
|
||||
func (s Signer) SignHTTP(ctx context.Context, credentials aws.Credentials, r *http.Request, payloadHash string, service string, region string, signingTime time.Time, optFns ...func(options *SignerOptions)) error {
|
||||
options := s.options
|
||||
|
||||
for _, fn := range optFns {
|
||||
fn(&options)
|
||||
}
|
||||
|
||||
signer := &httpSigner{
|
||||
Request: r,
|
||||
PayloadHash: payloadHash,
|
||||
ServiceName: service,
|
||||
Region: region,
|
||||
Credentials: credentials,
|
||||
Time: v4Internal.NewSigningTime(signingTime.UTC()),
|
||||
DisableHeaderHoisting: options.DisableHeaderHoisting,
|
||||
DisableURIPathEscaping: options.DisableURIPathEscaping,
|
||||
DisableSessionToken: options.DisableSessionToken,
|
||||
KeyDerivator: s.keyDerivator,
|
||||
}
|
||||
|
||||
signedRequest, err := signer.Build()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logSigningInfo(ctx, options, &signedRequest, false)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PresignHTTP signs AWS v4 requests with the payload hash, service name, region
|
||||
// the request is made to, and time the request is signed at. The signTime
|
||||
// allows you to specify that a request is signed for the future, and cannot
|
||||
// be used until then.
|
||||
//
|
||||
// Returns the signed URL and the map of HTTP headers that were included in the
|
||||
// signature or an error if signing the request failed. For presigned requests
|
||||
// these headers and their values must be included on the HTTP request when it
|
||||
// is made. This is helpful to know what header values need to be shared with
|
||||
// the party the presigned request will be distributed to.
|
||||
//
|
||||
// The payloadHash is the hex encoded SHA-256 hash of the request payload, and
|
||||
// must be provided. Even if the request has no payload (aka body). If the
|
||||
// request has no payload you should use the hex encoded SHA-256 of an empty
|
||||
// string as the payloadHash value.
|
||||
//
|
||||
// "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
//
|
||||
// Some services such as Amazon S3 accept alternative values for the payload
|
||||
// hash, such as "UNSIGNED-PAYLOAD" for requests where the body will not be
|
||||
// included in the request signature.
|
||||
//
|
||||
// https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html
|
||||
//
|
||||
// PresignHTTP differs from SignHTTP in that it will sign the request using
|
||||
// query string instead of header values. This allows you to share the
|
||||
// Presigned Request's URL with third parties, or distribute it throughout your
|
||||
// system with minimal dependencies.
|
||||
//
|
||||
// PresignHTTP will not set the expires time of the presigned request
|
||||
// automatically. To specify the expire duration for a request add the
|
||||
// "X-Amz-Expires" query parameter on the request with the value as the
|
||||
// duration in seconds the presigned URL should be considered valid for. This
|
||||
// parameter is not used by all AWS services, and is most notable used by
|
||||
// Amazon S3 APIs.
|
||||
//
|
||||
// expires := 20 * time.Minute
|
||||
// query := req.URL.Query()
|
||||
// query.Set("X-Amz-Expires", strconv.FormatInt(int64(expires/time.Second), 10))
|
||||
// req.URL.RawQuery = query.Encode()
|
||||
//
|
||||
// This method does not modify the provided request.
|
||||
func (s *Signer) PresignHTTP(
|
||||
ctx context.Context, credentials aws.Credentials, r *http.Request,
|
||||
payloadHash string, service string, region string, signingTime time.Time,
|
||||
optFns ...func(*SignerOptions),
|
||||
) (signedURI string, signedHeaders http.Header, err error) {
|
||||
options := s.options
|
||||
|
||||
for _, fn := range optFns {
|
||||
fn(&options)
|
||||
}
|
||||
|
||||
signer := &httpSigner{
|
||||
Request: r.Clone(r.Context()),
|
||||
PayloadHash: payloadHash,
|
||||
ServiceName: service,
|
||||
Region: region,
|
||||
Credentials: credentials,
|
||||
Time: v4Internal.NewSigningTime(signingTime.UTC()),
|
||||
IsPreSign: true,
|
||||
DisableHeaderHoisting: options.DisableHeaderHoisting,
|
||||
DisableURIPathEscaping: options.DisableURIPathEscaping,
|
||||
DisableSessionToken: options.DisableSessionToken,
|
||||
KeyDerivator: s.keyDerivator,
|
||||
}
|
||||
|
||||
signedRequest, err := signer.Build()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
logSigningInfo(ctx, options, &signedRequest, true)
|
||||
|
||||
signedHeaders = make(http.Header)
|
||||
|
||||
// For the signed headers we canonicalize the header keys in the returned map.
|
||||
// This avoids situations where can standard library double headers like host header. For example the standard
|
||||
// library will set the Host header, even if it is present in lower-case form.
|
||||
for k, v := range signedRequest.SignedHeaders {
|
||||
key := textproto.CanonicalMIMEHeaderKey(k)
|
||||
signedHeaders[key] = append(signedHeaders[key], v...)
|
||||
}
|
||||
|
||||
return signedRequest.Request.URL.String(), signedHeaders, nil
|
||||
}
|
||||
|
||||
func (s *httpSigner) buildCredentialScope() string {
|
||||
return v4Internal.BuildCredentialScope(s.Time, s.Region, s.ServiceName)
|
||||
}
|
||||
|
||||
func buildQuery(r v4Internal.Rule, header http.Header) (url.Values, http.Header) {
|
||||
query := url.Values{}
|
||||
unsignedHeaders := http.Header{}
|
||||
|
||||
// A list of headers to be converted to lower case to mitigate a limitation from S3
|
||||
lowerCaseHeaders := map[string]string{
|
||||
"X-Amz-Expected-Bucket-Owner": "x-amz-expected-bucket-owner", // see #2508
|
||||
"X-Amz-Request-Payer": "x-amz-request-payer", // see #2764
|
||||
}
|
||||
|
||||
for k, h := range header {
|
||||
if newKey, ok := lowerCaseHeaders[k]; ok {
|
||||
k = newKey
|
||||
}
|
||||
|
||||
if r.IsValid(k) {
|
||||
query[k] = h
|
||||
} else {
|
||||
unsignedHeaders[k] = h
|
||||
}
|
||||
}
|
||||
|
||||
return query, unsignedHeaders
|
||||
}
|
||||
|
||||
func (s *httpSigner) buildCanonicalHeaders(host string, rule v4Internal.Rule, header http.Header, length int64) (signed http.Header, signedHeaders, canonicalHeadersStr string) {
|
||||
signed = make(http.Header)
|
||||
|
||||
var headers []string
|
||||
const hostHeader = "host"
|
||||
headers = append(headers, hostHeader)
|
||||
signed[hostHeader] = append(signed[hostHeader], host)
|
||||
|
||||
const contentLengthHeader = "content-length"
|
||||
if length > 0 {
|
||||
headers = append(headers, contentLengthHeader)
|
||||
signed[contentLengthHeader] = append(signed[contentLengthHeader], strconv.FormatInt(length, 10))
|
||||
}
|
||||
|
||||
for k, v := range header {
|
||||
if !rule.IsValid(k) {
|
||||
continue // ignored header
|
||||
}
|
||||
if strings.EqualFold(k, contentLengthHeader) {
|
||||
// prevent signing already handled content-length header.
|
||||
continue
|
||||
}
|
||||
|
||||
lowerCaseKey := strings.ToLower(k)
|
||||
if _, ok := signed[lowerCaseKey]; ok {
|
||||
// include additional values
|
||||
signed[lowerCaseKey] = append(signed[lowerCaseKey], v...)
|
||||
continue
|
||||
}
|
||||
|
||||
headers = append(headers, lowerCaseKey)
|
||||
signed[lowerCaseKey] = v
|
||||
}
|
||||
sort.Strings(headers)
|
||||
|
||||
signedHeaders = strings.Join(headers, ";")
|
||||
|
||||
var canonicalHeaders strings.Builder
|
||||
n := len(headers)
|
||||
const colon = ':'
|
||||
for i := 0; i < n; i++ {
|
||||
if headers[i] == hostHeader {
|
||||
canonicalHeaders.WriteString(hostHeader)
|
||||
canonicalHeaders.WriteRune(colon)
|
||||
canonicalHeaders.WriteString(v4Internal.StripExcessSpaces(host))
|
||||
} else {
|
||||
canonicalHeaders.WriteString(headers[i])
|
||||
canonicalHeaders.WriteRune(colon)
|
||||
// Trim out leading, trailing, and dedup inner spaces from signed header values.
|
||||
values := signed[headers[i]]
|
||||
for j, v := range values {
|
||||
cleanedValue := strings.TrimSpace(v4Internal.StripExcessSpaces(v))
|
||||
canonicalHeaders.WriteString(cleanedValue)
|
||||
if j < len(values)-1 {
|
||||
canonicalHeaders.WriteRune(',')
|
||||
}
|
||||
}
|
||||
}
|
||||
canonicalHeaders.WriteRune('\n')
|
||||
}
|
||||
canonicalHeadersStr = canonicalHeaders.String()
|
||||
|
||||
return signed, signedHeaders, canonicalHeadersStr
|
||||
}
|
||||
|
||||
func (s *httpSigner) buildCanonicalString(method, uri, query, signedHeaders, canonicalHeaders string) string {
|
||||
return strings.Join([]string{
|
||||
method,
|
||||
uri,
|
||||
query,
|
||||
canonicalHeaders,
|
||||
signedHeaders,
|
||||
s.PayloadHash,
|
||||
}, "\n")
|
||||
}
|
||||
|
||||
func (s *httpSigner) buildStringToSign(credentialScope, canonicalRequestString string) string {
|
||||
return strings.Join([]string{
|
||||
signingAlgorithm,
|
||||
s.Time.TimeFormat(),
|
||||
credentialScope,
|
||||
hex.EncodeToString(makeHash(sha256.New(), []byte(canonicalRequestString))),
|
||||
}, "\n")
|
||||
}
|
||||
|
||||
func makeHash(hash hash.Hash, b []byte) []byte {
|
||||
hash.Reset()
|
||||
hash.Write(b)
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
|
||||
func (s *httpSigner) buildSignature(strToSign string) (string, error) {
|
||||
key := s.KeyDerivator.DeriveKey(s.Credentials, s.ServiceName, s.Region, s.Time)
|
||||
return hex.EncodeToString(v4Internal.HMACSHA256(key, []byte(strToSign))), nil
|
||||
}
|
||||
|
||||
func (s *httpSigner) setRequiredSigningFields(headers http.Header, query url.Values) {
|
||||
amzDate := s.Time.TimeFormat()
|
||||
|
||||
if s.IsPreSign {
|
||||
query.Set(v4Internal.AmzAlgorithmKey, signingAlgorithm)
|
||||
sessionToken := s.Credentials.SessionToken
|
||||
if !s.DisableSessionToken && len(sessionToken) > 0 {
|
||||
query.Set("X-Amz-Security-Token", sessionToken)
|
||||
}
|
||||
|
||||
query.Set(v4Internal.AmzDateKey, amzDate)
|
||||
return
|
||||
}
|
||||
|
||||
headers[v4Internal.AmzDateKey] = append(headers[v4Internal.AmzDateKey][:0], amzDate)
|
||||
|
||||
if !s.DisableSessionToken && len(s.Credentials.SessionToken) > 0 {
|
||||
headers[v4Internal.AmzSecurityTokenKey] = append(headers[v4Internal.AmzSecurityTokenKey][:0], s.Credentials.SessionToken)
|
||||
}
|
||||
}
|
||||
|
||||
func logSigningInfo(ctx context.Context, options SignerOptions, request *signedRequest, isPresign bool) {
|
||||
if !options.LogSigning {
|
||||
return
|
||||
}
|
||||
signedURLMsg := ""
|
||||
if isPresign {
|
||||
signedURLMsg = fmt.Sprintf(logSignedURLMsg, request.Request.URL.String())
|
||||
}
|
||||
logger := logging.WithContext(ctx, options.Logger)
|
||||
logger.Logf(logging.Debug, logSignInfoMsg, request.CanonicalString, request.StringToSign, signedURLMsg)
|
||||
}
|
||||
|
||||
type signedRequest struct {
|
||||
Request *http.Request
|
||||
SignedHeaders http.Header
|
||||
CanonicalString string
|
||||
StringToSign string
|
||||
PreSigned bool
|
||||
}
|
||||
|
||||
const logSignInfoMsg = `Request Signature:
|
||||
---[ CANONICAL STRING ]-----------------------------
|
||||
%s
|
||||
---[ STRING TO SIGN ]--------------------------------
|
||||
%s%s
|
||||
-----------------------------------------------------`
|
||||
const logSignedURLMsg = `
|
||||
---[ SIGNED URL ]------------------------------------
|
||||
%s`
|
||||
297
go/vendor/github.com/aws/aws-sdk-go-v2/aws/to_ptr.go
generated
vendored
Normal file
297
go/vendor/github.com/aws/aws-sdk-go-v2/aws/to_ptr.go
generated
vendored
Normal file
@@ -0,0 +1,297 @@
|
||||
// Code generated by aws/generate.go DO NOT EDIT.
|
||||
|
||||
package aws
|
||||
|
||||
import (
|
||||
"github.com/aws/smithy-go/ptr"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Bool returns a pointer value for the bool value passed in.
|
||||
func Bool(v bool) *bool {
|
||||
return ptr.Bool(v)
|
||||
}
|
||||
|
||||
// BoolSlice returns a slice of bool pointers from the values
|
||||
// passed in.
|
||||
func BoolSlice(vs []bool) []*bool {
|
||||
return ptr.BoolSlice(vs)
|
||||
}
|
||||
|
||||
// BoolMap returns a map of bool pointers from the values
|
||||
// passed in.
|
||||
func BoolMap(vs map[string]bool) map[string]*bool {
|
||||
return ptr.BoolMap(vs)
|
||||
}
|
||||
|
||||
// Byte returns a pointer value for the byte value passed in.
|
||||
func Byte(v byte) *byte {
|
||||
return ptr.Byte(v)
|
||||
}
|
||||
|
||||
// ByteSlice returns a slice of byte pointers from the values
|
||||
// passed in.
|
||||
func ByteSlice(vs []byte) []*byte {
|
||||
return ptr.ByteSlice(vs)
|
||||
}
|
||||
|
||||
// ByteMap returns a map of byte pointers from the values
|
||||
// passed in.
|
||||
func ByteMap(vs map[string]byte) map[string]*byte {
|
||||
return ptr.ByteMap(vs)
|
||||
}
|
||||
|
||||
// String returns a pointer value for the string value passed in.
|
||||
func String(v string) *string {
|
||||
return ptr.String(v)
|
||||
}
|
||||
|
||||
// StringSlice returns a slice of string pointers from the values
|
||||
// passed in.
|
||||
func StringSlice(vs []string) []*string {
|
||||
return ptr.StringSlice(vs)
|
||||
}
|
||||
|
||||
// StringMap returns a map of string pointers from the values
|
||||
// passed in.
|
||||
func StringMap(vs map[string]string) map[string]*string {
|
||||
return ptr.StringMap(vs)
|
||||
}
|
||||
|
||||
// Int returns a pointer value for the int value passed in.
|
||||
func Int(v int) *int {
|
||||
return ptr.Int(v)
|
||||
}
|
||||
|
||||
// IntSlice returns a slice of int pointers from the values
|
||||
// passed in.
|
||||
func IntSlice(vs []int) []*int {
|
||||
return ptr.IntSlice(vs)
|
||||
}
|
||||
|
||||
// IntMap returns a map of int pointers from the values
|
||||
// passed in.
|
||||
func IntMap(vs map[string]int) map[string]*int {
|
||||
return ptr.IntMap(vs)
|
||||
}
|
||||
|
||||
// Int8 returns a pointer value for the int8 value passed in.
|
||||
func Int8(v int8) *int8 {
|
||||
return ptr.Int8(v)
|
||||
}
|
||||
|
||||
// Int8Slice returns a slice of int8 pointers from the values
|
||||
// passed in.
|
||||
func Int8Slice(vs []int8) []*int8 {
|
||||
return ptr.Int8Slice(vs)
|
||||
}
|
||||
|
||||
// Int8Map returns a map of int8 pointers from the values
|
||||
// passed in.
|
||||
func Int8Map(vs map[string]int8) map[string]*int8 {
|
||||
return ptr.Int8Map(vs)
|
||||
}
|
||||
|
||||
// Int16 returns a pointer value for the int16 value passed in.
|
||||
func Int16(v int16) *int16 {
|
||||
return ptr.Int16(v)
|
||||
}
|
||||
|
||||
// Int16Slice returns a slice of int16 pointers from the values
|
||||
// passed in.
|
||||
func Int16Slice(vs []int16) []*int16 {
|
||||
return ptr.Int16Slice(vs)
|
||||
}
|
||||
|
||||
// Int16Map returns a map of int16 pointers from the values
|
||||
// passed in.
|
||||
func Int16Map(vs map[string]int16) map[string]*int16 {
|
||||
return ptr.Int16Map(vs)
|
||||
}
|
||||
|
||||
// Int32 returns a pointer value for the int32 value passed in.
|
||||
func Int32(v int32) *int32 {
|
||||
return ptr.Int32(v)
|
||||
}
|
||||
|
||||
// Int32Slice returns a slice of int32 pointers from the values
|
||||
// passed in.
|
||||
func Int32Slice(vs []int32) []*int32 {
|
||||
return ptr.Int32Slice(vs)
|
||||
}
|
||||
|
||||
// Int32Map returns a map of int32 pointers from the values
|
||||
// passed in.
|
||||
func Int32Map(vs map[string]int32) map[string]*int32 {
|
||||
return ptr.Int32Map(vs)
|
||||
}
|
||||
|
||||
// Int64 returns a pointer value for the int64 value passed in.
|
||||
func Int64(v int64) *int64 {
|
||||
return ptr.Int64(v)
|
||||
}
|
||||
|
||||
// Int64Slice returns a slice of int64 pointers from the values
|
||||
// passed in.
|
||||
func Int64Slice(vs []int64) []*int64 {
|
||||
return ptr.Int64Slice(vs)
|
||||
}
|
||||
|
||||
// Int64Map returns a map of int64 pointers from the values
|
||||
// passed in.
|
||||
func Int64Map(vs map[string]int64) map[string]*int64 {
|
||||
return ptr.Int64Map(vs)
|
||||
}
|
||||
|
||||
// Uint returns a pointer value for the uint value passed in.
|
||||
func Uint(v uint) *uint {
|
||||
return ptr.Uint(v)
|
||||
}
|
||||
|
||||
// UintSlice returns a slice of uint pointers from the values
|
||||
// passed in.
|
||||
func UintSlice(vs []uint) []*uint {
|
||||
return ptr.UintSlice(vs)
|
||||
}
|
||||
|
||||
// UintMap returns a map of uint pointers from the values
|
||||
// passed in.
|
||||
func UintMap(vs map[string]uint) map[string]*uint {
|
||||
return ptr.UintMap(vs)
|
||||
}
|
||||
|
||||
// Uint8 returns a pointer value for the uint8 value passed in.
|
||||
func Uint8(v uint8) *uint8 {
|
||||
return ptr.Uint8(v)
|
||||
}
|
||||
|
||||
// Uint8Slice returns a slice of uint8 pointers from the values
|
||||
// passed in.
|
||||
func Uint8Slice(vs []uint8) []*uint8 {
|
||||
return ptr.Uint8Slice(vs)
|
||||
}
|
||||
|
||||
// Uint8Map returns a map of uint8 pointers from the values
|
||||
// passed in.
|
||||
func Uint8Map(vs map[string]uint8) map[string]*uint8 {
|
||||
return ptr.Uint8Map(vs)
|
||||
}
|
||||
|
||||
// Uint16 returns a pointer value for the uint16 value passed in.
|
||||
func Uint16(v uint16) *uint16 {
|
||||
return ptr.Uint16(v)
|
||||
}
|
||||
|
||||
// Uint16Slice returns a slice of uint16 pointers from the values
|
||||
// passed in.
|
||||
func Uint16Slice(vs []uint16) []*uint16 {
|
||||
return ptr.Uint16Slice(vs)
|
||||
}
|
||||
|
||||
// Uint16Map returns a map of uint16 pointers from the values
|
||||
// passed in.
|
||||
func Uint16Map(vs map[string]uint16) map[string]*uint16 {
|
||||
return ptr.Uint16Map(vs)
|
||||
}
|
||||
|
||||
// Uint32 returns a pointer value for the uint32 value passed in.
|
||||
func Uint32(v uint32) *uint32 {
|
||||
return ptr.Uint32(v)
|
||||
}
|
||||
|
||||
// Uint32Slice returns a slice of uint32 pointers from the values
|
||||
// passed in.
|
||||
func Uint32Slice(vs []uint32) []*uint32 {
|
||||
return ptr.Uint32Slice(vs)
|
||||
}
|
||||
|
||||
// Uint32Map returns a map of uint32 pointers from the values
|
||||
// passed in.
|
||||
func Uint32Map(vs map[string]uint32) map[string]*uint32 {
|
||||
return ptr.Uint32Map(vs)
|
||||
}
|
||||
|
||||
// Uint64 returns a pointer value for the uint64 value passed in.
|
||||
func Uint64(v uint64) *uint64 {
|
||||
return ptr.Uint64(v)
|
||||
}
|
||||
|
||||
// Uint64Slice returns a slice of uint64 pointers from the values
|
||||
// passed in.
|
||||
func Uint64Slice(vs []uint64) []*uint64 {
|
||||
return ptr.Uint64Slice(vs)
|
||||
}
|
||||
|
||||
// Uint64Map returns a map of uint64 pointers from the values
|
||||
// passed in.
|
||||
func Uint64Map(vs map[string]uint64) map[string]*uint64 {
|
||||
return ptr.Uint64Map(vs)
|
||||
}
|
||||
|
||||
// Float32 returns a pointer value for the float32 value passed in.
|
||||
func Float32(v float32) *float32 {
|
||||
return ptr.Float32(v)
|
||||
}
|
||||
|
||||
// Float32Slice returns a slice of float32 pointers from the values
|
||||
// passed in.
|
||||
func Float32Slice(vs []float32) []*float32 {
|
||||
return ptr.Float32Slice(vs)
|
||||
}
|
||||
|
||||
// Float32Map returns a map of float32 pointers from the values
|
||||
// passed in.
|
||||
func Float32Map(vs map[string]float32) map[string]*float32 {
|
||||
return ptr.Float32Map(vs)
|
||||
}
|
||||
|
||||
// Float64 returns a pointer value for the float64 value passed in.
|
||||
func Float64(v float64) *float64 {
|
||||
return ptr.Float64(v)
|
||||
}
|
||||
|
||||
// Float64Slice returns a slice of float64 pointers from the values
|
||||
// passed in.
|
||||
func Float64Slice(vs []float64) []*float64 {
|
||||
return ptr.Float64Slice(vs)
|
||||
}
|
||||
|
||||
// Float64Map returns a map of float64 pointers from the values
|
||||
// passed in.
|
||||
func Float64Map(vs map[string]float64) map[string]*float64 {
|
||||
return ptr.Float64Map(vs)
|
||||
}
|
||||
|
||||
// Time returns a pointer value for the time.Time value passed in.
|
||||
func Time(v time.Time) *time.Time {
|
||||
return ptr.Time(v)
|
||||
}
|
||||
|
||||
// TimeSlice returns a slice of time.Time pointers from the values
|
||||
// passed in.
|
||||
func TimeSlice(vs []time.Time) []*time.Time {
|
||||
return ptr.TimeSlice(vs)
|
||||
}
|
||||
|
||||
// TimeMap returns a map of time.Time pointers from the values
|
||||
// passed in.
|
||||
func TimeMap(vs map[string]time.Time) map[string]*time.Time {
|
||||
return ptr.TimeMap(vs)
|
||||
}
|
||||
|
||||
// Duration returns a pointer value for the time.Duration value passed in.
|
||||
func Duration(v time.Duration) *time.Duration {
|
||||
return ptr.Duration(v)
|
||||
}
|
||||
|
||||
// DurationSlice returns a slice of time.Duration pointers from the values
|
||||
// passed in.
|
||||
func DurationSlice(vs []time.Duration) []*time.Duration {
|
||||
return ptr.DurationSlice(vs)
|
||||
}
|
||||
|
||||
// DurationMap returns a map of time.Duration pointers from the values
|
||||
// passed in.
|
||||
func DurationMap(vs map[string]time.Duration) map[string]*time.Duration {
|
||||
return ptr.DurationMap(vs)
|
||||
}
|
||||
342
go/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/client.go
generated
vendored
Normal file
342
go/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/client.go
generated
vendored
Normal file
@@ -0,0 +1,342 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/smithy-go/tracing"
|
||||
)
|
||||
|
||||
// Defaults for the HTTPTransportBuilder.
|
||||
var (
|
||||
// Default connection pool options
|
||||
DefaultHTTPTransportMaxIdleConns = 100
|
||||
DefaultHTTPTransportMaxIdleConnsPerHost = 10
|
||||
|
||||
// Default connection timeouts
|
||||
DefaultHTTPTransportIdleConnTimeout = 90 * time.Second
|
||||
DefaultHTTPTransportTLSHandleshakeTimeout = 10 * time.Second
|
||||
DefaultHTTPTransportExpectContinueTimeout = 1 * time.Second
|
||||
|
||||
// Default to TLS 1.2 for all HTTPS requests.
|
||||
DefaultHTTPTransportTLSMinVersion uint16 = tls.VersionTLS12
|
||||
)
|
||||
|
||||
// Timeouts for net.Dialer's network connection.
|
||||
var (
|
||||
DefaultDialConnectTimeout = 30 * time.Second
|
||||
DefaultDialKeepAliveTimeout = 30 * time.Second
|
||||
)
|
||||
|
||||
// BuildableClient provides a HTTPClient implementation with options to
|
||||
// create copies of the HTTPClient when additional configuration is provided.
|
||||
//
|
||||
// The client's methods will not share the http.Transport value between copies
|
||||
// of the BuildableClient. Only exported member values of the Transport and
|
||||
// optional Dialer will be copied between copies of BuildableClient.
|
||||
type BuildableClient struct {
|
||||
transport *http.Transport
|
||||
dialer *net.Dialer
|
||||
|
||||
initOnce sync.Once
|
||||
|
||||
clientTimeout time.Duration
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
// NewBuildableClient returns an initialized client for invoking HTTP
|
||||
// requests.
|
||||
func NewBuildableClient() *BuildableClient {
|
||||
return &BuildableClient{}
|
||||
}
|
||||
|
||||
// Do implements the HTTPClient interface's Do method to invoke a HTTP request,
|
||||
// and receive the response. Uses the BuildableClient's current
|
||||
// configuration to invoke the http.Request.
|
||||
//
|
||||
// If connection pooling is enabled (aka HTTP KeepAlive) the client will only
|
||||
// share pooled connections with its own instance. Copies of the
|
||||
// BuildableClient will have their own connection pools.
|
||||
//
|
||||
// Redirect (3xx) responses will not be followed, the HTTP response received
|
||||
// will returned instead.
|
||||
func (b *BuildableClient) Do(req *http.Request) (*http.Response, error) {
|
||||
b.initOnce.Do(b.build)
|
||||
|
||||
return b.client.Do(req)
|
||||
}
|
||||
|
||||
// Freeze returns a frozen aws.HTTPClient implementation that is no longer a BuildableClient.
|
||||
// Use this to prevent the SDK from applying DefaultMode configuration values to a buildable client.
|
||||
func (b *BuildableClient) Freeze() aws.HTTPClient {
|
||||
cpy := b.clone()
|
||||
cpy.build()
|
||||
return cpy.client
|
||||
}
|
||||
|
||||
func (b *BuildableClient) build() {
|
||||
b.client = wrapWithLimitedRedirect(&http.Client{
|
||||
Timeout: b.clientTimeout,
|
||||
Transport: b.GetTransport(),
|
||||
})
|
||||
}
|
||||
|
||||
func (b *BuildableClient) clone() *BuildableClient {
|
||||
cpy := NewBuildableClient()
|
||||
cpy.transport = b.GetTransport()
|
||||
cpy.dialer = b.GetDialer()
|
||||
cpy.clientTimeout = b.clientTimeout
|
||||
|
||||
return cpy
|
||||
}
|
||||
|
||||
// WithTransportOptions copies the BuildableClient and returns it with the
|
||||
// http.Transport options applied.
|
||||
//
|
||||
// If a non (*http.Transport) was set as the round tripper, the round tripper
|
||||
// will be replaced with a default Transport value before invoking the option
|
||||
// functions.
|
||||
func (b *BuildableClient) WithTransportOptions(opts ...func(*http.Transport)) *BuildableClient {
|
||||
cpy := b.clone()
|
||||
|
||||
tr := cpy.GetTransport()
|
||||
for _, opt := range opts {
|
||||
opt(tr)
|
||||
}
|
||||
cpy.transport = tr
|
||||
|
||||
return cpy
|
||||
}
|
||||
|
||||
// WithDialerOptions copies the BuildableClient and returns it with the
|
||||
// net.Dialer options applied. Will set the client's http.Transport DialContext
|
||||
// member.
|
||||
func (b *BuildableClient) WithDialerOptions(opts ...func(*net.Dialer)) *BuildableClient {
|
||||
cpy := b.clone()
|
||||
|
||||
dialer := cpy.GetDialer()
|
||||
for _, opt := range opts {
|
||||
opt(dialer)
|
||||
}
|
||||
cpy.dialer = dialer
|
||||
|
||||
tr := cpy.GetTransport()
|
||||
tr.DialContext = cpy.dialer.DialContext
|
||||
cpy.transport = tr
|
||||
|
||||
return cpy
|
||||
}
|
||||
|
||||
// WithTimeout Sets the timeout used by the client for all requests.
|
||||
func (b *BuildableClient) WithTimeout(timeout time.Duration) *BuildableClient {
|
||||
cpy := b.clone()
|
||||
cpy.clientTimeout = timeout
|
||||
return cpy
|
||||
}
|
||||
|
||||
// GetTransport returns a copy of the client's HTTP Transport.
|
||||
func (b *BuildableClient) GetTransport() *http.Transport {
|
||||
var tr *http.Transport
|
||||
if b.transport != nil {
|
||||
tr = b.transport.Clone()
|
||||
} else {
|
||||
tr = defaultHTTPTransport()
|
||||
}
|
||||
|
||||
return tr
|
||||
}
|
||||
|
||||
// GetDialer returns a copy of the client's network dialer.
|
||||
func (b *BuildableClient) GetDialer() *net.Dialer {
|
||||
var dialer *net.Dialer
|
||||
if b.dialer != nil {
|
||||
dialer = shallowCopyStruct(b.dialer).(*net.Dialer)
|
||||
} else {
|
||||
dialer = defaultDialer()
|
||||
}
|
||||
|
||||
return dialer
|
||||
}
|
||||
|
||||
// GetTimeout returns a copy of the client's timeout to cancel requests with.
|
||||
func (b *BuildableClient) GetTimeout() time.Duration {
|
||||
return b.clientTimeout
|
||||
}
|
||||
|
||||
func defaultDialer() *net.Dialer {
|
||||
return &net.Dialer{
|
||||
Timeout: DefaultDialConnectTimeout,
|
||||
KeepAlive: DefaultDialKeepAliveTimeout,
|
||||
DualStack: true,
|
||||
}
|
||||
}
|
||||
|
||||
func defaultHTTPTransport() *http.Transport {
|
||||
dialer := defaultDialer()
|
||||
|
||||
tr := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: traceDialContext(dialer.DialContext),
|
||||
TLSHandshakeTimeout: DefaultHTTPTransportTLSHandleshakeTimeout,
|
||||
MaxIdleConns: DefaultHTTPTransportMaxIdleConns,
|
||||
MaxIdleConnsPerHost: DefaultHTTPTransportMaxIdleConnsPerHost,
|
||||
IdleConnTimeout: DefaultHTTPTransportIdleConnTimeout,
|
||||
ExpectContinueTimeout: DefaultHTTPTransportExpectContinueTimeout,
|
||||
ForceAttemptHTTP2: true,
|
||||
TLSClientConfig: &tls.Config{
|
||||
MinVersion: DefaultHTTPTransportTLSMinVersion,
|
||||
},
|
||||
}
|
||||
|
||||
return tr
|
||||
}
|
||||
|
||||
type dialContext func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||
|
||||
func traceDialContext(dc dialContext) dialContext {
|
||||
return func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
span, _ := tracing.GetSpan(ctx)
|
||||
span.SetProperty("net.peer.name", addr)
|
||||
|
||||
conn, err := dc(ctx, network, addr)
|
||||
if err != nil {
|
||||
return conn, err
|
||||
}
|
||||
|
||||
raddr := conn.RemoteAddr()
|
||||
if raddr == nil {
|
||||
return conn, err
|
||||
}
|
||||
|
||||
host, port, err := net.SplitHostPort(raddr.String())
|
||||
if err != nil { // don't blow up just because we couldn't parse
|
||||
span.SetProperty("net.peer.addr", raddr.String())
|
||||
} else {
|
||||
span.SetProperty("net.peer.host", host)
|
||||
span.SetProperty("net.peer.port", port)
|
||||
}
|
||||
|
||||
return conn, err
|
||||
}
|
||||
}
|
||||
|
||||
// shallowCopyStruct creates a shallow copy of the passed in source struct, and
|
||||
// returns that copy of the same struct type.
|
||||
func shallowCopyStruct(src interface{}) interface{} {
|
||||
srcVal := reflect.ValueOf(src)
|
||||
srcValType := srcVal.Type()
|
||||
|
||||
var returnAsPtr bool
|
||||
if srcValType.Kind() == reflect.Ptr {
|
||||
srcVal = srcVal.Elem()
|
||||
srcValType = srcValType.Elem()
|
||||
returnAsPtr = true
|
||||
}
|
||||
dstVal := reflect.New(srcValType).Elem()
|
||||
|
||||
for i := 0; i < srcValType.NumField(); i++ {
|
||||
ft := srcValType.Field(i)
|
||||
if len(ft.PkgPath) != 0 {
|
||||
// unexported fields have a PkgPath
|
||||
continue
|
||||
}
|
||||
|
||||
dstVal.Field(i).Set(srcVal.Field(i))
|
||||
}
|
||||
|
||||
if returnAsPtr {
|
||||
dstVal = dstVal.Addr()
|
||||
}
|
||||
|
||||
return dstVal.Interface()
|
||||
}
|
||||
|
||||
// wrapWithLimitedRedirect updates the Client's Transport and CheckRedirect to
|
||||
// not follow any redirect other than 307 and 308. No other redirect will be
|
||||
// followed.
|
||||
//
|
||||
// If the client does not have a Transport defined will use a new SDK default
|
||||
// http.Transport configuration.
|
||||
func wrapWithLimitedRedirect(c *http.Client) *http.Client {
|
||||
tr := c.Transport
|
||||
if tr == nil {
|
||||
tr = defaultHTTPTransport()
|
||||
}
|
||||
|
||||
cc := *c
|
||||
cc.CheckRedirect = limitedRedirect
|
||||
cc.Transport = suppressBadHTTPRedirectTransport{
|
||||
tr: tr,
|
||||
}
|
||||
|
||||
return &cc
|
||||
}
|
||||
|
||||
// limitedRedirect is a CheckRedirect that prevents the client from following
|
||||
// any non 307/308 HTTP status code redirects.
|
||||
//
|
||||
// The 307 and 308 redirects are allowed because the client must use the
|
||||
// original HTTP method for the redirected to location. Whereas 301 and 302
|
||||
// allow the client to switch to GET for the redirect.
|
||||
//
|
||||
// Suppresses all redirect requests with a URL of badHTTPRedirectLocation.
|
||||
func limitedRedirect(r *http.Request, via []*http.Request) error {
|
||||
// Request.Response, in CheckRedirect is the response that is triggering
|
||||
// the redirect.
|
||||
resp := r.Response
|
||||
if r.URL.String() == badHTTPRedirectLocation {
|
||||
resp.Header.Del(badHTTPRedirectLocation)
|
||||
return http.ErrUseLastResponse
|
||||
}
|
||||
|
||||
switch resp.StatusCode {
|
||||
case 307, 308:
|
||||
// Only allow 307 and 308 redirects as they preserve the method.
|
||||
return nil
|
||||
}
|
||||
|
||||
return http.ErrUseLastResponse
|
||||
}
|
||||
|
||||
// suppressBadHTTPRedirectTransport provides an http.RoundTripper
|
||||
// implementation that wraps another http.RoundTripper to prevent HTTP client
|
||||
// receiving 301 and 302 HTTP responses redirects without the required location
|
||||
// header.
|
||||
//
|
||||
// Clients using this utility must have a CheckRedirect, e.g. limitedRedirect,
|
||||
// that check for responses with having a URL of baseHTTPRedirectLocation, and
|
||||
// suppress the redirect.
|
||||
type suppressBadHTTPRedirectTransport struct {
|
||||
tr http.RoundTripper
|
||||
}
|
||||
|
||||
const badHTTPRedirectLocation = `https://amazonaws.com/badhttpredirectlocation`
|
||||
|
||||
// RoundTrip backfills a stub location when a 301/302 response is received
|
||||
// without a location. This stub location is used by limitedRedirect to prevent
|
||||
// the HTTP client from failing attempting to use follow a redirect without a
|
||||
// location value.
|
||||
func (t suppressBadHTTPRedirectTransport) RoundTrip(r *http.Request) (*http.Response, error) {
|
||||
resp, err := t.tr.RoundTrip(r)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// S3 is the only known service to return 301 without location header.
|
||||
// The Go standard library HTTP client will return an opaque error if it
|
||||
// tries to follow a 301/302 response missing the location header.
|
||||
switch resp.StatusCode {
|
||||
case 301, 302:
|
||||
if v := resp.Header.Get("Location"); len(v) == 0 {
|
||||
resp.Header.Set("Location", badHTTPRedirectLocation)
|
||||
}
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
42
go/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/content_type.go
generated
vendored
Normal file
42
go/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/content_type.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
)
|
||||
|
||||
// removeContentTypeHeader is a build middleware that removes
|
||||
// content type header if content-length header is unset or
|
||||
// is set to zero,
|
||||
type removeContentTypeHeader struct {
|
||||
}
|
||||
|
||||
// ID the name of the middleware.
|
||||
func (m *removeContentTypeHeader) ID() string {
|
||||
return "RemoveContentTypeHeader"
|
||||
}
|
||||
|
||||
// HandleBuild adds or appends the constructed user agent to the request.
|
||||
func (m *removeContentTypeHeader) HandleBuild(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) (
|
||||
out middleware.BuildOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
req, ok := in.Request.(*smithyhttp.Request)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("unknown transport type %T", in)
|
||||
}
|
||||
|
||||
// remove contentTypeHeader when content-length is zero
|
||||
if req.ContentLength == 0 {
|
||||
req.Header.Del("content-type")
|
||||
}
|
||||
|
||||
return next.HandleBuild(ctx, in)
|
||||
}
|
||||
|
||||
// RemoveContentTypeHeader removes content-type header if
|
||||
// content length is unset or equal to zero.
|
||||
func RemoveContentTypeHeader(stack *middleware.Stack) error {
|
||||
return stack.Build.Add(&removeContentTypeHeader{}, middleware.After)
|
||||
}
|
||||
33
go/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/response_error.go
generated
vendored
Normal file
33
go/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/response_error.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
)
|
||||
|
||||
// ResponseError provides the HTTP centric error type wrapping the underlying error
|
||||
// with the HTTP response value and the deserialized RequestID.
|
||||
type ResponseError struct {
|
||||
*smithyhttp.ResponseError
|
||||
|
||||
// RequestID associated with response error
|
||||
RequestID string
|
||||
}
|
||||
|
||||
// ServiceRequestID returns the request id associated with Response Error
|
||||
func (e *ResponseError) ServiceRequestID() string { return e.RequestID }
|
||||
|
||||
// Error returns the formatted error
|
||||
func (e *ResponseError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"https response error StatusCode: %d, RequestID: %s, %v",
|
||||
e.Response.StatusCode, e.RequestID, e.Err)
|
||||
}
|
||||
|
||||
// As populates target and returns true if the type of target is a error type that
|
||||
// the ResponseError embeds, (e.g.AWS HTTP ResponseError)
|
||||
func (e *ResponseError) As(target interface{}) bool {
|
||||
return errors.As(e.ResponseError, target)
|
||||
}
|
||||
56
go/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/response_error_middleware.go
generated
vendored
Normal file
56
go/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/response_error_middleware.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
)
|
||||
|
||||
// AddResponseErrorMiddleware adds response error wrapper middleware
|
||||
func AddResponseErrorMiddleware(stack *middleware.Stack) error {
|
||||
// add error wrapper middleware before request id retriever middleware so that it can wrap the error response
|
||||
// returned by operation deserializers
|
||||
return stack.Deserialize.Insert(&ResponseErrorWrapper{}, "RequestIDRetriever", middleware.Before)
|
||||
}
|
||||
|
||||
// ResponseErrorWrapper wraps operation errors with ResponseError.
|
||||
type ResponseErrorWrapper struct {
|
||||
}
|
||||
|
||||
// ID returns the middleware identifier
|
||||
func (m *ResponseErrorWrapper) ID() string {
|
||||
return "ResponseErrorWrapper"
|
||||
}
|
||||
|
||||
// HandleDeserialize wraps the stack error with smithyhttp.ResponseError.
|
||||
func (m *ResponseErrorWrapper) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) (
|
||||
out middleware.DeserializeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
out, metadata, err = next.HandleDeserialize(ctx, in)
|
||||
if err == nil {
|
||||
// Nothing to do when there is no error.
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
resp, ok := out.RawResponse.(*smithyhttp.Response)
|
||||
if !ok {
|
||||
// No raw response to wrap with.
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
// look for request id in metadata
|
||||
reqID, _ := awsmiddleware.GetRequestIDMetadata(metadata)
|
||||
|
||||
// Wrap the returned smithy error with the request id retrieved from the metadata
|
||||
err = &ResponseError{
|
||||
ResponseError: &smithyhttp.ResponseError{
|
||||
Response: resp,
|
||||
Err: err,
|
||||
},
|
||||
RequestID: reqID,
|
||||
}
|
||||
|
||||
return out, metadata, err
|
||||
}
|
||||
104
go/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/timeout_read_closer.go
generated
vendored
Normal file
104
go/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/timeout_read_closer.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/aws/smithy-go"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
)
|
||||
|
||||
type readResult struct {
|
||||
n int
|
||||
err error
|
||||
}
|
||||
|
||||
// ResponseTimeoutError is an error when the reads from the response are
|
||||
// delayed longer than the timeout the read was configured for.
|
||||
type ResponseTimeoutError struct {
|
||||
TimeoutDur time.Duration
|
||||
}
|
||||
|
||||
// Timeout returns that the error is was caused by a timeout, and can be
|
||||
// retried.
|
||||
func (*ResponseTimeoutError) Timeout() bool { return true }
|
||||
|
||||
func (e *ResponseTimeoutError) Error() string {
|
||||
return fmt.Sprintf("read on body reach timeout limit, %v", e.TimeoutDur)
|
||||
}
|
||||
|
||||
// timeoutReadCloser will handle body reads that take too long.
|
||||
// We will return a ErrReadTimeout error if a timeout occurs.
|
||||
type timeoutReadCloser struct {
|
||||
reader io.ReadCloser
|
||||
duration time.Duration
|
||||
}
|
||||
|
||||
// Read will spin off a goroutine to call the reader's Read method. We will
|
||||
// select on the timer's channel or the read's channel. Whoever completes first
|
||||
// will be returned.
|
||||
func (r *timeoutReadCloser) Read(b []byte) (int, error) {
|
||||
timer := time.NewTimer(r.duration)
|
||||
c := make(chan readResult, 1)
|
||||
|
||||
go func() {
|
||||
n, err := r.reader.Read(b)
|
||||
timer.Stop()
|
||||
c <- readResult{n: n, err: err}
|
||||
}()
|
||||
|
||||
select {
|
||||
case data := <-c:
|
||||
return data.n, data.err
|
||||
case <-timer.C:
|
||||
return 0, &ResponseTimeoutError{TimeoutDur: r.duration}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *timeoutReadCloser) Close() error {
|
||||
return r.reader.Close()
|
||||
}
|
||||
|
||||
// AddResponseReadTimeoutMiddleware adds a middleware to the stack that wraps the
|
||||
// response body so that a read that takes too long will return an error.
|
||||
func AddResponseReadTimeoutMiddleware(stack *middleware.Stack, duration time.Duration) error {
|
||||
return stack.Deserialize.Add(&readTimeout{duration: duration}, middleware.After)
|
||||
}
|
||||
|
||||
// readTimeout wraps the response body with a timeoutReadCloser
|
||||
type readTimeout struct {
|
||||
duration time.Duration
|
||||
}
|
||||
|
||||
// ID returns the id of the middleware
|
||||
func (*readTimeout) ID() string {
|
||||
return "ReadResponseTimeout"
|
||||
}
|
||||
|
||||
// HandleDeserialize implements the DeserializeMiddleware interface
|
||||
func (m *readTimeout) HandleDeserialize(
|
||||
ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler,
|
||||
) (
|
||||
out middleware.DeserializeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
out, metadata, err = next.HandleDeserialize(ctx, in)
|
||||
if err != nil {
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
response, ok := out.RawResponse.(*smithyhttp.Response)
|
||||
if !ok {
|
||||
return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)}
|
||||
}
|
||||
|
||||
response.Body = &timeoutReadCloser{
|
||||
reader: response.Body,
|
||||
duration: m.duration,
|
||||
}
|
||||
out.RawResponse = response
|
||||
|
||||
return out, metadata, err
|
||||
}
|
||||
42
go/vendor/github.com/aws/aws-sdk-go-v2/aws/types.go
generated
vendored
Normal file
42
go/vendor/github.com/aws/aws-sdk-go-v2/aws/types.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Ternary is an enum allowing an unknown or none state in addition to a bool's
|
||||
// true and false.
|
||||
type Ternary int
|
||||
|
||||
func (t Ternary) String() string {
|
||||
switch t {
|
||||
case UnknownTernary:
|
||||
return "unknown"
|
||||
case FalseTernary:
|
||||
return "false"
|
||||
case TrueTernary:
|
||||
return "true"
|
||||
default:
|
||||
return fmt.Sprintf("unknown value, %d", int(t))
|
||||
}
|
||||
}
|
||||
|
||||
// Bool returns true if the value is TrueTernary, false otherwise.
|
||||
func (t Ternary) Bool() bool {
|
||||
return t == TrueTernary
|
||||
}
|
||||
|
||||
// Enumerations for the values of the Ternary type.
|
||||
const (
|
||||
UnknownTernary Ternary = iota
|
||||
FalseTernary
|
||||
TrueTernary
|
||||
)
|
||||
|
||||
// BoolTernary returns a true or false Ternary value for the bool provided.
|
||||
func BoolTernary(v bool) Ternary {
|
||||
if v {
|
||||
return TrueTernary
|
||||
}
|
||||
return FalseTernary
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user