Bump aws sdk to v1.15.11
This is the latest official release for this dependency Signed-off-by: Ryan Abrams <rdabrams@gmail.com>master
							parent
							
								
									5f37adaa41
								
							
						
					
					
						commit
						57212c909b
					
				|  | @ -1,7 +1,7 @@ | |||
| github.com/Azure/azure-sdk-for-go 4650843026a7fdec254a8d9cf893693a254edd0b | ||||
| github.com/Azure/go-autorest eaa7994b2278094c904d31993d26f56324db3052 | ||||
| github.com/sirupsen/logrus 3d4380f53a34dcdc95f0c1db702615992b38d9a4 | ||||
| github.com/aws/aws-sdk-go 5bcc0a238d880469f949fc7cd24e35f32ab80cbd | ||||
| github.com/aws/aws-sdk-go f831d5a0822a1ad72420ab18c6269bca1ddaf490 | ||||
| github.com/bshuster-repo/logrus-logstash-hook d2c0ecc1836d91814e15e23bb5dc309c3ef51f4a | ||||
| github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9 | ||||
| github.com/bugsnag/bugsnag-go b1d153021fcd90ca3f080db36bec96dc690fb274 | ||||
|  |  | |||
|  | @ -6,6 +6,8 @@ aws-sdk-go is the official AWS SDK for the Go programming language. | |||
| 
 | ||||
| Checkout our [release notes](https://github.com/aws/aws-sdk-go/releases) for information about the latest bug fixes, updates, and features added to the SDK. | ||||
| 
 | ||||
| We [announced](https://aws.amazon.com/blogs/developer/aws-sdk-for-go-2-0-developer-preview/) the Developer Preview for the [v2 AWS SDK for Go](https://github.com/aws/aws-sdk-go-v2). The v2 SDK is available at https://github.com/aws/aws-sdk-go-v2, and `go get github.com/aws/aws-sdk-go-v2` via `go get`. Check out the v2 SDK's [changes and updates](https://github.com/aws/aws-sdk-go-v2/blob/master/CHANGELOG.md), and let us know what you think. We want your feedback.  | ||||
| 
 | ||||
| ## Installing | ||||
| 
 | ||||
| If you are using Go 1.5 with the `GO15VENDOREXPERIMENT=1` vendoring flag, or 1.6 and higher you can use the following command to retrieve the SDK. The SDK's non-testing dependencies will be included and are vendored in the `vendor` folder. | ||||
|  | @ -305,7 +307,7 @@ documentation for the errors that could be returned. | |||
|   // will leak connections. | ||||
|   defer result.Body.Close() | ||||
| 
 | ||||
|   fmt.Println("Object Size:", aws.StringValue(result.ContentLength)) | ||||
|   fmt.Println("Object Size:", aws.Int64Value(result.ContentLength)) | ||||
| ``` | ||||
| 
 | ||||
| ### API Request Pagination and Resource Waiters | ||||
|  | @ -332,7 +334,7 @@ take a callback function that will be called for each page of the API's response | |||
| ``` | ||||
| 
 | ||||
| Waiter helper methods provide the functionality to wait for an AWS resource | ||||
| state. These methods abstract the logic needed to to check the state of an | ||||
| state. These methods abstract the logic needed to check the state of an | ||||
| AWS resource, and wait until that resource is in a desired state. The waiter | ||||
| will block until the resource is in the state that is desired, an error occurs, | ||||
| or the waiter times out. If a resource times out the error code returned will | ||||
|  |  | |||
|  | @ -15,6 +15,12 @@ type Config struct { | |||
| 	Endpoint      string | ||||
| 	SigningRegion string | ||||
| 	SigningName   string | ||||
| 
 | ||||
| 	// States that the signing name did not come from a modeled source but
 | ||||
| 	// was derived based on other data. Used by service client constructors
 | ||||
| 	// to determine if the signin name can be overriden based on metadata the
 | ||||
| 	// service has.
 | ||||
| 	SigningNameDerived bool | ||||
| } | ||||
| 
 | ||||
| // ConfigProvider provides a generic way for a service client to receive
 | ||||
|  | @ -85,6 +91,6 @@ func (c *Client) AddDebugHandlers() { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	c.Handlers.Send.PushFrontNamed(request.NamedHandler{Name: "awssdk.client.LogRequest", Fn: logRequest}) | ||||
| 	c.Handlers.Send.PushBackNamed(request.NamedHandler{Name: "awssdk.client.LogResponse", Fn: logResponse}) | ||||
| 	c.Handlers.Send.PushFrontNamed(LogHTTPRequestHandler) | ||||
| 	c.Handlers.Send.PushBackNamed(LogHTTPResponseHandler) | ||||
| } | ||||
|  |  | |||
|  | @ -1,12 +1,11 @@ | |||
| package client | ||||
| 
 | ||||
| import ( | ||||
| 	"math/rand" | ||||
| 	"strconv" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/aws/request" | ||||
| 	"github.com/aws/aws-sdk-go/internal/sdkrand" | ||||
| ) | ||||
| 
 | ||||
| // DefaultRetryer implements basic retry logic using exponential backoff for
 | ||||
|  | @ -31,8 +30,6 @@ func (d DefaultRetryer) MaxRetries() int { | |||
| 	return d.NumMaxRetries | ||||
| } | ||||
| 
 | ||||
| var seededRand = rand.New(&lockedSource{src: rand.NewSource(time.Now().UnixNano())}) | ||||
| 
 | ||||
| // RetryRules returns the delay duration before retrying this request again
 | ||||
| func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration { | ||||
| 	// Set the upper limit of delay in retrying at ~five minutes
 | ||||
|  | @ -53,7 +50,7 @@ func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration { | |||
| 		retryCount = 13 | ||||
| 	} | ||||
| 
 | ||||
| 	delay := (1 << uint(retryCount)) * (seededRand.Intn(minTime) + minTime) | ||||
| 	delay := (1 << uint(retryCount)) * (sdkrand.SeededRand.Intn(minTime) + minTime) | ||||
| 	return time.Duration(delay) * time.Millisecond | ||||
| } | ||||
| 
 | ||||
|  | @ -65,7 +62,7 @@ func (d DefaultRetryer) ShouldRetry(r *request.Request) bool { | |||
| 		return *r.Retryable | ||||
| 	} | ||||
| 
 | ||||
| 	if r.HTTPResponse.StatusCode >= 500 { | ||||
| 	if r.HTTPResponse.StatusCode >= 500 && r.HTTPResponse.StatusCode != 501 { | ||||
| 		return true | ||||
| 	} | ||||
| 	return r.IsErrorRetryable() || d.shouldThrottle(r) | ||||
|  | @ -117,22 +114,3 @@ func canUseRetryAfterHeader(r *request.Request) bool { | |||
| 
 | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // lockedSource is a thread-safe implementation of rand.Source
 | ||||
| type lockedSource struct { | ||||
| 	lk  sync.Mutex | ||||
| 	src rand.Source | ||||
| } | ||||
| 
 | ||||
| func (r *lockedSource) Int63() (n int64) { | ||||
| 	r.lk.Lock() | ||||
| 	n = r.src.Int63() | ||||
| 	r.lk.Unlock() | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (r *lockedSource) Seed(seed int64) { | ||||
| 	r.lk.Lock() | ||||
| 	r.src.Seed(seed) | ||||
| 	r.lk.Unlock() | ||||
| } | ||||
|  |  | |||
|  | @ -44,22 +44,57 @@ func (reader *teeReaderCloser) Close() error { | |||
| 	return reader.Source.Close() | ||||
| } | ||||
| 
 | ||||
| // LogHTTPRequestHandler is a SDK request handler to log the HTTP request sent
 | ||||
| // to a service. Will include the HTTP request body if the LogLevel of the
 | ||||
| // request matches LogDebugWithHTTPBody.
 | ||||
| var LogHTTPRequestHandler = request.NamedHandler{ | ||||
| 	Name: "awssdk.client.LogRequest", | ||||
| 	Fn:   logRequest, | ||||
| } | ||||
| 
 | ||||
| func logRequest(r *request.Request) { | ||||
| 	logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody) | ||||
| 	dumpedBody, err := httputil.DumpRequestOut(r.HTTPRequest, logBody) | ||||
| 	bodySeekable := aws.IsReaderSeekable(r.Body) | ||||
| 
 | ||||
| 	b, err := httputil.DumpRequestOut(r.HTTPRequest, logBody) | ||||
| 	if err != nil { | ||||
| 		r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg, r.ClientInfo.ServiceName, r.Operation.Name, err)) | ||||
| 		r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg, | ||||
| 			r.ClientInfo.ServiceName, r.Operation.Name, err)) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if logBody { | ||||
| 		if !bodySeekable { | ||||
| 			r.SetReaderBody(aws.ReadSeekCloser(r.HTTPRequest.Body)) | ||||
| 		} | ||||
| 		// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
 | ||||
| 		// Body as a NoOpCloser and will not be reset after read by the HTTP
 | ||||
| 		// client reader.
 | ||||
| 		r.ResetBody() | ||||
| 	} | ||||
| 
 | ||||
| 	r.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.ClientInfo.ServiceName, r.Operation.Name, string(dumpedBody))) | ||||
| 	r.Config.Logger.Log(fmt.Sprintf(logReqMsg, | ||||
| 		r.ClientInfo.ServiceName, r.Operation.Name, string(b))) | ||||
| } | ||||
| 
 | ||||
| // LogHTTPRequestHeaderHandler is a SDK request handler to log the HTTP request sent
 | ||||
| // to a service. Will only log the HTTP request's headers. The request payload
 | ||||
| // will not be read.
 | ||||
| var LogHTTPRequestHeaderHandler = request.NamedHandler{ | ||||
| 	Name: "awssdk.client.LogRequestHeader", | ||||
| 	Fn:   logRequestHeader, | ||||
| } | ||||
| 
 | ||||
| func logRequestHeader(r *request.Request) { | ||||
| 	b, err := httputil.DumpRequestOut(r.HTTPRequest, false) | ||||
| 	if err != nil { | ||||
| 		r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg, | ||||
| 			r.ClientInfo.ServiceName, r.Operation.Name, err)) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	r.Config.Logger.Log(fmt.Sprintf(logReqMsg, | ||||
| 		r.ClientInfo.ServiceName, r.Operation.Name, string(b))) | ||||
| } | ||||
| 
 | ||||
| const logRespMsg = `DEBUG: Response %s/%s Details: | ||||
|  | @ -72,27 +107,44 @@ const logRespErrMsg = `DEBUG ERROR: Response %s/%s: | |||
| %s | ||||
| -----------------------------------------------------` | ||||
| 
 | ||||
| // LogHTTPResponseHandler is a SDK request handler to log the HTTP response
 | ||||
| // received from a service. Will include the HTTP response body if the LogLevel
 | ||||
| // of the request matches LogDebugWithHTTPBody.
 | ||||
| var LogHTTPResponseHandler = request.NamedHandler{ | ||||
| 	Name: "awssdk.client.LogResponse", | ||||
| 	Fn:   logResponse, | ||||
| } | ||||
| 
 | ||||
| func logResponse(r *request.Request) { | ||||
| 	lw := &logWriter{r.Config.Logger, bytes.NewBuffer(nil)} | ||||
| 	r.HTTPResponse.Body = &teeReaderCloser{ | ||||
| 		Reader: io.TeeReader(r.HTTPResponse.Body, lw), | ||||
| 		Source: r.HTTPResponse.Body, | ||||
| 
 | ||||
| 	logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody) | ||||
| 	if logBody { | ||||
| 		r.HTTPResponse.Body = &teeReaderCloser{ | ||||
| 			Reader: io.TeeReader(r.HTTPResponse.Body, lw), | ||||
| 			Source: r.HTTPResponse.Body, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	handlerFn := func(req *request.Request) { | ||||
| 		body, err := httputil.DumpResponse(req.HTTPResponse, false) | ||||
| 		b, err := httputil.DumpResponse(req.HTTPResponse, false) | ||||
| 		if err != nil { | ||||
| 			lw.Logger.Log(fmt.Sprintf(logRespErrMsg, req.ClientInfo.ServiceName, req.Operation.Name, err)) | ||||
| 			lw.Logger.Log(fmt.Sprintf(logRespErrMsg, | ||||
| 				req.ClientInfo.ServiceName, req.Operation.Name, err)) | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		b, err := ioutil.ReadAll(lw.buf) | ||||
| 		if err != nil { | ||||
| 			lw.Logger.Log(fmt.Sprintf(logRespErrMsg, req.ClientInfo.ServiceName, req.Operation.Name, err)) | ||||
| 			return | ||||
| 		} | ||||
| 		lw.Logger.Log(fmt.Sprintf(logRespMsg, req.ClientInfo.ServiceName, req.Operation.Name, string(body))) | ||||
| 		if req.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody) { | ||||
| 		lw.Logger.Log(fmt.Sprintf(logRespMsg, | ||||
| 			req.ClientInfo.ServiceName, req.Operation.Name, string(b))) | ||||
| 
 | ||||
| 		if logBody { | ||||
| 			b, err := ioutil.ReadAll(lw.buf) | ||||
| 			if err != nil { | ||||
| 				lw.Logger.Log(fmt.Sprintf(logRespErrMsg, | ||||
| 					req.ClientInfo.ServiceName, req.Operation.Name, err)) | ||||
| 				return | ||||
| 			} | ||||
| 
 | ||||
| 			lw.Logger.Log(string(b)) | ||||
| 		} | ||||
| 	} | ||||
|  | @ -106,3 +158,27 @@ func logResponse(r *request.Request) { | |||
| 		Name: handlerName, Fn: handlerFn, | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| // LogHTTPResponseHeaderHandler is a SDK request handler to log the HTTP
 | ||||
| // response received from a service. Will only log the HTTP response's headers.
 | ||||
| // The response payload will not be read.
 | ||||
| var LogHTTPResponseHeaderHandler = request.NamedHandler{ | ||||
| 	Name: "awssdk.client.LogResponseHeader", | ||||
| 	Fn:   logResponseHeader, | ||||
| } | ||||
| 
 | ||||
| func logResponseHeader(r *request.Request) { | ||||
| 	if r.Config.Logger == nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	b, err := httputil.DumpResponse(r.HTTPResponse, false) | ||||
| 	if err != nil { | ||||
| 		r.Config.Logger.Log(fmt.Sprintf(logRespErrMsg, | ||||
| 			r.ClientInfo.ServiceName, r.Operation.Name, err)) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	r.Config.Logger.Log(fmt.Sprintf(logRespMsg, | ||||
| 		r.ClientInfo.ServiceName, r.Operation.Name, string(b))) | ||||
| } | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ package metadata | |||
| // ClientInfo wraps immutable data from the client.Client structure.
 | ||||
| type ClientInfo struct { | ||||
| 	ServiceName   string | ||||
| 	ServiceID     string | ||||
| 	APIVersion    string | ||||
| 	Endpoint      string | ||||
| 	SigningName   string | ||||
|  |  | |||
|  | @ -151,6 +151,15 @@ type Config struct { | |||
| 	// with accelerate.
 | ||||
| 	S3UseAccelerate *bool | ||||
| 
 | ||||
| 	// S3DisableContentMD5Validation config option is temporarily disabled,
 | ||||
| 	// For S3 GetObject API calls, #1837.
 | ||||
| 	//
 | ||||
| 	// Set this to `true` to disable the S3 service client from automatically
 | ||||
| 	// adding the ContentMD5 to S3 Object Put and Upload API calls. This option
 | ||||
| 	// will also disable the SDK from performing object ContentMD5 validation
 | ||||
| 	// on GetObject API calls.
 | ||||
| 	S3DisableContentMD5Validation *bool | ||||
| 
 | ||||
| 	// Set this to `true` to disable the EC2Metadata client from overriding the
 | ||||
| 	// default http.Client's Timeout. This is helpful if you do not want the
 | ||||
| 	// EC2Metadata client to create a new http.Client. This options is only
 | ||||
|  | @ -168,7 +177,7 @@ type Config struct { | |||
| 	//
 | ||||
| 	EC2MetadataDisableTimeoutOverride *bool | ||||
| 
 | ||||
| 	// Instructs the endpiont to be generated for a service client to
 | ||||
| 	// Instructs the endpoint to be generated for a service client to
 | ||||
| 	// be the dual stack endpoint. The dual stack endpoint will support
 | ||||
| 	// both IPv4 and IPv6 addressing.
 | ||||
| 	//
 | ||||
|  | @ -336,6 +345,15 @@ func (c *Config) WithS3Disable100Continue(disable bool) *Config { | |||
| func (c *Config) WithS3UseAccelerate(enable bool) *Config { | ||||
| 	c.S3UseAccelerate = &enable | ||||
| 	return c | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // WithS3DisableContentMD5Validation sets a config
 | ||||
| // S3DisableContentMD5Validation value returning a Config pointer for chaining.
 | ||||
| func (c *Config) WithS3DisableContentMD5Validation(enable bool) *Config { | ||||
| 	c.S3DisableContentMD5Validation = &enable | ||||
| 	return c | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // WithUseDualStack sets a config UseDualStack value returning a Config
 | ||||
|  | @ -435,6 +453,10 @@ func mergeInConfig(dst *Config, other *Config) { | |||
| 		dst.S3UseAccelerate = other.S3UseAccelerate | ||||
| 	} | ||||
| 
 | ||||
| 	if other.S3DisableContentMD5Validation != nil { | ||||
| 		dst.S3DisableContentMD5Validation = other.S3DisableContentMD5Validation | ||||
| 	} | ||||
| 
 | ||||
| 	if other.UseDualStack != nil { | ||||
| 		dst.UseDualStack = other.UseDualStack | ||||
| 	} | ||||
|  |  | |||
|  | @ -3,12 +3,10 @@ package corehandlers | |||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"regexp" | ||||
| 	"runtime" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
|  | @ -36,18 +34,13 @@ var BuildContentLengthHandler = request.NamedHandler{Name: "core.BuildContentLen | |||
| 	if slength := r.HTTPRequest.Header.Get("Content-Length"); slength != "" { | ||||
| 		length, _ = strconv.ParseInt(slength, 10, 64) | ||||
| 	} else { | ||||
| 		switch body := r.Body.(type) { | ||||
| 		case nil: | ||||
| 			length = 0 | ||||
| 		case lener: | ||||
| 			length = int64(body.Len()) | ||||
| 		case io.Seeker: | ||||
| 			r.BodyStart, _ = body.Seek(0, 1) | ||||
| 			end, _ := body.Seek(0, 2) | ||||
| 			body.Seek(r.BodyStart, 0) // make sure to seek back to original location
 | ||||
| 			length = end - r.BodyStart | ||||
| 		default: | ||||
| 			panic("Cannot get length of body, must provide `ContentLength`") | ||||
| 		if r.Body != nil { | ||||
| 			var err error | ||||
| 			length, err = aws.SeekerLen(r.Body) | ||||
| 			if err != nil { | ||||
| 				r.Error = awserr.New(request.ErrCodeSerialization, "failed to get request body's length", err) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -60,13 +53,6 @@ var BuildContentLengthHandler = request.NamedHandler{Name: "core.BuildContentLen | |||
| 	} | ||||
| }} | ||||
| 
 | ||||
| // SDKVersionUserAgentHandler is a request handler for adding the SDK Version to the user agent.
 | ||||
| var SDKVersionUserAgentHandler = request.NamedHandler{ | ||||
| 	Name: "core.SDKVersionUserAgentHandler", | ||||
| 	Fn: request.MakeAddToUserAgentHandler(aws.SDKName, aws.SDKVersion, | ||||
| 		runtime.Version(), runtime.GOOS, runtime.GOARCH), | ||||
| } | ||||
| 
 | ||||
| var reStatusCode = regexp.MustCompile(`^(\d{3})`) | ||||
| 
 | ||||
| // ValidateReqSigHandler is a request handler to ensure that the request's
 | ||||
|  |  | |||
|  | @ -0,0 +1,37 @@ | |||
| package corehandlers | ||||
| 
 | ||||
| import ( | ||||
| 	"os" | ||||
| 	"runtime" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/aws" | ||||
| 	"github.com/aws/aws-sdk-go/aws/request" | ||||
| ) | ||||
| 
 | ||||
| // SDKVersionUserAgentHandler is a request handler for adding the SDK Version
 | ||||
| // to the user agent.
 | ||||
| var SDKVersionUserAgentHandler = request.NamedHandler{ | ||||
| 	Name: "core.SDKVersionUserAgentHandler", | ||||
| 	Fn: request.MakeAddToUserAgentHandler(aws.SDKName, aws.SDKVersion, | ||||
| 		runtime.Version(), runtime.GOOS, runtime.GOARCH), | ||||
| } | ||||
| 
 | ||||
| const execEnvVar = `AWS_EXECUTION_ENV` | ||||
| const execEnvUAKey = `exec_env` | ||||
| 
 | ||||
| // AddHostExecEnvUserAgentHander is a request handler appending the SDK's
 | ||||
| // execution environment to the user agent.
 | ||||
| //
 | ||||
| // If the environment variable AWS_EXECUTION_ENV is set, its value will be
 | ||||
| // appended to the user agent string.
 | ||||
| var AddHostExecEnvUserAgentHander = request.NamedHandler{ | ||||
| 	Name: "core.AddHostExecEnvUserAgentHander", | ||||
| 	Fn: func(r *request.Request) { | ||||
| 		v := os.Getenv(execEnvVar) | ||||
| 		if len(v) == 0 { | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		request.AddToUserAgent(r, execEnvUAKey+"/"+v) | ||||
| 	}, | ||||
| } | ||||
|  | @ -158,13 +158,14 @@ func (e *Expiry) SetExpiration(expiration time.Time, window time.Duration) { | |||
| 
 | ||||
| // IsExpired returns if the credentials are expired.
 | ||||
| func (e *Expiry) IsExpired() bool { | ||||
| 	if e.CurrentTime == nil { | ||||
| 		e.CurrentTime = time.Now | ||||
| 	curTime := e.CurrentTime | ||||
| 	if curTime == nil { | ||||
| 		curTime = time.Now | ||||
| 	} | ||||
| 	return e.expiration.Before(e.CurrentTime()) | ||||
| 	return e.expiration.Before(curTime()) | ||||
| } | ||||
| 
 | ||||
| // A Credentials provides synchronous safe retrieval of AWS credentials Value.
 | ||||
| // A Credentials provides concurrency safe retrieval of AWS credentials Value.
 | ||||
| // Credentials will cache the credentials value until they expire. Once the value
 | ||||
| // expires the next Get will attempt to retrieve valid credentials.
 | ||||
| //
 | ||||
|  | @ -178,7 +179,8 @@ func (e *Expiry) IsExpired() bool { | |||
| type Credentials struct { | ||||
| 	creds        Value | ||||
| 	forceRefresh bool | ||||
| 	m            sync.Mutex | ||||
| 
 | ||||
| 	m sync.RWMutex | ||||
| 
 | ||||
| 	provider Provider | ||||
| } | ||||
|  | @ -201,6 +203,17 @@ func NewCredentials(provider Provider) *Credentials { | |||
| // If Credentials.Expire() was called the credentials Value will be force
 | ||||
| // expired, and the next call to Get() will cause them to be refreshed.
 | ||||
| func (c *Credentials) Get() (Value, error) { | ||||
| 	// Check the cached credentials first with just the read lock.
 | ||||
| 	c.m.RLock() | ||||
| 	if !c.isExpired() { | ||||
| 		creds := c.creds | ||||
| 		c.m.RUnlock() | ||||
| 		return creds, nil | ||||
| 	} | ||||
| 	c.m.RUnlock() | ||||
| 
 | ||||
| 	// Credentials are expired need to retrieve the credentials taking the full
 | ||||
| 	// lock.
 | ||||
| 	c.m.Lock() | ||||
| 	defer c.m.Unlock() | ||||
| 
 | ||||
|  | @ -234,8 +247,8 @@ func (c *Credentials) Expire() { | |||
| // If the Credentials were forced to be expired with Expire() this will
 | ||||
| // reflect that override.
 | ||||
| func (c *Credentials) IsExpired() bool { | ||||
| 	c.m.Lock() | ||||
| 	defer c.m.Unlock() | ||||
| 	c.m.RLock() | ||||
| 	defer c.m.RUnlock() | ||||
| 
 | ||||
| 	return c.isExpired() | ||||
| } | ||||
|  |  | |||
							
								
								
									
										6
									
								
								vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go
								
								
									generated
								
								
									vendored
								
								
							
							
						
						
									
										6
									
								
								vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go
								
								
									generated
								
								
									vendored
								
								
							|  | @ -4,7 +4,6 @@ import ( | |||
| 	"bufio" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"path" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
|  | @ -12,6 +11,7 @@ import ( | |||
| 	"github.com/aws/aws-sdk-go/aws/client" | ||||
| 	"github.com/aws/aws-sdk-go/aws/credentials" | ||||
| 	"github.com/aws/aws-sdk-go/aws/ec2metadata" | ||||
| 	"github.com/aws/aws-sdk-go/internal/sdkuri" | ||||
| ) | ||||
| 
 | ||||
| // ProviderName provides a name of EC2Role provider
 | ||||
|  | @ -125,7 +125,7 @@ type ec2RoleCredRespBody struct { | |||
| 	Message string | ||||
| } | ||||
| 
 | ||||
| const iamSecurityCredsPath = "/iam/security-credentials" | ||||
| const iamSecurityCredsPath = "iam/security-credentials/" | ||||
| 
 | ||||
| // requestCredList requests a list of credentials from the EC2 service.
 | ||||
| // If there are no credentials, or there is an error making or receiving the request
 | ||||
|  | @ -153,7 +153,7 @@ func requestCredList(client *ec2metadata.EC2Metadata) ([]string, error) { | |||
| // If the credentials cannot be found, or there is an error reading the response
 | ||||
| // and error will be returned.
 | ||||
| func requestCred(client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCredRespBody, error) { | ||||
| 	resp, err := client.GetMetadata(path.Join(iamSecurityCredsPath, credsName)) | ||||
| 	resp, err := client.GetMetadata(sdkuri.PathJoin(iamSecurityCredsPath, credsName)) | ||||
| 	if err != nil { | ||||
| 		return ec2RoleCredRespBody{}, | ||||
| 			awserr.New("EC2RoleRequestError", | ||||
|  |  | |||
|  | @ -0,0 +1,46 @@ | |||
| // Package csm provides Client Side Monitoring (CSM) which enables sending metrics
 | ||||
| // via UDP connection. Using the Start function will enable the reporting of
 | ||||
| // metrics on a given port. If Start is called, with different parameters, again,
 | ||||
| // a panic will occur.
 | ||||
| //
 | ||||
| // Pause can be called to pause any metrics publishing on a given port. Sessions
 | ||||
| // that have had their handlers modified via InjectHandlers may still be used.
 | ||||
| // However, the handlers will act as a no-op meaning no metrics will be published.
 | ||||
| //
 | ||||
| //	Example:
 | ||||
| //		r, err := csm.Start("clientID", ":31000")
 | ||||
| //		if err != nil {
 | ||||
| //			panic(fmt.Errorf("failed starting CSM:  %v", err))
 | ||||
| //		}
 | ||||
| //
 | ||||
| //		sess, err := session.NewSession(&aws.Config{})
 | ||||
| //		if err != nil {
 | ||||
| //			panic(fmt.Errorf("failed loading session: %v", err))
 | ||||
| //		}
 | ||||
| //
 | ||||
| //		r.InjectHandlers(&sess.Handlers)
 | ||||
| //
 | ||||
| //		client := s3.New(sess)
 | ||||
| //		resp, err := client.GetObject(&s3.GetObjectInput{
 | ||||
| //			Bucket: aws.String("bucket"),
 | ||||
| //			Key: aws.String("key"),
 | ||||
| //		})
 | ||||
| //
 | ||||
| //		// Will pause monitoring
 | ||||
| //		r.Pause()
 | ||||
| //		resp, err = client.GetObject(&s3.GetObjectInput{
 | ||||
| //			Bucket: aws.String("bucket"),
 | ||||
| //			Key: aws.String("key"),
 | ||||
| //		})
 | ||||
| //
 | ||||
| //		// Resume monitoring
 | ||||
| //		r.Continue()
 | ||||
| //
 | ||||
| // Start returns a Reporter that is used to enable or disable monitoring. If
 | ||||
| // access to the Reporter is required later, calling Get will return the Reporter
 | ||||
| // singleton.
 | ||||
| //
 | ||||
| //	Example:
 | ||||
| //		r := csm.Get()
 | ||||
| //		r.Continue()
 | ||||
| package csm | ||||
|  | @ -0,0 +1,67 @@ | |||
| package csm | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"sync" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	lock sync.Mutex | ||||
| ) | ||||
| 
 | ||||
| // Client side metric handler names
 | ||||
| const ( | ||||
| 	APICallMetricHandlerName        = "awscsm.SendAPICallMetric" | ||||
| 	APICallAttemptMetricHandlerName = "awscsm.SendAPICallAttemptMetric" | ||||
| ) | ||||
| 
 | ||||
| // Start will start the a long running go routine to capture
 | ||||
| // client side metrics. Calling start multiple time will only
 | ||||
| // start the metric listener once and will panic if a different
 | ||||
| // client ID or port is passed in.
 | ||||
| //
 | ||||
| //	Example:
 | ||||
| //		r, err := csm.Start("clientID", "127.0.0.1:8094")
 | ||||
| //		if err != nil {
 | ||||
| //			panic(fmt.Errorf("expected no error, but received %v", err))
 | ||||
| //		}
 | ||||
| //		sess := session.NewSession()
 | ||||
| //		r.InjectHandlers(sess.Handlers)
 | ||||
| //
 | ||||
| //		svc := s3.New(sess)
 | ||||
| //		out, err := svc.GetObject(&s3.GetObjectInput{
 | ||||
| //			Bucket: aws.String("bucket"),
 | ||||
| //			Key: aws.String("key"),
 | ||||
| //		})
 | ||||
| func Start(clientID string, url string) (*Reporter, error) { | ||||
| 	lock.Lock() | ||||
| 	defer lock.Unlock() | ||||
| 
 | ||||
| 	if sender == nil { | ||||
| 		sender = newReporter(clientID, url) | ||||
| 	} else { | ||||
| 		if sender.clientID != clientID { | ||||
| 			panic(fmt.Errorf("inconsistent client IDs. %q was expected, but received %q", sender.clientID, clientID)) | ||||
| 		} | ||||
| 
 | ||||
| 		if sender.url != url { | ||||
| 			panic(fmt.Errorf("inconsistent URLs. %q was expected, but received %q", sender.url, url)) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if err := connect(url); err != nil { | ||||
| 		sender = nil | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return sender, nil | ||||
| } | ||||
| 
 | ||||
| // Get will return a reporter if one exists, if one does not exist, nil will
 | ||||
| // be returned.
 | ||||
| func Get() *Reporter { | ||||
| 	lock.Lock() | ||||
| 	defer lock.Unlock() | ||||
| 
 | ||||
| 	return sender | ||||
| } | ||||
|  | @ -0,0 +1,51 @@ | |||
| package csm | ||||
| 
 | ||||
| import ( | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| type metricTime time.Time | ||||
| 
 | ||||
| func (t metricTime) MarshalJSON() ([]byte, error) { | ||||
| 	ns := time.Duration(time.Time(t).UnixNano()) | ||||
| 	return []byte(strconv.FormatInt(int64(ns/time.Millisecond), 10)), nil | ||||
| } | ||||
| 
 | ||||
| type metric struct { | ||||
| 	ClientID  *string     `json:"ClientId,omitempty"` | ||||
| 	API       *string     `json:"Api,omitempty"` | ||||
| 	Service   *string     `json:"Service,omitempty"` | ||||
| 	Timestamp *metricTime `json:"Timestamp,omitempty"` | ||||
| 	Type      *string     `json:"Type,omitempty"` | ||||
| 	Version   *int        `json:"Version,omitempty"` | ||||
| 
 | ||||
| 	AttemptCount *int `json:"AttemptCount,omitempty"` | ||||
| 	Latency      *int `json:"Latency,omitempty"` | ||||
| 
 | ||||
| 	Fqdn           *string `json:"Fqdn,omitempty"` | ||||
| 	UserAgent      *string `json:"UserAgent,omitempty"` | ||||
| 	AttemptLatency *int    `json:"AttemptLatency,omitempty"` | ||||
| 
 | ||||
| 	SessionToken   *string `json:"SessionToken,omitempty"` | ||||
| 	Region         *string `json:"Region,omitempty"` | ||||
| 	AccessKey      *string `json:"AccessKey,omitempty"` | ||||
| 	HTTPStatusCode *int    `json:"HttpStatusCode,omitempty"` | ||||
| 	XAmzID2        *string `json:"XAmzId2,omitempty"` | ||||
| 	XAmzRequestID  *string `json:"XAmznRequestId,omitempty"` | ||||
| 
 | ||||
| 	AWSException        *string `json:"AwsException,omitempty"` | ||||
| 	AWSExceptionMessage *string `json:"AwsExceptionMessage,omitempty"` | ||||
| 	SDKException        *string `json:"SdkException,omitempty"` | ||||
| 	SDKExceptionMessage *string `json:"SdkExceptionMessage,omitempty"` | ||||
| 
 | ||||
| 	DestinationIP    *string `json:"DestinationIp,omitempty"` | ||||
| 	ConnectionReused *int    `json:"ConnectionReused,omitempty"` | ||||
| 
 | ||||
| 	AcquireConnectionLatency *int `json:"AcquireConnectionLatency,omitempty"` | ||||
| 	ConnectLatency           *int `json:"ConnectLatency,omitempty"` | ||||
| 	RequestLatency           *int `json:"RequestLatency,omitempty"` | ||||
| 	DNSLatency               *int `json:"DnsLatency,omitempty"` | ||||
| 	TCPLatency               *int `json:"TcpLatency,omitempty"` | ||||
| 	SSLLatency               *int `json:"SslLatency,omitempty"` | ||||
| } | ||||
|  | @ -0,0 +1,54 @@ | |||
| package csm | ||||
| 
 | ||||
| import ( | ||||
| 	"sync/atomic" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	runningEnum = iota | ||||
| 	pausedEnum | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	// MetricsChannelSize of metrics to hold in the channel
 | ||||
| 	MetricsChannelSize = 100 | ||||
| ) | ||||
| 
 | ||||
| type metricChan struct { | ||||
| 	ch     chan metric | ||||
| 	paused int64 | ||||
| } | ||||
| 
 | ||||
| func newMetricChan(size int) metricChan { | ||||
| 	return metricChan{ | ||||
| 		ch: make(chan metric, size), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (ch *metricChan) Pause() { | ||||
| 	atomic.StoreInt64(&ch.paused, pausedEnum) | ||||
| } | ||||
| 
 | ||||
| func (ch *metricChan) Continue() { | ||||
| 	atomic.StoreInt64(&ch.paused, runningEnum) | ||||
| } | ||||
| 
 | ||||
| func (ch *metricChan) IsPaused() bool { | ||||
| 	v := atomic.LoadInt64(&ch.paused) | ||||
| 	return v == pausedEnum | ||||
| } | ||||
| 
 | ||||
| // Push will push metrics to the metric channel if the channel
 | ||||
| // is not paused
 | ||||
| func (ch *metricChan) Push(m metric) bool { | ||||
| 	if ch.IsPaused() { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	select { | ||||
| 	case ch.ch <- m: | ||||
| 		return true | ||||
| 	default: | ||||
| 		return false | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,231 @@ | |||
| package csm | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"net" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/aws" | ||||
| 	"github.com/aws/aws-sdk-go/aws/awserr" | ||||
| 	"github.com/aws/aws-sdk-go/aws/request" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	// DefaultPort is used when no port is specified
 | ||||
| 	DefaultPort = "31000" | ||||
| ) | ||||
| 
 | ||||
| // Reporter will gather metrics of API requests made and
 | ||||
| // send those metrics to the CSM endpoint.
 | ||||
| type Reporter struct { | ||||
| 	clientID  string | ||||
| 	url       string | ||||
| 	conn      net.Conn | ||||
| 	metricsCh metricChan | ||||
| 	done      chan struct{} | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	sender *Reporter | ||||
| ) | ||||
| 
 | ||||
| func connect(url string) error { | ||||
| 	const network = "udp" | ||||
| 	if err := sender.connect(network, url); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if sender.done == nil { | ||||
| 		sender.done = make(chan struct{}) | ||||
| 		go sender.start() | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func newReporter(clientID, url string) *Reporter { | ||||
| 	return &Reporter{ | ||||
| 		clientID:  clientID, | ||||
| 		url:       url, | ||||
| 		metricsCh: newMetricChan(MetricsChannelSize), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (rep *Reporter) sendAPICallAttemptMetric(r *request.Request) { | ||||
| 	if rep == nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	now := time.Now() | ||||
| 	creds, _ := r.Config.Credentials.Get() | ||||
| 
 | ||||
| 	m := metric{ | ||||
| 		ClientID:  aws.String(rep.clientID), | ||||
| 		API:       aws.String(r.Operation.Name), | ||||
| 		Service:   aws.String(r.ClientInfo.ServiceID), | ||||
| 		Timestamp: (*metricTime)(&now), | ||||
| 		UserAgent: aws.String(r.HTTPRequest.Header.Get("User-Agent")), | ||||
| 		Region:    r.Config.Region, | ||||
| 		Type:      aws.String("ApiCallAttempt"), | ||||
| 		Version:   aws.Int(1), | ||||
| 
 | ||||
| 		XAmzRequestID: aws.String(r.RequestID), | ||||
| 
 | ||||
| 		AttemptCount:   aws.Int(r.RetryCount + 1), | ||||
| 		AttemptLatency: aws.Int(int(now.Sub(r.AttemptTime).Nanoseconds() / int64(time.Millisecond))), | ||||
| 		AccessKey:      aws.String(creds.AccessKeyID), | ||||
| 	} | ||||
| 
 | ||||
| 	if r.HTTPResponse != nil { | ||||
| 		m.HTTPStatusCode = aws.Int(r.HTTPResponse.StatusCode) | ||||
| 	} | ||||
| 
 | ||||
| 	if r.Error != nil { | ||||
| 		if awserr, ok := r.Error.(awserr.Error); ok { | ||||
| 			setError(&m, awserr) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	rep.metricsCh.Push(m) | ||||
| } | ||||
| 
 | ||||
| func setError(m *metric, err awserr.Error) { | ||||
| 	msg := err.Error() | ||||
| 	code := err.Code() | ||||
| 
 | ||||
| 	switch code { | ||||
| 	case "RequestError", | ||||
| 		"SerializationError", | ||||
| 		request.CanceledErrorCode: | ||||
| 		m.SDKException = &code | ||||
| 		m.SDKExceptionMessage = &msg | ||||
| 	default: | ||||
| 		m.AWSException = &code | ||||
| 		m.AWSExceptionMessage = &msg | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (rep *Reporter) sendAPICallMetric(r *request.Request) { | ||||
| 	if rep == nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	now := time.Now() | ||||
| 	m := metric{ | ||||
| 		ClientID:      aws.String(rep.clientID), | ||||
| 		API:           aws.String(r.Operation.Name), | ||||
| 		Service:       aws.String(r.ClientInfo.ServiceID), | ||||
| 		Timestamp:     (*metricTime)(&now), | ||||
| 		Type:          aws.String("ApiCall"), | ||||
| 		AttemptCount:  aws.Int(r.RetryCount + 1), | ||||
| 		Latency:       aws.Int(int(time.Now().Sub(r.Time) / time.Millisecond)), | ||||
| 		XAmzRequestID: aws.String(r.RequestID), | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: Probably want to figure something out for logging dropped
 | ||||
| 	// metrics
 | ||||
| 	rep.metricsCh.Push(m) | ||||
| } | ||||
| 
 | ||||
| func (rep *Reporter) connect(network, url string) error { | ||||
| 	if rep.conn != nil { | ||||
| 		rep.conn.Close() | ||||
| 	} | ||||
| 
 | ||||
| 	conn, err := net.Dial(network, url) | ||||
| 	if err != nil { | ||||
| 		return awserr.New("UDPError", "Could not connect", err) | ||||
| 	} | ||||
| 
 | ||||
| 	rep.conn = conn | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (rep *Reporter) close() { | ||||
| 	if rep.done != nil { | ||||
| 		close(rep.done) | ||||
| 	} | ||||
| 
 | ||||
| 	rep.metricsCh.Pause() | ||||
| } | ||||
| 
 | ||||
| func (rep *Reporter) start() { | ||||
| 	defer func() { | ||||
| 		rep.metricsCh.Pause() | ||||
| 	}() | ||||
| 
 | ||||
| 	for { | ||||
| 		select { | ||||
| 		case <-rep.done: | ||||
| 			rep.done = nil | ||||
| 			return | ||||
| 		case m := <-rep.metricsCh.ch: | ||||
| 			// TODO: What to do with this error? Probably should just log
 | ||||
| 			b, err := json.Marshal(m) | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			rep.conn.Write(b) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Pause will pause the metric channel preventing any new metrics from
 | ||||
| // being added.
 | ||||
| func (rep *Reporter) Pause() { | ||||
| 	lock.Lock() | ||||
| 	defer lock.Unlock() | ||||
| 
 | ||||
| 	if rep == nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	rep.close() | ||||
| } | ||||
| 
 | ||||
| // Continue will reopen the metric channel and allow for monitoring
 | ||||
| // to be resumed.
 | ||||
| func (rep *Reporter) Continue() { | ||||
| 	lock.Lock() | ||||
| 	defer lock.Unlock() | ||||
| 	if rep == nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if !rep.metricsCh.IsPaused() { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	rep.metricsCh.Continue() | ||||
| } | ||||
| 
 | ||||
| // InjectHandlers will will enable client side metrics and inject the proper
 | ||||
| // handlers to handle how metrics are sent.
 | ||||
| //
 | ||||
| //	Example:
 | ||||
| //		// Start must be called in order to inject the correct handlers
 | ||||
| //		r, err := csm.Start("clientID", "127.0.0.1:8094")
 | ||||
| //		if err != nil {
 | ||||
| //			panic(fmt.Errorf("expected no error, but received %v", err))
 | ||||
| //		}
 | ||||
| //
 | ||||
| //		sess := session.NewSession()
 | ||||
| //		r.InjectHandlers(&sess.Handlers)
 | ||||
| //
 | ||||
| //		// create a new service client with our client side metric session
 | ||||
| //		svc := s3.New(sess)
 | ||||
| func (rep *Reporter) InjectHandlers(handlers *request.Handlers) { | ||||
| 	if rep == nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	apiCallHandler := request.NamedHandler{Name: APICallMetricHandlerName, Fn: rep.sendAPICallMetric} | ||||
| 	apiCallAttemptHandler := request.NamedHandler{Name: APICallAttemptMetricHandlerName, Fn: rep.sendAPICallAttemptMetric} | ||||
| 
 | ||||
| 	handlers.Complete.PushFrontNamed(apiCallHandler) | ||||
| 	handlers.Complete.PushFrontNamed(apiCallAttemptHandler) | ||||
| 
 | ||||
| 	handlers.AfterRetry.PushFrontNamed(apiCallAttemptHandler) | ||||
| } | ||||
|  | @ -9,6 +9,7 @@ package defaults | |||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"os" | ||||
|  | @ -72,6 +73,7 @@ func Handlers() request.Handlers { | |||
| 	handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler) | ||||
| 	handlers.Validate.AfterEachFn = request.HandlerListStopOnError | ||||
| 	handlers.Build.PushBackNamed(corehandlers.SDKVersionUserAgentHandler) | ||||
| 	handlers.Build.PushBackNamed(corehandlers.AddHostExecEnvUserAgentHander) | ||||
| 	handlers.Build.AfterEachFn = request.HandlerListStopOnError | ||||
| 	handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler) | ||||
| 	handlers.Send.PushBackNamed(corehandlers.ValidateReqSigHandler) | ||||
|  | @ -90,14 +92,25 @@ func Handlers() request.Handlers { | |||
| func CredChain(cfg *aws.Config, handlers request.Handlers) *credentials.Credentials { | ||||
| 	return credentials.NewCredentials(&credentials.ChainProvider{ | ||||
| 		VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors), | ||||
| 		Providers: []credentials.Provider{ | ||||
| 			&credentials.EnvProvider{}, | ||||
| 			&credentials.SharedCredentialsProvider{Filename: "", Profile: ""}, | ||||
| 			RemoteCredProvider(*cfg, handlers), | ||||
| 		}, | ||||
| 		Providers:     CredProviders(cfg, handlers), | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| // CredProviders returns the slice of providers used in
 | ||||
| // the default credential chain.
 | ||||
| //
 | ||||
| // For applications that need to use some other provider (for example use
 | ||||
| // different  environment variables for legacy reasons) but still fall back
 | ||||
| // on the default chain of providers. This allows that default chaint to be
 | ||||
| // automatically updated
 | ||||
| func CredProviders(cfg *aws.Config, handlers request.Handlers) []credentials.Provider { | ||||
| 	return []credentials.Provider{ | ||||
| 		&credentials.EnvProvider{}, | ||||
| 		&credentials.SharedCredentialsProvider{Filename: "", Profile: ""}, | ||||
| 		RemoteCredProvider(*cfg, handlers), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| const ( | ||||
| 	httpProviderEnvVar     = "AWS_CONTAINER_CREDENTIALS_FULL_URI" | ||||
| 	ecsCredsProviderEnvVar = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" | ||||
|  | @ -118,14 +131,43 @@ func RemoteCredProvider(cfg aws.Config, handlers request.Handlers) credentials.P | |||
| 	return ec2RoleProvider(cfg, handlers) | ||||
| } | ||||
| 
 | ||||
| var lookupHostFn = net.LookupHost | ||||
| 
 | ||||
| func isLoopbackHost(host string) (bool, error) { | ||||
| 	ip := net.ParseIP(host) | ||||
| 	if ip != nil { | ||||
| 		return ip.IsLoopback(), nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Host is not an ip, perform lookup
 | ||||
| 	addrs, err := lookupHostFn(host) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	for _, addr := range addrs { | ||||
| 		if !net.ParseIP(addr).IsLoopback() { | ||||
| 			return false, nil | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return true, nil | ||||
| } | ||||
| 
 | ||||
| func localHTTPCredProvider(cfg aws.Config, handlers request.Handlers, u string) credentials.Provider { | ||||
| 	var errMsg string | ||||
| 
 | ||||
| 	parsed, err := url.Parse(u) | ||||
| 	if err != nil { | ||||
| 		errMsg = fmt.Sprintf("invalid URL, %v", err) | ||||
| 	} else if host := aws.URLHostname(parsed); !(host == "localhost" || host == "127.0.0.1") { | ||||
| 		errMsg = fmt.Sprintf("invalid host address, %q, only localhost and 127.0.0.1 are valid.", host) | ||||
| 	} else { | ||||
| 		host := aws.URLHostname(parsed) | ||||
| 		if len(host) == 0 { | ||||
| 			errMsg = "unable to parse host from local HTTP cred provider URL" | ||||
| 		} else if isLoopback, loopbackErr := isLoopbackHost(host); loopbackErr != nil { | ||||
| 			errMsg = fmt.Sprintf("failed to resolve host %q, %v", host, loopbackErr) | ||||
| 		} else if !isLoopback { | ||||
| 			errMsg = fmt.Sprintf("invalid endpoint host, %q, only loopback hosts are allowed.", host) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if len(errMsg) > 0 { | ||||
|  |  | |||
|  | @ -4,12 +4,12 @@ import ( | |||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"path" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/aws/awserr" | ||||
| 	"github.com/aws/aws-sdk-go/aws/request" | ||||
| 	"github.com/aws/aws-sdk-go/internal/sdkuri" | ||||
| ) | ||||
| 
 | ||||
| // GetMetadata uses the path provided to request information from the EC2
 | ||||
|  | @ -19,7 +19,7 @@ func (c *EC2Metadata) GetMetadata(p string) (string, error) { | |||
| 	op := &request.Operation{ | ||||
| 		Name:       "GetMetadata", | ||||
| 		HTTPMethod: "GET", | ||||
| 		HTTPPath:   path.Join("/", "meta-data", p), | ||||
| 		HTTPPath:   sdkuri.PathJoin("/meta-data", p), | ||||
| 	} | ||||
| 
 | ||||
| 	output := &metadataOutput{} | ||||
|  | @ -35,7 +35,7 @@ func (c *EC2Metadata) GetUserData() (string, error) { | |||
| 	op := &request.Operation{ | ||||
| 		Name:       "GetUserData", | ||||
| 		HTTPMethod: "GET", | ||||
| 		HTTPPath:   path.Join("/", "user-data"), | ||||
| 		HTTPPath:   "/user-data", | ||||
| 	} | ||||
| 
 | ||||
| 	output := &metadataOutput{} | ||||
|  | @ -56,7 +56,7 @@ func (c *EC2Metadata) GetDynamicData(p string) (string, error) { | |||
| 	op := &request.Operation{ | ||||
| 		Name:       "GetDynamicData", | ||||
| 		HTTPMethod: "GET", | ||||
| 		HTTPPath:   path.Join("/", "dynamic", p), | ||||
| 		HTTPPath:   sdkuri.PathJoin("/dynamic", p), | ||||
| 	} | ||||
| 
 | ||||
| 	output := &metadataOutput{} | ||||
|  |  | |||
|  | @ -1,5 +1,10 @@ | |||
| // Package ec2metadata provides the client for making API calls to the
 | ||||
| // EC2 Metadata service.
 | ||||
| //
 | ||||
| // This package's client can be disabled completely by setting the environment
 | ||||
| // variable "AWS_EC2_METADATA_DISABLED=true". This environment variable set to
 | ||||
| // true instructs the SDK to disable the EC2 Metadata client. The client cannot
 | ||||
| // be used while the environemnt variable is set to true, (case insensitive).
 | ||||
| package ec2metadata | ||||
| 
 | ||||
| import ( | ||||
|  | @ -7,17 +12,21 @@ import ( | |||
| 	"errors" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/aws" | ||||
| 	"github.com/aws/aws-sdk-go/aws/awserr" | ||||
| 	"github.com/aws/aws-sdk-go/aws/client" | ||||
| 	"github.com/aws/aws-sdk-go/aws/client/metadata" | ||||
| 	"github.com/aws/aws-sdk-go/aws/corehandlers" | ||||
| 	"github.com/aws/aws-sdk-go/aws/request" | ||||
| ) | ||||
| 
 | ||||
| // ServiceName is the name of the service.
 | ||||
| const ServiceName = "ec2metadata" | ||||
| const disableServiceEnvVar = "AWS_EC2_METADATA_DISABLED" | ||||
| 
 | ||||
| // A EC2Metadata is an EC2 Metadata service Client.
 | ||||
| type EC2Metadata struct { | ||||
|  | @ -75,6 +84,21 @@ func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio | |||
| 	svc.Handlers.Validate.Clear() | ||||
| 	svc.Handlers.Validate.PushBack(validateEndpointHandler) | ||||
| 
 | ||||
| 	// Disable the EC2 Metadata service if the environment variable is set.
 | ||||
| 	// This shortcirctes the service's functionality to always fail to send
 | ||||
| 	// requests.
 | ||||
| 	if strings.ToLower(os.Getenv(disableServiceEnvVar)) == "true" { | ||||
| 		svc.Handlers.Send.SwapNamed(request.NamedHandler{ | ||||
| 			Name: corehandlers.SendHandler.Name, | ||||
| 			Fn: func(r *request.Request) { | ||||
| 				r.Error = awserr.New( | ||||
| 					request.CanceledErrorCode, | ||||
| 					"EC2 IMDS access disabled via "+disableServiceEnvVar+" env var", | ||||
| 					nil) | ||||
| 			}, | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	// Add additional options to the service config
 | ||||
| 	for _, option := range opts { | ||||
| 		option(svc.Client) | ||||
|  |  | |||
|  | @ -84,6 +84,7 @@ func decodeV3Endpoints(modelDef modelDefinition, opts DecodeModelOptions) (Resol | |||
| 		custAddEC2Metadata(p) | ||||
| 		custAddS3DualStack(p) | ||||
| 		custRmIotDataService(p) | ||||
| 		custFixAppAutoscalingChina(p) | ||||
| 	} | ||||
| 
 | ||||
| 	return ps, nil | ||||
|  | @ -122,6 +123,27 @@ func custRmIotDataService(p *partition) { | |||
| 	delete(p.Services, "data.iot") | ||||
| } | ||||
| 
 | ||||
| func custFixAppAutoscalingChina(p *partition) { | ||||
| 	if p.ID != "aws-cn" { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	const serviceName = "application-autoscaling" | ||||
| 	s, ok := p.Services[serviceName] | ||||
| 	if !ok { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	const expectHostname = `autoscaling.{region}.amazonaws.com` | ||||
| 	if e, a := s.Defaults.Hostname, expectHostname; e != a { | ||||
| 		fmt.Printf("custFixAppAutoscalingChina: ignoring customization, expected %s, got %s\n", e, a) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	s.Defaults.Hostname = expectHostname + ".cn" | ||||
| 	p.Services[serviceName] = s | ||||
| } | ||||
| 
 | ||||
| type decodeModelError struct { | ||||
| 	awsError | ||||
| } | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -206,10 +206,11 @@ func (p Partition) EndpointFor(service, region string, opts ...func(*Options)) ( | |||
| // enumerating over the regions in a partition.
 | ||||
| func (p Partition) Regions() map[string]Region { | ||||
| 	rs := map[string]Region{} | ||||
| 	for id := range p.p.Regions { | ||||
| 	for id, r := range p.p.Regions { | ||||
| 		rs[id] = Region{ | ||||
| 			id: id, | ||||
| 			p:  p.p, | ||||
| 			id:   id, | ||||
| 			desc: r.Description, | ||||
| 			p:    p.p, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -240,6 +241,10 @@ type Region struct { | |||
| // ID returns the region's identifier.
 | ||||
| func (r Region) ID() string { return r.id } | ||||
| 
 | ||||
| // Description returns the region's description. The region description
 | ||||
| // is free text, it can be empty, and it may change between SDK releases.
 | ||||
| func (r Region) Description() string { return r.desc } | ||||
| 
 | ||||
| // ResolveEndpoint resolves an endpoint from the context of the region given
 | ||||
| // a service. See Partition.EndpointFor for usage and errors that can be returned.
 | ||||
| func (r Region) ResolveEndpoint(service string, opts ...func(*Options)) (ResolvedEndpoint, error) { | ||||
|  | @ -284,10 +289,11 @@ func (s Service) ResolveEndpoint(region string, opts ...func(*Options)) (Resolve | |||
| func (s Service) Regions() map[string]Region { | ||||
| 	rs := map[string]Region{} | ||||
| 	for id := range s.p.Services[s.id].Endpoints { | ||||
| 		if _, ok := s.p.Regions[id]; ok { | ||||
| 		if r, ok := s.p.Regions[id]; ok { | ||||
| 			rs[id] = Region{ | ||||
| 				id: id, | ||||
| 				p:  s.p, | ||||
| 				id:   id, | ||||
| 				desc: r.Description, | ||||
| 				p:    s.p, | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -347,6 +353,10 @@ type ResolvedEndpoint struct { | |||
| 	// The service name that should be used for signing requests.
 | ||||
| 	SigningName string | ||||
| 
 | ||||
| 	// States that the signing name for this endpoint was derived from metadata
 | ||||
| 	// passed in, but was not explicitly modeled.
 | ||||
| 	SigningNameDerived bool | ||||
| 
 | ||||
| 	// The signing method that should be used for signing requests.
 | ||||
| 	SigningMethod string | ||||
| } | ||||
|  |  | |||
|  | @ -226,16 +226,20 @@ func (e endpoint) resolve(service, region, dnsSuffix string, defs []endpoint, op | |||
| 	if len(signingRegion) == 0 { | ||||
| 		signingRegion = region | ||||
| 	} | ||||
| 
 | ||||
| 	signingName := e.CredentialScope.Service | ||||
| 	var signingNameDerived bool | ||||
| 	if len(signingName) == 0 { | ||||
| 		signingName = service | ||||
| 		signingNameDerived = true | ||||
| 	} | ||||
| 
 | ||||
| 	return ResolvedEndpoint{ | ||||
| 		URL:           u, | ||||
| 		SigningRegion: signingRegion, | ||||
| 		SigningName:   signingName, | ||||
| 		SigningMethod: getByPriority(e.SignatureVersions, signerPriority, defaultSigner), | ||||
| 		URL:                u, | ||||
| 		SigningRegion:      signingRegion, | ||||
| 		SigningName:        signingName, | ||||
| 		SigningNameDerived: signingNameDerived, | ||||
| 		SigningMethod:      getByPriority(e.SignatureVersions, signerPriority, defaultSigner), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -71,6 +71,12 @@ const ( | |||
| 	// LogDebugWithRequestErrors states the SDK should log when service requests fail
 | ||||
| 	// to build, send, validate, or unmarshal.
 | ||||
| 	LogDebugWithRequestErrors | ||||
| 
 | ||||
| 	// LogDebugWithEventStreamBody states the SDK should log EventStream
 | ||||
| 	// request and response bodys. This should be used to log the EventStream
 | ||||
| 	// wire unmarshaled message content of requests and responses made while
 | ||||
| 	// using the SDK Will also enable LogDebug.
 | ||||
| 	LogDebugWithEventStreamBody | ||||
| ) | ||||
| 
 | ||||
| // A Logger is a minimalistic interface for the SDK to log messages to. Should
 | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ type Handlers struct { | |||
| 	Send             HandlerList | ||||
| 	ValidateResponse HandlerList | ||||
| 	Unmarshal        HandlerList | ||||
| 	UnmarshalStream  HandlerList | ||||
| 	UnmarshalMeta    HandlerList | ||||
| 	UnmarshalError   HandlerList | ||||
| 	Retry            HandlerList | ||||
|  | @ -30,6 +31,7 @@ func (h *Handlers) Copy() Handlers { | |||
| 		Send:             h.Send.copy(), | ||||
| 		ValidateResponse: h.ValidateResponse.copy(), | ||||
| 		Unmarshal:        h.Unmarshal.copy(), | ||||
| 		UnmarshalStream:  h.UnmarshalStream.copy(), | ||||
| 		UnmarshalError:   h.UnmarshalError.copy(), | ||||
| 		UnmarshalMeta:    h.UnmarshalMeta.copy(), | ||||
| 		Retry:            h.Retry.copy(), | ||||
|  | @ -45,6 +47,7 @@ func (h *Handlers) Clear() { | |||
| 	h.Send.Clear() | ||||
| 	h.Sign.Clear() | ||||
| 	h.Unmarshal.Clear() | ||||
| 	h.UnmarshalStream.Clear() | ||||
| 	h.UnmarshalMeta.Clear() | ||||
| 	h.UnmarshalError.Clear() | ||||
| 	h.ValidateResponse.Clear() | ||||
|  | @ -172,6 +175,21 @@ func (l *HandlerList) SwapNamed(n NamedHandler) (swapped bool) { | |||
| 	return swapped | ||||
| } | ||||
| 
 | ||||
| // Swap will swap out all handlers matching the name passed in. The matched
 | ||||
| // handlers will be swapped in. True is returned if the handlers were swapped.
 | ||||
| func (l *HandlerList) Swap(name string, replace NamedHandler) bool { | ||||
| 	var swapped bool | ||||
| 
 | ||||
| 	for i := 0; i < len(l.list); i++ { | ||||
| 		if l.list[i].Name == name { | ||||
| 			l.list[i] = replace | ||||
| 			swapped = true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return swapped | ||||
| } | ||||
| 
 | ||||
| // SetBackNamed will replace the named handler if it exists in the handler list.
 | ||||
| // If the handler does not exist the handler will be added to the end of the list.
 | ||||
| func (l *HandlerList) SetBackNamed(n NamedHandler) { | ||||
|  |  | |||
|  | @ -3,6 +3,8 @@ package request | |||
| import ( | ||||
| 	"io" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/internal/sdkio" | ||||
| ) | ||||
| 
 | ||||
| // offsetReader is a thread-safe io.ReadCloser to prevent racing
 | ||||
|  | @ -15,7 +17,7 @@ type offsetReader struct { | |||
| 
 | ||||
| func newOffsetReader(buf io.ReadSeeker, offset int64) *offsetReader { | ||||
| 	reader := &offsetReader{} | ||||
| 	buf.Seek(offset, 0) | ||||
| 	buf.Seek(offset, sdkio.SeekStart) | ||||
| 
 | ||||
| 	reader.buf = buf | ||||
| 	return reader | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ import ( | |||
| 	"github.com/aws/aws-sdk-go/aws" | ||||
| 	"github.com/aws/aws-sdk-go/aws/awserr" | ||||
| 	"github.com/aws/aws-sdk-go/aws/client/metadata" | ||||
| 	"github.com/aws/aws-sdk-go/internal/sdkio" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
|  | @ -45,6 +46,7 @@ type Request struct { | |||
| 	Handlers   Handlers | ||||
| 
 | ||||
| 	Retryer | ||||
| 	AttemptTime            time.Time | ||||
| 	Time                   time.Time | ||||
| 	Operation              *Operation | ||||
| 	HTTPRequest            *http.Request | ||||
|  | @ -120,6 +122,7 @@ func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers, | |||
| 		Handlers:   handlers.Copy(), | ||||
| 
 | ||||
| 		Retryer:     retryer, | ||||
| 		AttemptTime: time.Now(), | ||||
| 		Time:        time.Now(), | ||||
| 		ExpireTime:  0, | ||||
| 		Operation:   operation, | ||||
|  | @ -224,6 +227,9 @@ func (r *Request) SetContext(ctx aws.Context) { | |||
| 
 | ||||
| // WillRetry returns if the request's can be retried.
 | ||||
| func (r *Request) WillRetry() bool { | ||||
| 	if !aws.IsReaderSeekable(r.Body) && r.HTTPRequest.Body != NoBody { | ||||
| 		return false | ||||
| 	} | ||||
| 	return r.Error != nil && aws.BoolValue(r.Retryable) && r.RetryCount < r.MaxRetries() | ||||
| } | ||||
| 
 | ||||
|  | @ -255,6 +261,7 @@ func (r *Request) SetStringBody(s string) { | |||
| // SetReaderBody will set the request's body reader.
 | ||||
| func (r *Request) SetReaderBody(reader io.ReadSeeker) { | ||||
| 	r.Body = reader | ||||
| 	r.BodyStart, _ = reader.Seek(0, sdkio.SeekCurrent) // Get the Bodies current offset.
 | ||||
| 	r.ResetBody() | ||||
| } | ||||
| 
 | ||||
|  | @ -292,6 +299,11 @@ func (r *Request) PresignRequest(expire time.Duration) (string, http.Header, err | |||
| 	return getPresignedURL(r, expire) | ||||
| } | ||||
| 
 | ||||
| // IsPresigned returns true if the request represents a presigned API url.
 | ||||
| func (r *Request) IsPresigned() bool { | ||||
| 	return r.ExpireTime != 0 | ||||
| } | ||||
| 
 | ||||
| func getPresignedURL(r *Request, expire time.Duration) (string, http.Header, error) { | ||||
| 	if expire <= 0 { | ||||
| 		return "", nil, awserr.New( | ||||
|  | @ -332,7 +344,7 @@ func debugLogReqError(r *Request, stage string, retrying bool, err error) { | |||
| 
 | ||||
| // Build will build the request's object so it can be signed and sent
 | ||||
| // to the service. Build will also validate all the request's parameters.
 | ||||
| // Anny additional build Handlers set on this request will be run
 | ||||
| // Any additional build Handlers set on this request will be run
 | ||||
| // in the order they were set.
 | ||||
| //
 | ||||
| // The request will only be built once. Multiple calls to build will have
 | ||||
|  | @ -358,9 +370,9 @@ func (r *Request) Build() error { | |||
| 	return r.Error | ||||
| } | ||||
| 
 | ||||
| // Sign will sign the request returning error if errors are encountered.
 | ||||
| // Sign will sign the request, returning error if errors are encountered.
 | ||||
| //
 | ||||
| // Send will build the request prior to signing. All Sign Handlers will
 | ||||
| // Sign will build the request prior to signing. All Sign Handlers will
 | ||||
| // be executed in the order they were set.
 | ||||
| func (r *Request) Sign() error { | ||||
| 	r.Build() | ||||
|  | @ -393,7 +405,7 @@ func (r *Request) getNextRequestBody() (io.ReadCloser, error) { | |||
| 	// of the SDK if they used that field.
 | ||||
| 	//
 | ||||
| 	// Related golang/go#18257
 | ||||
| 	l, err := computeBodyLength(r.Body) | ||||
| 	l, err := aws.SeekerLen(r.Body) | ||||
| 	if err != nil { | ||||
| 		return nil, awserr.New(ErrCodeSerialization, "failed to compute request body size", err) | ||||
| 	} | ||||
|  | @ -411,7 +423,8 @@ func (r *Request) getNextRequestBody() (io.ReadCloser, error) { | |||
| 		// Transfer-Encoding: chunked bodies for these methods.
 | ||||
| 		//
 | ||||
| 		// This would only happen if a aws.ReaderSeekerCloser was used with
 | ||||
| 		// a io.Reader that was not also an io.Seeker.
 | ||||
| 		// a io.Reader that was not also an io.Seeker, or did not implement
 | ||||
| 		// Len() method.
 | ||||
| 		switch r.Operation.HTTPMethod { | ||||
| 		case "GET", "HEAD", "DELETE": | ||||
| 			body = NoBody | ||||
|  | @ -423,49 +436,13 @@ func (r *Request) getNextRequestBody() (io.ReadCloser, error) { | |||
| 	return body, nil | ||||
| } | ||||
| 
 | ||||
| // Attempts to compute the length of the body of the reader using the
 | ||||
| // io.Seeker interface. If the value is not seekable because of being
 | ||||
| // a ReaderSeekerCloser without an unerlying Seeker -1 will be returned.
 | ||||
| // If no error occurs the length of the body will be returned.
 | ||||
| func computeBodyLength(r io.ReadSeeker) (int64, error) { | ||||
| 	seekable := true | ||||
| 	// Determine if the seeker is actually seekable. ReaderSeekerCloser
 | ||||
| 	// hides the fact that a io.Readers might not actually be seekable.
 | ||||
| 	switch v := r.(type) { | ||||
| 	case aws.ReaderSeekerCloser: | ||||
| 		seekable = v.IsSeeker() | ||||
| 	case *aws.ReaderSeekerCloser: | ||||
| 		seekable = v.IsSeeker() | ||||
| 	} | ||||
| 	if !seekable { | ||||
| 		return -1, nil | ||||
| 	} | ||||
| 
 | ||||
| 	curOffset, err := r.Seek(0, 1) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	endOffset, err := r.Seek(0, 2) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = r.Seek(curOffset, 0) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	return endOffset - curOffset, nil | ||||
| } | ||||
| 
 | ||||
| // GetBody will return an io.ReadSeeker of the Request's underlying
 | ||||
| // input body with a concurrency safe wrapper.
 | ||||
| func (r *Request) GetBody() io.ReadSeeker { | ||||
| 	return r.safeBody | ||||
| } | ||||
| 
 | ||||
| // Send will send the request returning error if errors are encountered.
 | ||||
| // Send will send the request, returning error if errors are encountered.
 | ||||
| //
 | ||||
| // Send will sign the request prior to sending. All Send Handlers will
 | ||||
| // be executed in the order they were set.
 | ||||
|  | @ -486,6 +463,7 @@ func (r *Request) Send() error { | |||
| 	}() | ||||
| 
 | ||||
| 	for { | ||||
| 		r.AttemptTime = time.Now() | ||||
| 		if aws.BoolValue(r.Retryable) { | ||||
| 			if r.Config.LogLevel.Matches(aws.LogDebugWithRequestRetries) { | ||||
| 				r.Config.Logger.Log(fmt.Sprintf("DEBUG: Retrying Request %s/%s, attempt %d", | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |||
| var NoBody = noBody{} | ||||
| 
 | ||||
| // ResetBody rewinds the request body back to its starting position, and
 | ||||
| // set's the HTTP Request body reference. When the body is read prior
 | ||||
| // sets the HTTP Request body reference. When the body is read prior
 | ||||
| // to being sent in the HTTP request it will need to be rewound.
 | ||||
| //
 | ||||
| // ResetBody will automatically be called by the SDK's build handler, but if
 | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ import ( | |||
| var NoBody = http.NoBody | ||||
| 
 | ||||
| // ResetBody rewinds the request body back to its starting position, and
 | ||||
| // set's the HTTP Request body reference. When the body is read prior
 | ||||
| // sets the HTTP Request body reference. When the body is read prior
 | ||||
| // to being sent in the HTTP request it will need to be rewound.
 | ||||
| //
 | ||||
| // ResetBody will automatically be called by the SDK's build handler, but if
 | ||||
|  |  | |||
|  | @ -35,8 +35,12 @@ type Pagination struct { | |||
| 	// NewRequest should always be built from the same API operations. It is
 | ||||
| 	// undefined if different API operations are returned on subsequent calls.
 | ||||
| 	NewRequest func() (*Request, error) | ||||
| 	// EndPageOnSameToken, when enabled, will allow the paginator to stop on
 | ||||
| 	// token that are the same as its previous tokens.
 | ||||
| 	EndPageOnSameToken bool | ||||
| 
 | ||||
| 	started    bool | ||||
| 	prevTokens []interface{} | ||||
| 	nextTokens []interface{} | ||||
| 
 | ||||
| 	err     error | ||||
|  | @ -49,7 +53,15 @@ type Pagination struct { | |||
| //
 | ||||
| // Will always return true if Next has not been called yet.
 | ||||
| func (p *Pagination) HasNextPage() bool { | ||||
| 	return !(p.started && len(p.nextTokens) == 0) | ||||
| 	if !p.started { | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	hasNextPage := len(p.nextTokens) != 0 | ||||
| 	if p.EndPageOnSameToken { | ||||
| 		return hasNextPage && !awsutil.DeepEqual(p.nextTokens, p.prevTokens) | ||||
| 	} | ||||
| 	return hasNextPage | ||||
| } | ||||
| 
 | ||||
| // Err returns the error Pagination encountered when retrieving the next page.
 | ||||
|  | @ -96,6 +108,7 @@ func (p *Pagination) Next() bool { | |||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	p.prevTokens = p.nextTokens | ||||
| 	p.nextTokens = req.nextPageTokens() | ||||
| 	p.curPage = req.Data | ||||
| 
 | ||||
|  | @ -142,13 +155,28 @@ func (r *Request) nextPageTokens() []interface{} { | |||
| 	tokens := []interface{}{} | ||||
| 	tokenAdded := false | ||||
| 	for _, outToken := range r.Operation.OutputTokens { | ||||
| 		v, _ := awsutil.ValuesAtPath(r.Data, outToken) | ||||
| 		if len(v) > 0 { | ||||
| 			tokens = append(tokens, v[0]) | ||||
| 			tokenAdded = true | ||||
| 		} else { | ||||
| 		vs, _ := awsutil.ValuesAtPath(r.Data, outToken) | ||||
| 		if len(vs) == 0 { | ||||
| 			tokens = append(tokens, nil) | ||||
| 			continue | ||||
| 		} | ||||
| 		v := vs[0] | ||||
| 
 | ||||
| 		switch tv := v.(type) { | ||||
| 		case *string: | ||||
| 			if len(aws.StringValue(tv)) == 0 { | ||||
| 				tokens = append(tokens, nil) | ||||
| 				continue | ||||
| 			} | ||||
| 		case string: | ||||
| 			if len(tv) == 0 { | ||||
| 				tokens = append(tokens, nil) | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		tokenAdded = true | ||||
| 		tokens = append(tokens, v) | ||||
| 	} | ||||
| 	if !tokenAdded { | ||||
| 		return nil | ||||
|  |  | |||
|  | @ -97,7 +97,7 @@ func isNestedErrorRetryable(parentErr awserr.Error) bool { | |||
| 	} | ||||
| 
 | ||||
| 	if t, ok := err.(temporaryError); ok { | ||||
| 		return t.Temporary() | ||||
| 		return t.Temporary() || isErrConnectionReset(err) | ||||
| 	} | ||||
| 
 | ||||
| 	return isErrConnectionReset(err) | ||||
|  |  | |||
|  | @ -128,7 +128,7 @@ read. The Session will be created from configuration values from the shared | |||
| credentials file (~/.aws/credentials) over those in the shared config file (~/.aws/config). | ||||
| 
 | ||||
| Credentials are the values the SDK should use for authenticating requests with | ||||
| AWS Services. They arfrom a configuration file will need to include both | ||||
| AWS Services. They are from a configuration file will need to include both | ||||
| aws_access_key_id and aws_secret_access_key must be provided together in the | ||||
| same file to be considered valid. The values will be ignored if not a complete | ||||
| group. aws_session_token is an optional field that can be provided if both of | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ import ( | |||
| 	"strconv" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/aws/credentials" | ||||
| 	"github.com/aws/aws-sdk-go/aws/defaults" | ||||
| ) | ||||
| 
 | ||||
| // EnvProviderName provides a name of the provider when config is loaded from environment.
 | ||||
|  | @ -95,9 +96,23 @@ type envConfig struct { | |||
| 	//
 | ||||
| 	//  AWS_CA_BUNDLE=$HOME/my_custom_ca_bundle
 | ||||
| 	CustomCABundle string | ||||
| 
 | ||||
| 	csmEnabled  string | ||||
| 	CSMEnabled  bool | ||||
| 	CSMPort     string | ||||
| 	CSMClientID string | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	csmEnabledEnvKey = []string{ | ||||
| 		"AWS_CSM_ENABLED", | ||||
| 	} | ||||
| 	csmPortEnvKey = []string{ | ||||
| 		"AWS_CSM_PORT", | ||||
| 	} | ||||
| 	csmClientIDEnvKey = []string{ | ||||
| 		"AWS_CSM_CLIENT_ID", | ||||
| 	} | ||||
| 	credAccessEnvKey = []string{ | ||||
| 		"AWS_ACCESS_KEY_ID", | ||||
| 		"AWS_ACCESS_KEY", | ||||
|  | @ -156,6 +171,12 @@ func envConfigLoad(enableSharedConfig bool) envConfig { | |||
| 	setFromEnvVal(&cfg.Creds.SecretAccessKey, credSecretEnvKey) | ||||
| 	setFromEnvVal(&cfg.Creds.SessionToken, credSessionEnvKey) | ||||
| 
 | ||||
| 	// CSM environment variables
 | ||||
| 	setFromEnvVal(&cfg.csmEnabled, csmEnabledEnvKey) | ||||
| 	setFromEnvVal(&cfg.CSMPort, csmPortEnvKey) | ||||
| 	setFromEnvVal(&cfg.CSMClientID, csmClientIDEnvKey) | ||||
| 	cfg.CSMEnabled = len(cfg.csmEnabled) > 0 | ||||
| 
 | ||||
| 	// Require logical grouping of credentials
 | ||||
| 	if len(cfg.Creds.AccessKeyID) == 0 || len(cfg.Creds.SecretAccessKey) == 0 { | ||||
| 		cfg.Creds = credentials.Value{} | ||||
|  | @ -176,6 +197,13 @@ func envConfigLoad(enableSharedConfig bool) envConfig { | |||
| 	setFromEnvVal(&cfg.SharedCredentialsFile, sharedCredsFileEnvKey) | ||||
| 	setFromEnvVal(&cfg.SharedConfigFile, sharedConfigFileEnvKey) | ||||
| 
 | ||||
| 	if len(cfg.SharedCredentialsFile) == 0 { | ||||
| 		cfg.SharedCredentialsFile = defaults.SharedCredentialsFilename() | ||||
| 	} | ||||
| 	if len(cfg.SharedConfigFile) == 0 { | ||||
| 		cfg.SharedConfigFile = defaults.SharedConfigFilename() | ||||
| 	} | ||||
| 
 | ||||
| 	cfg.CustomCABundle = os.Getenv("AWS_CA_BUNDLE") | ||||
| 
 | ||||
| 	return cfg | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ import ( | |||
| 	"github.com/aws/aws-sdk-go/aws/corehandlers" | ||||
| 	"github.com/aws/aws-sdk-go/aws/credentials" | ||||
| 	"github.com/aws/aws-sdk-go/aws/credentials/stscreds" | ||||
| 	"github.com/aws/aws-sdk-go/aws/csm" | ||||
| 	"github.com/aws/aws-sdk-go/aws/defaults" | ||||
| 	"github.com/aws/aws-sdk-go/aws/endpoints" | ||||
| 	"github.com/aws/aws-sdk-go/aws/request" | ||||
|  | @ -26,7 +27,7 @@ import ( | |||
| // Sessions are safe to create service clients concurrently, but it is not safe
 | ||||
| // to mutate the Session concurrently.
 | ||||
| //
 | ||||
| // The Session satisfies the service client's client.ClientConfigProvider.
 | ||||
| // The Session satisfies the service client's client.ConfigProvider.
 | ||||
| type Session struct { | ||||
| 	Config   *aws.Config | ||||
| 	Handlers request.Handlers | ||||
|  | @ -58,7 +59,12 @@ func New(cfgs ...*aws.Config) *Session { | |||
| 	envCfg := loadEnvConfig() | ||||
| 
 | ||||
| 	if envCfg.EnableSharedConfig { | ||||
| 		s, err := newSession(Options{}, envCfg, cfgs...) | ||||
| 		var cfg aws.Config | ||||
| 		cfg.MergeIn(cfgs...) | ||||
| 		s, err := NewSessionWithOptions(Options{ | ||||
| 			Config:            cfg, | ||||
| 			SharedConfigState: SharedConfigEnable, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			// Old session.New expected all errors to be discovered when
 | ||||
| 			// a request is made, and would report the errors then. This
 | ||||
|  | @ -76,10 +82,16 @@ func New(cfgs ...*aws.Config) *Session { | |||
| 				r.Error = err | ||||
| 			}) | ||||
| 		} | ||||
| 
 | ||||
| 		return s | ||||
| 	} | ||||
| 
 | ||||
| 	return deprecatedNewSession(cfgs...) | ||||
| 	s := deprecatedNewSession(cfgs...) | ||||
| 	if envCfg.CSMEnabled { | ||||
| 		enableCSM(&s.Handlers, envCfg.CSMClientID, envCfg.CSMPort, s.Config.Logger) | ||||
| 	} | ||||
| 
 | ||||
| 	return s | ||||
| } | ||||
| 
 | ||||
| // NewSession returns a new Session created from SDK defaults, config files,
 | ||||
|  | @ -243,13 +255,6 @@ func NewSessionWithOptions(opts Options) (*Session, error) { | |||
| 		envCfg.EnableSharedConfig = true | ||||
| 	} | ||||
| 
 | ||||
| 	if len(envCfg.SharedCredentialsFile) == 0 { | ||||
| 		envCfg.SharedCredentialsFile = defaults.SharedCredentialsFilename() | ||||
| 	} | ||||
| 	if len(envCfg.SharedConfigFile) == 0 { | ||||
| 		envCfg.SharedConfigFile = defaults.SharedConfigFilename() | ||||
| 	} | ||||
| 
 | ||||
| 	// Only use AWS_CA_BUNDLE if session option is not provided.
 | ||||
| 	if len(envCfg.CustomCABundle) != 0 && opts.CustomCABundle == nil { | ||||
| 		f, err := os.Open(envCfg.CustomCABundle) | ||||
|  | @ -302,10 +307,22 @@ func deprecatedNewSession(cfgs ...*aws.Config) *Session { | |||
| 	} | ||||
| 
 | ||||
| 	initHandlers(s) | ||||
| 
 | ||||
| 	return s | ||||
| } | ||||
| 
 | ||||
| func enableCSM(handlers *request.Handlers, clientID string, port string, logger aws.Logger) { | ||||
| 	logger.Log("Enabling CSM") | ||||
| 	if len(port) == 0 { | ||||
| 		port = csm.DefaultPort | ||||
| 	} | ||||
| 
 | ||||
| 	r, err := csm.Start(clientID, "127.0.0.1:"+port) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	r.InjectHandlers(handlers) | ||||
| } | ||||
| 
 | ||||
| func newSession(opts Options, envCfg envConfig, cfgs ...*aws.Config) (*Session, error) { | ||||
| 	cfg := defaults.Config() | ||||
| 	handlers := defaults.Handlers() | ||||
|  | @ -345,6 +362,9 @@ func newSession(opts Options, envCfg envConfig, cfgs ...*aws.Config) (*Session, | |||
| 	} | ||||
| 
 | ||||
| 	initHandlers(s) | ||||
| 	if envCfg.CSMEnabled { | ||||
| 		enableCSM(&s.Handlers, envCfg.CSMClientID, envCfg.CSMPort, s.Config.Logger) | ||||
| 	} | ||||
| 
 | ||||
| 	// Setup HTTP client with custom cert bundle if enabled
 | ||||
| 	if opts.CustomCABundle != nil { | ||||
|  | @ -573,11 +593,12 @@ func (s *Session) clientConfigWithErr(serviceName string, cfgs ...*aws.Config) ( | |||
| 	} | ||||
| 
 | ||||
| 	return client.Config{ | ||||
| 		Config:        s.Config, | ||||
| 		Handlers:      s.Handlers, | ||||
| 		Endpoint:      resolved.URL, | ||||
| 		SigningRegion: resolved.SigningRegion, | ||||
| 		SigningName:   resolved.SigningName, | ||||
| 		Config:             s.Config, | ||||
| 		Handlers:           s.Handlers, | ||||
| 		Endpoint:           resolved.URL, | ||||
| 		SigningRegion:      resolved.SigningRegion, | ||||
| 		SigningNameDerived: resolved.SigningNameDerived, | ||||
| 		SigningName:        resolved.SigningName, | ||||
| 	}, err | ||||
| } | ||||
| 
 | ||||
|  | @ -597,10 +618,11 @@ func (s *Session) ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) client.Conf | |||
| 	} | ||||
| 
 | ||||
| 	return client.Config{ | ||||
| 		Config:        s.Config, | ||||
| 		Handlers:      s.Handlers, | ||||
| 		Endpoint:      resolved.URL, | ||||
| 		SigningRegion: resolved.SigningRegion, | ||||
| 		SigningName:   resolved.SigningName, | ||||
| 		Config:             s.Config, | ||||
| 		Handlers:           s.Handlers, | ||||
| 		Endpoint:           resolved.URL, | ||||
| 		SigningRegion:      resolved.SigningRegion, | ||||
| 		SigningNameDerived: resolved.SigningNameDerived, | ||||
| 		SigningName:        resolved.SigningName, | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -71,6 +71,7 @@ import ( | |||
| 	"github.com/aws/aws-sdk-go/aws" | ||||
| 	"github.com/aws/aws-sdk-go/aws/credentials" | ||||
| 	"github.com/aws/aws-sdk-go/aws/request" | ||||
| 	"github.com/aws/aws-sdk-go/internal/sdkio" | ||||
| 	"github.com/aws/aws-sdk-go/private/protocol/rest" | ||||
| ) | ||||
| 
 | ||||
|  | @ -97,25 +98,25 @@ var ignoredHeaders = rules{ | |||
| var requiredSignedHeaders = rules{ | ||||
| 	whitelist{ | ||||
| 		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{}{}, | ||||
| 			"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{}{}, | ||||
|  | @ -134,6 +135,7 @@ var requiredSignedHeaders = rules{ | |||
| 			"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{}{}, | ||||
| 		}, | ||||
| 	}, | ||||
| 	patterns{"X-Amz-Meta-"}, | ||||
|  | @ -341,7 +343,9 @@ func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, regi | |||
| 
 | ||||
| 	ctx.sanitizeHostForHeader() | ||||
| 	ctx.assignAmzQueryValues() | ||||
| 	ctx.build(v4.DisableHeaderHoisting) | ||||
| 	if err := ctx.build(v4.DisableHeaderHoisting); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// If the request is not presigned the body should be attached to it. This
 | ||||
| 	// prevents the confusion of wanting to send a signed request without
 | ||||
|  | @ -503,11 +507,13 @@ func (v4 *Signer) logSigningInfo(ctx *signingCtx) { | |||
| 	v4.Logger.Log(msg) | ||||
| } | ||||
| 
 | ||||
| func (ctx *signingCtx) build(disableHeaderHoisting bool) { | ||||
| func (ctx *signingCtx) build(disableHeaderHoisting bool) error { | ||||
| 	ctx.buildTime()             // no depends
 | ||||
| 	ctx.buildCredentialString() // no depends
 | ||||
| 
 | ||||
| 	ctx.buildBodyDigest() | ||||
| 	if err := ctx.buildBodyDigest(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	unsignedHeaders := ctx.Request.Header | ||||
| 	if ctx.isPresign { | ||||
|  | @ -535,6 +541,8 @@ func (ctx *signingCtx) build(disableHeaderHoisting bool) { | |||
| 		} | ||||
| 		ctx.Request.Header.Set("Authorization", strings.Join(parts, ", ")) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (ctx *signingCtx) buildTime() { | ||||
|  | @ -661,21 +669,34 @@ func (ctx *signingCtx) buildSignature() { | |||
| 	ctx.signature = hex.EncodeToString(signature) | ||||
| } | ||||
| 
 | ||||
| func (ctx *signingCtx) buildBodyDigest() { | ||||
| func (ctx *signingCtx) buildBodyDigest() error { | ||||
| 	hash := ctx.Request.Header.Get("X-Amz-Content-Sha256") | ||||
| 	if hash == "" { | ||||
| 		if ctx.unsignedPayload || (ctx.isPresign && ctx.ServiceName == "s3") { | ||||
| 		includeSHA256Header := ctx.unsignedPayload || | ||||
| 			ctx.ServiceName == "s3" || | ||||
| 			ctx.ServiceName == "glacier" | ||||
| 
 | ||||
| 		s3Presign := ctx.isPresign && ctx.ServiceName == "s3" | ||||
| 
 | ||||
| 		if ctx.unsignedPayload || s3Presign { | ||||
| 			hash = "UNSIGNED-PAYLOAD" | ||||
| 			includeSHA256Header = !s3Presign | ||||
| 		} else if ctx.Body == nil { | ||||
| 			hash = emptyStringSHA256 | ||||
| 		} else { | ||||
| 			if !aws.IsReaderSeekable(ctx.Body) { | ||||
| 				return fmt.Errorf("cannot use unseekable request body %T, for signed request with body", ctx.Body) | ||||
| 			} | ||||
| 			hash = hex.EncodeToString(makeSha256Reader(ctx.Body)) | ||||
| 		} | ||||
| 		if ctx.unsignedPayload || ctx.ServiceName == "s3" || ctx.ServiceName == "glacier" { | ||||
| 
 | ||||
| 		if includeSHA256Header { | ||||
| 			ctx.Request.Header.Set("X-Amz-Content-Sha256", hash) | ||||
| 		} | ||||
| 	} | ||||
| 	ctx.bodyDigest = hash | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // isRequestSigned returns if the request is currently signed or presigned
 | ||||
|  | @ -715,8 +736,8 @@ func makeSha256(data []byte) []byte { | |||
| 
 | ||||
| func makeSha256Reader(reader io.ReadSeeker) []byte { | ||||
| 	hash := sha256.New() | ||||
| 	start, _ := reader.Seek(0, 1) | ||||
| 	defer reader.Seek(start, 0) | ||||
| 	start, _ := reader.Seek(0, sdkio.SeekCurrent) | ||||
| 	defer reader.Seek(start, sdkio.SeekStart) | ||||
| 
 | ||||
| 	io.Copy(hash, reader) | ||||
| 	return hash.Sum(nil) | ||||
|  |  | |||
|  | @ -3,6 +3,8 @@ package aws | |||
| import ( | ||||
| 	"io" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/internal/sdkio" | ||||
| ) | ||||
| 
 | ||||
| // ReadSeekCloser wraps a io.Reader returning a ReaderSeekerCloser. Should
 | ||||
|  | @ -22,6 +24,22 @@ type ReaderSeekerCloser struct { | |||
| 	r io.Reader | ||||
| } | ||||
| 
 | ||||
| // IsReaderSeekable returns if the underlying reader type can be seeked. A
 | ||||
| // io.Reader might not actually be seekable if it is the ReaderSeekerCloser
 | ||||
| // type.
 | ||||
| func IsReaderSeekable(r io.Reader) bool { | ||||
| 	switch v := r.(type) { | ||||
| 	case ReaderSeekerCloser: | ||||
| 		return v.IsSeeker() | ||||
| 	case *ReaderSeekerCloser: | ||||
| 		return v.IsSeeker() | ||||
| 	case io.ReadSeeker: | ||||
| 		return true | ||||
| 	default: | ||||
| 		return false | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Read reads from the reader up to size of p. The number of bytes read, and
 | ||||
| // error if it occurred will be returned.
 | ||||
| //
 | ||||
|  | @ -56,6 +74,71 @@ func (r ReaderSeekerCloser) IsSeeker() bool { | |||
| 	return ok | ||||
| } | ||||
| 
 | ||||
| // HasLen returns the length of the underlying reader if the value implements
 | ||||
| // the Len() int method.
 | ||||
| func (r ReaderSeekerCloser) HasLen() (int, bool) { | ||||
| 	type lenner interface { | ||||
| 		Len() int | ||||
| 	} | ||||
| 
 | ||||
| 	if lr, ok := r.r.(lenner); ok { | ||||
| 		return lr.Len(), true | ||||
| 	} | ||||
| 
 | ||||
| 	return 0, false | ||||
| } | ||||
| 
 | ||||
| // GetLen returns the length of the bytes remaining in the underlying reader.
 | ||||
| // Checks first for Len(), then io.Seeker to determine the size of the
 | ||||
| // underlying reader.
 | ||||
| //
 | ||||
| // Will return -1 if the length cannot be determined.
 | ||||
| func (r ReaderSeekerCloser) GetLen() (int64, error) { | ||||
| 	if l, ok := r.HasLen(); ok { | ||||
| 		return int64(l), nil | ||||
| 	} | ||||
| 
 | ||||
| 	if s, ok := r.r.(io.Seeker); ok { | ||||
| 		return seekerLen(s) | ||||
| 	} | ||||
| 
 | ||||
| 	return -1, nil | ||||
| } | ||||
| 
 | ||||
| // SeekerLen attempts to get the number of bytes remaining at the seeker's
 | ||||
| // current position.  Returns the number of bytes remaining or error.
 | ||||
| func SeekerLen(s io.Seeker) (int64, error) { | ||||
| 	// Determine if the seeker is actually seekable. ReaderSeekerCloser
 | ||||
| 	// hides the fact that a io.Readers might not actually be seekable.
 | ||||
| 	switch v := s.(type) { | ||||
| 	case ReaderSeekerCloser: | ||||
| 		return v.GetLen() | ||||
| 	case *ReaderSeekerCloser: | ||||
| 		return v.GetLen() | ||||
| 	} | ||||
| 
 | ||||
| 	return seekerLen(s) | ||||
| } | ||||
| 
 | ||||
| func seekerLen(s io.Seeker) (int64, error) { | ||||
| 	curOffset, err := s.Seek(0, sdkio.SeekCurrent) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	endOffset, err := s.Seek(0, sdkio.SeekEnd) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = s.Seek(curOffset, sdkio.SeekStart) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	return endOffset - curOffset, nil | ||||
| } | ||||
| 
 | ||||
| // Close closes the ReaderSeekerCloser.
 | ||||
| //
 | ||||
| // If the ReaderSeekerCloser is not an io.Closer nothing will be done.
 | ||||
|  |  | |||
|  | @ -5,4 +5,4 @@ package aws | |||
| const SDKName = "aws-sdk-go" | ||||
| 
 | ||||
| // SDKVersion is the version of this SDK
 | ||||
| const SDKVersion = "1.12.36" | ||||
| const SDKVersion = "1.15.11" | ||||
|  |  | |||
|  | @ -0,0 +1,10 @@ | |||
| // +build !go1.7
 | ||||
| 
 | ||||
| package sdkio | ||||
| 
 | ||||
| // Copy of Go 1.7 io package's Seeker constants.
 | ||||
| const ( | ||||
| 	SeekStart   = 0 // seek relative to the origin of the file
 | ||||
| 	SeekCurrent = 1 // seek relative to the current offset
 | ||||
| 	SeekEnd     = 2 // seek relative to the end
 | ||||
| ) | ||||
|  | @ -0,0 +1,12 @@ | |||
| // +build go1.7
 | ||||
| 
 | ||||
| package sdkio | ||||
| 
 | ||||
| import "io" | ||||
| 
 | ||||
| // Alias for Go 1.7 io package Seeker constants
 | ||||
| const ( | ||||
| 	SeekStart   = io.SeekStart   // seek relative to the origin of the file
 | ||||
| 	SeekCurrent = io.SeekCurrent // seek relative to the current offset
 | ||||
| 	SeekEnd     = io.SeekEnd     // seek relative to the end
 | ||||
| ) | ||||
							
								
								
									
										29
									
								
								vendor/github.com/aws/aws-sdk-go/internal/sdkrand/locked_source.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										29
									
								
								vendor/github.com/aws/aws-sdk-go/internal/sdkrand/locked_source.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,29 @@ | |||
| package sdkrand | ||||
| 
 | ||||
| import ( | ||||
| 	"math/rand" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| // lockedSource is a thread-safe implementation of rand.Source
 | ||||
| type lockedSource struct { | ||||
| 	lk  sync.Mutex | ||||
| 	src rand.Source | ||||
| } | ||||
| 
 | ||||
| func (r *lockedSource) Int63() (n int64) { | ||||
| 	r.lk.Lock() | ||||
| 	n = r.src.Int63() | ||||
| 	r.lk.Unlock() | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (r *lockedSource) Seed(seed int64) { | ||||
| 	r.lk.Lock() | ||||
| 	r.src.Seed(seed) | ||||
| 	r.lk.Unlock() | ||||
| } | ||||
| 
 | ||||
| // SeededRand is a new RNG using a thread safe implementation of rand.Source
 | ||||
| var SeededRand = rand.New(&lockedSource{src: rand.NewSource(time.Now().UnixNano())}) | ||||
|  | @ -0,0 +1,23 @@ | |||
| package sdkuri | ||||
| 
 | ||||
| import ( | ||||
| 	"path" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| // PathJoin will join the elements of the path delimited by the "/"
 | ||||
| // character. Similar to path.Join with the exception the trailing "/"
 | ||||
| // character is preserved if present.
 | ||||
| func PathJoin(elems ...string) string { | ||||
| 	if len(elems) == 0 { | ||||
| 		return "" | ||||
| 	} | ||||
| 
 | ||||
| 	hasTrailing := strings.HasSuffix(elems[len(elems)-1], "/") | ||||
| 	str := path.Join(elems...) | ||||
| 	if hasTrailing && str != "/" { | ||||
| 		str += "/" | ||||
| 	} | ||||
| 
 | ||||
| 	return str | ||||
| } | ||||
							
								
								
									
										144
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/debug.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										144
									
								
								vendor/github.com/aws/aws-sdk-go/private/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)) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										199
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/decode.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										199
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/decode.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,199 @@ | |||
| package eventstream | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/binary" | ||||
| 	"encoding/hex" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"hash" | ||||
| 	"hash/crc32" | ||||
| 	"io" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/aws" | ||||
| ) | ||||
| 
 | ||||
| // Decoder provides decoding of an Event Stream messages.
 | ||||
| type Decoder struct { | ||||
| 	r      io.Reader | ||||
| 	logger aws.Logger | ||||
| } | ||||
| 
 | ||||
| // NewDecoder initializes and returns a Decoder for decoding event
 | ||||
| // stream messages from the reader provided.
 | ||||
| func NewDecoder(r io.Reader) *Decoder { | ||||
| 	return &Decoder{ | ||||
| 		r: r, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Decode attempts to decode a single message from the event stream reader.
 | ||||
| // Will return the event stream message, or error if Decode fails to read
 | ||||
| // the message from the stream.
 | ||||
| func (d *Decoder) Decode(payloadBuf []byte) (m Message, err error) { | ||||
| 	reader := d.r | ||||
| 	if d.logger != nil { | ||||
| 		debugMsgBuf := bytes.NewBuffer(nil) | ||||
| 		reader = io.TeeReader(reader, debugMsgBuf) | ||||
| 		defer func() { | ||||
| 			logMessageDecode(d.logger, debugMsgBuf, m, err) | ||||
| 		}() | ||||
| 	} | ||||
| 
 | ||||
| 	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 | ||||
| } | ||||
| 
 | ||||
| // UseLogger specifies the Logger that that the decoder should use to log the
 | ||||
| // message decode to.
 | ||||
| func (d *Decoder) UseLogger(logger aws.Logger) { | ||||
| 	d.logger = logger | ||||
| } | ||||
| 
 | ||||
| func logMessageDecode(logger aws.Logger, msgBuf *bytes.Buffer, msg Message, decodeErr error) { | ||||
| 	w := bytes.NewBuffer(nil) | ||||
| 	defer func() { logger.Log(w.String()) }() | ||||
| 
 | ||||
| 	fmt.Fprintf(w, "Raw message:\n%s\n", | ||||
| 		hex.Dump(msgBuf.Bytes())) | ||||
| 
 | ||||
| 	if decodeErr != nil { | ||||
| 		fmt.Fprintf(w, "Decode 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 uint8(v), err | ||||
| 	} | ||||
| 
 | ||||
| 	var b [1]byte | ||||
| 	_, err := io.ReadFull(r, b[:]) | ||||
| 	return uint8(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 | ||||
| } | ||||
							
								
								
									
										114
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/encode.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										114
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/encode.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,114 @@ | |||
| package eventstream | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/binary" | ||||
| 	"hash" | ||||
| 	"hash/crc32" | ||||
| 	"io" | ||||
| ) | ||||
| 
 | ||||
| // Encoder provides EventStream message encoding.
 | ||||
| type Encoder struct { | ||||
| 	w io.Writer | ||||
| 
 | ||||
| 	headersBuf *bytes.Buffer | ||||
| } | ||||
| 
 | ||||
| // NewEncoder initializes and returns an Encoder to encode Event Stream
 | ||||
| // messages to an io.Writer.
 | ||||
| func NewEncoder(w io.Writer) *Encoder { | ||||
| 	return &Encoder{ | ||||
| 		w:          w, | ||||
| 		headersBuf: 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(msg Message) error { | ||||
| 	e.headersBuf.Reset() | ||||
| 
 | ||||
| 	err := encodeHeaders(e.headersBuf, msg.Headers) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	crc := crc32.New(crc32IEEETable) | ||||
| 	hashWriter := io.MultiWriter(e.w, 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() | ||||
| 	return binary.Write(e.w, binary.BigEndian, msgCRC) | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
| } | ||||
| 
 | ||||
| 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
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/error.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										23
									
								
								vendor/github.com/aws/aws-sdk-go/private/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" | ||||
| } | ||||
							
								
								
									
										196
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/api.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										196
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/api.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,196 @@ | |||
| package eventstreamapi | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/aws" | ||||
| 	"github.com/aws/aws-sdk-go/private/protocol" | ||||
| 	"github.com/aws/aws-sdk-go/private/protocol/eventstream" | ||||
| ) | ||||
| 
 | ||||
| // Unmarshaler provides the interface for unmarshaling a EventStream
 | ||||
| // message into a SDK type.
 | ||||
| type Unmarshaler interface { | ||||
| 	UnmarshalEvent(protocol.PayloadUnmarshaler, eventstream.Message) error | ||||
| } | ||||
| 
 | ||||
| // EventStream headers with specific meaning to async API functionality.
 | ||||
| const ( | ||||
| 	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` | ||||
| ) | ||||
| 
 | ||||
| // EventReader provides reading from the EventStream of an reader.
 | ||||
| type EventReader struct { | ||||
| 	reader  io.ReadCloser | ||||
| 	decoder *eventstream.Decoder | ||||
| 
 | ||||
| 	unmarshalerForEventType func(string) (Unmarshaler, error) | ||||
| 	payloadUnmarshaler      protocol.PayloadUnmarshaler | ||||
| 
 | ||||
| 	payloadBuf []byte | ||||
| } | ||||
| 
 | ||||
| // NewEventReader returns a EventReader built from the reader and unmarshaler
 | ||||
| // provided.  Use ReadStream method to start reading from the EventStream.
 | ||||
| func NewEventReader( | ||||
| 	reader io.ReadCloser, | ||||
| 	payloadUnmarshaler protocol.PayloadUnmarshaler, | ||||
| 	unmarshalerForEventType func(string) (Unmarshaler, error), | ||||
| ) *EventReader { | ||||
| 	return &EventReader{ | ||||
| 		reader:                  reader, | ||||
| 		decoder:                 eventstream.NewDecoder(reader), | ||||
| 		payloadUnmarshaler:      payloadUnmarshaler, | ||||
| 		unmarshalerForEventType: unmarshalerForEventType, | ||||
| 		payloadBuf:              make([]byte, 10*1024), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // UseLogger instructs the EventReader to use the logger and log level
 | ||||
| // specified.
 | ||||
| func (r *EventReader) UseLogger(logger aws.Logger, logLevel aws.LogLevelType) { | ||||
| 	if logger != nil && logLevel.Matches(aws.LogDebugWithEventStreamBody) { | ||||
| 		r.decoder.UseLogger(logger) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ReadEvent attempts to read a message from the EventStream and return the
 | ||||
| // unmarshaled event value that the message is for.
 | ||||
| //
 | ||||
| // For EventStream API errors check if the returned error satisfies the
 | ||||
| // awserr.Error interface to get the error's Code and Message components.
 | ||||
| //
 | ||||
| // EventUnmarshalers called with EventStream messages must take copies of the
 | ||||
| // message's Payload. The payload will is reused between events read.
 | ||||
| func (r *EventReader) ReadEvent() (event interface{}, err error) { | ||||
| 	msg, err := r.decoder.Decode(r.payloadBuf) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer func() { | ||||
| 		// Reclaim payload buffer for next message read.
 | ||||
| 		r.payloadBuf = msg.Payload[0:0] | ||||
| 	}() | ||||
| 
 | ||||
| 	typ, err := GetHeaderString(msg, MessageTypeHeader) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	switch typ { | ||||
| 	case EventMessageType: | ||||
| 		return r.unmarshalEventMessage(msg) | ||||
| 	case ExceptionMessageType: | ||||
| 		err = r.unmarshalEventException(msg) | ||||
| 		return nil, err | ||||
| 	case ErrorMessageType: | ||||
| 		return nil, r.unmarshalErrorMessage(msg) | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("unknown eventstream message type, %v", typ) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (r *EventReader) unmarshalEventMessage( | ||||
| 	msg eventstream.Message, | ||||
| ) (event interface{}, err error) { | ||||
| 	eventType, err := GetHeaderString(msg, EventTypeHeader) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	ev, err := r.unmarshalerForEventType(eventType) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	err = ev.UnmarshalEvent(r.payloadUnmarshaler, msg) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return ev, nil | ||||
| } | ||||
| 
 | ||||
| func (r *EventReader) unmarshalEventException( | ||||
| 	msg eventstream.Message, | ||||
| ) (err error) { | ||||
| 	eventType, err := GetHeaderString(msg, ExceptionTypeHeader) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	ev, err := r.unmarshalerForEventType(eventType) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	err = ev.UnmarshalEvent(r.payloadUnmarshaler, msg) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	var ok bool | ||||
| 	err, ok = ev.(error) | ||||
| 	if !ok { | ||||
| 		err = messageError{ | ||||
| 			code: "SerializationError", | ||||
| 			msg: fmt.Sprintf( | ||||
| 				"event stream exception %s mapped to non-error %T, %v", | ||||
| 				eventType, ev, ev, | ||||
| 			), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (r *EventReader) unmarshalErrorMessage(msg eventstream.Message) (err error) { | ||||
| 	var msgErr messageError | ||||
| 
 | ||||
| 	msgErr.code, err = GetHeaderString(msg, ErrorCodeHeader) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	msgErr.msg, err = GetHeaderString(msg, ErrorMessageHeader) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return msgErr | ||||
| } | ||||
| 
 | ||||
| // Close closes the EventReader's EventStream reader.
 | ||||
| func (r *EventReader) Close() error { | ||||
| 	return r.reader.Close() | ||||
| } | ||||
| 
 | ||||
| // GetHeaderString returns the value of the header as a string. If the header
 | ||||
| // is not set or the value is not a string an error will be returned.
 | ||||
| func GetHeaderString(msg eventstream.Message, headerName string) (string, error) { | ||||
| 	headerVal := msg.Headers.Get(headerName) | ||||
| 	if headerVal == nil { | ||||
| 		return "", fmt.Errorf("error header %s not present", headerName) | ||||
| 	} | ||||
| 
 | ||||
| 	v, ok := headerVal.Get().(string) | ||||
| 	if !ok { | ||||
| 		return "", fmt.Errorf("error header value is not a string, %T", headerVal) | ||||
| 	} | ||||
| 
 | ||||
| 	return v, nil | ||||
| } | ||||
							
								
								
									
										24
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/error.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										24
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/error.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,24 @@ | |||
| package eventstreamapi | ||||
| 
 | ||||
| import "fmt" | ||||
| 
 | ||||
| type messageError struct { | ||||
| 	code string | ||||
| 	msg  string | ||||
| } | ||||
| 
 | ||||
| func (e messageError) Code() string { | ||||
| 	return e.code | ||||
| } | ||||
| 
 | ||||
| func (e messageError) Message() string { | ||||
| 	return e.msg | ||||
| } | ||||
| 
 | ||||
| func (e messageError) Error() string { | ||||
| 	return fmt.Sprintf("%s: %s", e.code, e.msg) | ||||
| } | ||||
| 
 | ||||
| func (e messageError) OrigErr() error { | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										166
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										166
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,166 @@ | |||
| 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] | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
| } | ||||
							
								
								
									
										501
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header_value.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										501
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header_value.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,501 @@ | |||
| package eventstream | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/base64" | ||||
| 	"encoding/binary" | ||||
| 	"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 | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
| 	return fmt.Sprintf(`%X-%X-%X-%X-%X`, v[0:4], v[4:6], v[6:8], v[8:10], v[10:]) | ||||
| } | ||||
| 
 | ||||
| // 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) | ||||
| } | ||||
							
								
								
									
										103
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/message.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										103
									
								
								vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/message.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,103 @@ | |||
| package eventstream | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/binary" | ||||
| 	"hash/crc32" | ||||
| ) | ||||
| 
 | ||||
| const preludeLen = 8 | ||||
| const preludeCRCLen = 4 | ||||
| const msgCRCLen = 4 | ||||
| const minMsgLen = preludeLen + preludeCRCLen + msgCRCLen | ||||
| const maxPayloadLen = 1024 * 1024 * 16 // 16MB
 | ||||
| const maxHeadersLen = 1024 * 128       // 128KB
 | ||||
| const maxMsgLen = minMsgLen + maxHeadersLen + maxPayloadLen | ||||
| 
 | ||||
| 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 | ||||
| } | ||||
| 
 | ||||
| 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 || p.Length > maxMsgLen { | ||||
| 		return LengthError{ | ||||
| 			Part: "message prelude", | ||||
| 			Want: maxMsgLen, | ||||
| 			Have: int(p.Length), | ||||
| 		} | ||||
| 	} | ||||
| 	if p.HeadersLen > maxHeadersLen { | ||||
| 		return LengthError{ | ||||
| 			Part: "message headers", | ||||
| 			Want: maxHeadersLen, | ||||
| 			Have: int(p.HeadersLen), | ||||
| 		} | ||||
| 	} | ||||
| 	if payloadLen := p.PayloadLen(); payloadLen > maxPayloadLen { | ||||
| 		return LengthError{ | ||||
| 			Part: "message payload", | ||||
| 			Want: maxPayloadLen, | ||||
| 			Have: int(payloadLen), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| type rawMessage struct { | ||||
| 	messagePrelude | ||||
| 
 | ||||
| 	Headers []byte | ||||
| 	Payload []byte | ||||
| 
 | ||||
| 	CRC uint32 | ||||
| } | ||||
|  | @ -0,0 +1,81 @@ | |||
| package protocol | ||||
| 
 | ||||
| import ( | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/aws" | ||||
| 	"github.com/aws/aws-sdk-go/aws/client/metadata" | ||||
| 	"github.com/aws/aws-sdk-go/aws/request" | ||||
| ) | ||||
| 
 | ||||
| // PayloadUnmarshaler provides the interface for unmarshaling a payload's
 | ||||
| // reader into a SDK shape.
 | ||||
| type PayloadUnmarshaler interface { | ||||
| 	UnmarshalPayload(io.Reader, interface{}) error | ||||
| } | ||||
| 
 | ||||
| // HandlerPayloadUnmarshal implements the PayloadUnmarshaler from a
 | ||||
| // HandlerList. This provides the support for unmarshaling a payload reader to
 | ||||
| // a shape without needing a SDK request first.
 | ||||
| type HandlerPayloadUnmarshal struct { | ||||
| 	Unmarshalers request.HandlerList | ||||
| } | ||||
| 
 | ||||
| // UnmarshalPayload unmarshals the io.Reader payload into the SDK shape using
 | ||||
| // the Unmarshalers HandlerList provided. Returns an error if unable
 | ||||
| // unmarshaling fails.
 | ||||
| func (h HandlerPayloadUnmarshal) UnmarshalPayload(r io.Reader, v interface{}) error { | ||||
| 	req := &request.Request{ | ||||
| 		HTTPRequest: &http.Request{}, | ||||
| 		HTTPResponse: &http.Response{ | ||||
| 			StatusCode: 200, | ||||
| 			Header:     http.Header{}, | ||||
| 			Body:       ioutil.NopCloser(r), | ||||
| 		}, | ||||
| 		Data: v, | ||||
| 	} | ||||
| 
 | ||||
| 	h.Unmarshalers.Run(req) | ||||
| 
 | ||||
| 	return req.Error | ||||
| } | ||||
| 
 | ||||
| // PayloadMarshaler provides the interface for marshaling a SDK shape into and
 | ||||
| // io.Writer.
 | ||||
| type PayloadMarshaler interface { | ||||
| 	MarshalPayload(io.Writer, interface{}) error | ||||
| } | ||||
| 
 | ||||
| // HandlerPayloadMarshal implements the PayloadMarshaler from a HandlerList.
 | ||||
| // This provides support for marshaling a SDK shape into an io.Writer without
 | ||||
| // needing a SDK request first.
 | ||||
| type HandlerPayloadMarshal struct { | ||||
| 	Marshalers request.HandlerList | ||||
| } | ||||
| 
 | ||||
| // MarshalPayload marshals the SDK shape into the io.Writer using the
 | ||||
| // Marshalers HandlerList provided. Returns an error if unable if marshal
 | ||||
| // fails.
 | ||||
| func (h HandlerPayloadMarshal) MarshalPayload(w io.Writer, v interface{}) error { | ||||
| 	req := request.New( | ||||
| 		aws.Config{}, | ||||
| 		metadata.ClientInfo{}, | ||||
| 		request.Handlers{}, | ||||
| 		nil, | ||||
| 		&request.Operation{HTTPMethod: "GET"}, | ||||
| 		v, | ||||
| 		nil, | ||||
| 	) | ||||
| 
 | ||||
| 	h.Marshalers.Run(req) | ||||
| 
 | ||||
| 	if req.Error != nil { | ||||
| 		return req.Error | ||||
| 	} | ||||
| 
 | ||||
| 	io.Copy(w, req.GetBody()) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | @ -25,7 +25,7 @@ func Build(r *request.Request) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if r.ExpireTime == 0 { | ||||
| 	if !r.IsPresigned() { | ||||
| 		r.HTTPRequest.Method = "POST" | ||||
| 		r.HTTPRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8") | ||||
| 		r.SetBufferBody([]byte(body.Encode())) | ||||
|  |  | |||
|  | @ -233,7 +233,12 @@ func (q *queryParser) parseScalar(v url.Values, r reflect.Value, name string, ta | |||
| 		v.Set(name, strconv.FormatFloat(float64(value), 'f', -1, 32)) | ||||
| 	case time.Time: | ||||
| 		const ISO8601UTC = "2006-01-02T15:04:05Z" | ||||
| 		v.Set(name, value.UTC().Format(ISO8601UTC)) | ||||
| 		format := tag.Get("timestampFormat") | ||||
| 		if len(format) == 0 { | ||||
| 			format = protocol.ISO8601TimeFormatName | ||||
| 		} | ||||
| 
 | ||||
| 		v.Set(name, protocol.FormatTime(format, value)) | ||||
| 	default: | ||||
| 		return fmt.Errorf("unsupported value for param %s: %v (%s)", name, r.Interface(), r.Type().Name()) | ||||
| 	} | ||||
|  |  | |||
|  | @ -20,9 +20,6 @@ import ( | |||
| 	"github.com/aws/aws-sdk-go/private/protocol" | ||||
| ) | ||||
| 
 | ||||
| // RFC822 returns an RFC822 formatted timestamp for AWS protocols
 | ||||
| const RFC822 = "Mon, 2 Jan 2006 15:04:05 GMT" | ||||
| 
 | ||||
| // Whether the byte value can be sent without escaping in AWS URLs
 | ||||
| var noEscape [256]bool | ||||
| 
 | ||||
|  | @ -270,7 +267,14 @@ func convertType(v reflect.Value, tag reflect.StructTag) (str string, err error) | |||
| 	case float64: | ||||
| 		str = strconv.FormatFloat(value, 'f', -1, 64) | ||||
| 	case time.Time: | ||||
| 		str = value.UTC().Format(RFC822) | ||||
| 		format := tag.Get("timestampFormat") | ||||
| 		if len(format) == 0 { | ||||
| 			format = protocol.RFC822TimeFormatName | ||||
| 			if tag.Get("location") == "querystring" { | ||||
| 				format = protocol.ISO8601TimeFormatName | ||||
| 			} | ||||
| 		} | ||||
| 		str = protocol.FormatTime(format, value) | ||||
| 	case aws.JSONValue: | ||||
| 		if len(value) == 0 { | ||||
| 			return "", errValueNotSet | ||||
|  |  | |||
|  | @ -198,7 +198,11 @@ func unmarshalHeader(v reflect.Value, header string, tag reflect.StructTag) erro | |||
| 		} | ||||
| 		v.Set(reflect.ValueOf(&f)) | ||||
| 	case *time.Time: | ||||
| 		t, err := time.Parse(RFC822, header) | ||||
| 		format := tag.Get("timestampFormat") | ||||
| 		if len(format) == 0 { | ||||
| 			format = protocol.RFC822TimeFormatName | ||||
| 		} | ||||
| 		t, err := protocol.ParseTime(format, header) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  |  | |||
|  | @ -0,0 +1,72 @@ | |||
| package protocol | ||||
| 
 | ||||
| import ( | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| // Names of time formats supported by the SDK
 | ||||
| const ( | ||||
| 	RFC822TimeFormatName  = "rfc822" | ||||
| 	ISO8601TimeFormatName = "iso8601" | ||||
| 	UnixTimeFormatName    = "unixTimestamp" | ||||
| ) | ||||
| 
 | ||||
| // Time formats supported by the SDK
 | ||||
| const ( | ||||
| 	// RFC 7231#section-7.1.1.1 timetamp format. e.g Tue, 29 Apr 2014 18:30:38 GMT
 | ||||
| 	RFC822TimeFormat = "Mon, 2 Jan 2006 15:04:05 GMT" | ||||
| 
 | ||||
| 	// RFC3339 a subset of the ISO8601 timestamp format. e.g 2014-04-29T18:30:38Z
 | ||||
| 	ISO8601TimeFormat = "2006-01-02T15:04:05Z" | ||||
| ) | ||||
| 
 | ||||
| // IsKnownTimestampFormat returns if the timestamp format name
 | ||||
| // is know to the SDK's protocols.
 | ||||
| func IsKnownTimestampFormat(name string) bool { | ||||
| 	switch name { | ||||
| 	case RFC822TimeFormatName: | ||||
| 		fallthrough | ||||
| 	case ISO8601TimeFormatName: | ||||
| 		fallthrough | ||||
| 	case UnixTimeFormatName: | ||||
| 		return true | ||||
| 	default: | ||||
| 		return false | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // FormatTime returns a string value of the time.
 | ||||
| func FormatTime(name string, t time.Time) string { | ||||
| 	t = t.UTC() | ||||
| 
 | ||||
| 	switch name { | ||||
| 	case RFC822TimeFormatName: | ||||
| 		return t.Format(RFC822TimeFormat) | ||||
| 	case ISO8601TimeFormatName: | ||||
| 		return t.Format(ISO8601TimeFormat) | ||||
| 	case UnixTimeFormatName: | ||||
| 		return strconv.FormatInt(t.Unix(), 10) | ||||
| 	default: | ||||
| 		panic("unknown timestamp format name, " + name) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ParseTime attempts to parse the time given the format. Returns
 | ||||
| // the time if it was able to be parsed, and fails otherwise.
 | ||||
| func ParseTime(formatName, value string) (time.Time, error) { | ||||
| 	switch formatName { | ||||
| 	case RFC822TimeFormatName: | ||||
| 		return time.Parse(RFC822TimeFormat, value) | ||||
| 	case ISO8601TimeFormatName: | ||||
| 		return time.Parse(ISO8601TimeFormat, value) | ||||
| 	case UnixTimeFormatName: | ||||
| 		v, err := strconv.ParseFloat(value, 64) | ||||
| 		if err != nil { | ||||
| 			return time.Time{}, err | ||||
| 		} | ||||
| 		return time.Unix(int64(v), 0), nil | ||||
| 	default: | ||||
| 		panic("unknown timestamp format name, " + formatName) | ||||
| 	} | ||||
| } | ||||
|  | @ -13,9 +13,13 @@ import ( | |||
| 	"github.com/aws/aws-sdk-go/private/protocol" | ||||
| ) | ||||
| 
 | ||||
| // BuildXML will serialize params into an xml.Encoder.
 | ||||
| // Error will be returned if the serialization of any of the params or nested values fails.
 | ||||
| // BuildXML will serialize params into an xml.Encoder. Error will be returned
 | ||||
| // if the serialization of any of the params or nested values fails.
 | ||||
| func BuildXML(params interface{}, e *xml.Encoder) error { | ||||
| 	return buildXML(params, e, false) | ||||
| } | ||||
| 
 | ||||
| func buildXML(params interface{}, e *xml.Encoder, sorted bool) error { | ||||
| 	b := xmlBuilder{encoder: e, namespaces: map[string]string{}} | ||||
| 	root := NewXMLElement(xml.Name{}) | ||||
| 	if err := b.buildValue(reflect.ValueOf(params), root, ""); err != nil { | ||||
|  | @ -23,7 +27,7 @@ func BuildXML(params interface{}, e *xml.Encoder) error { | |||
| 	} | ||||
| 	for _, c := range root.Children { | ||||
| 		for _, v := range c { | ||||
| 			return StructToXML(e, v, false) | ||||
| 			return StructToXML(e, v, sorted) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
|  | @ -90,8 +94,6 @@ func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag refl | |||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	fieldAdded := false | ||||
| 
 | ||||
| 	// unwrap payloads
 | ||||
| 	if payload := tag.Get("payload"); payload != "" { | ||||
| 		field, _ := value.Type().FieldByName(payload) | ||||
|  | @ -119,6 +121,8 @@ func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag refl | |||
| 		child.Attr = append(child.Attr, ns) | ||||
| 	} | ||||
| 
 | ||||
| 	var payloadFields, nonPayloadFields int | ||||
| 
 | ||||
| 	t := value.Type() | ||||
| 	for i := 0; i < value.NumField(); i++ { | ||||
| 		member := elemOf(value.Field(i)) | ||||
|  | @ -133,8 +137,10 @@ func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag refl | |||
| 
 | ||||
| 		mTag := field.Tag | ||||
| 		if mTag.Get("location") != "" { // skip non-body members
 | ||||
| 			nonPayloadFields++ | ||||
| 			continue | ||||
| 		} | ||||
| 		payloadFields++ | ||||
| 
 | ||||
| 		if protocol.CanSetIdempotencyToken(value.Field(i), field) { | ||||
| 			token := protocol.GetIdempotencyToken() | ||||
|  | @ -149,11 +155,11 @@ func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag refl | |||
| 		if err := b.buildValue(member, child, mTag); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		fieldAdded = true | ||||
| 	} | ||||
| 
 | ||||
| 	if fieldAdded { // only append this child if we have one ore more valid members
 | ||||
| 	// Only case where the child shape is not added is if the shape only contains
 | ||||
| 	// non-payload fields, e.g headers/query.
 | ||||
| 	if !(payloadFields == 0 && nonPayloadFields > 0) { | ||||
| 		current.AddChild(child) | ||||
| 	} | ||||
| 
 | ||||
|  | @ -278,8 +284,12 @@ func (b *xmlBuilder) buildScalar(value reflect.Value, current *XMLNode, tag refl | |||
| 	case float32: | ||||
| 		str = strconv.FormatFloat(float64(converted), 'f', -1, 32) | ||||
| 	case time.Time: | ||||
| 		const ISO8601UTC = "2006-01-02T15:04:05Z" | ||||
| 		str = converted.UTC().Format(ISO8601UTC) | ||||
| 		format := tag.Get("timestampFormat") | ||||
| 		if len(format) == 0 { | ||||
| 			format = protocol.ISO8601TimeFormatName | ||||
| 		} | ||||
| 
 | ||||
| 		str = protocol.FormatTime(format, converted) | ||||
| 	default: | ||||
| 		return fmt.Errorf("unsupported value for param %s: %v (%s)", | ||||
| 			tag.Get("locationName"), value.Interface(), value.Type().Name()) | ||||
|  |  | |||
|  | @ -9,6 +9,8 @@ import ( | |||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/private/protocol" | ||||
| ) | ||||
| 
 | ||||
| // UnmarshalXML deserializes an xml.Decoder into the container v. V
 | ||||
|  | @ -52,9 +54,15 @@ func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { | |||
| 	if t == "" { | ||||
| 		switch rtype.Kind() { | ||||
| 		case reflect.Struct: | ||||
| 			t = "structure" | ||||
| 			// also it can't be a time object
 | ||||
| 			if _, ok := r.Interface().(*time.Time); !ok { | ||||
| 				t = "structure" | ||||
| 			} | ||||
| 		case reflect.Slice: | ||||
| 			t = "list" | ||||
| 			// also it can't be a byte slice
 | ||||
| 			if _, ok := r.Interface().([]byte); !ok { | ||||
| 				t = "list" | ||||
| 			} | ||||
| 		case reflect.Map: | ||||
| 			t = "map" | ||||
| 		} | ||||
|  | @ -247,8 +255,12 @@ func parseScalar(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { | |||
| 		} | ||||
| 		r.Set(reflect.ValueOf(&v)) | ||||
| 	case *time.Time: | ||||
| 		const ISO8601UTC = "2006-01-02T15:04:05Z" | ||||
| 		t, err := time.Parse(ISO8601UTC, node.Text) | ||||
| 		format := tag.Get("timestampFormat") | ||||
| 		if len(format) == 0 { | ||||
| 			format = protocol.ISO8601TimeFormatName | ||||
| 		} | ||||
| 
 | ||||
| 		t, err := protocol.ParseTime(format, node.Text) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ func NewXMLElement(name xml.Name) *XMLNode { | |||
| 
 | ||||
| // AddChild adds child to the XMLNode.
 | ||||
| func (n *XMLNode) AddChild(child *XMLNode) { | ||||
| 	child.parent = n | ||||
| 	if _, ok := n.Children[child.Name.Local]; !ok { | ||||
| 		n.Children[child.Name.Local] = []*XMLNode{} | ||||
| 	} | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,249 @@ | |||
| package s3 | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto/md5" | ||||
| 	"crypto/sha256" | ||||
| 	"encoding/base64" | ||||
| 	"encoding/hex" | ||||
| 	"fmt" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/aws" | ||||
| 	"github.com/aws/aws-sdk-go/aws/awserr" | ||||
| 	"github.com/aws/aws-sdk-go/aws/request" | ||||
| 	"github.com/aws/aws-sdk-go/internal/sdkio" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	contentMD5Header    = "Content-Md5" | ||||
| 	contentSha256Header = "X-Amz-Content-Sha256" | ||||
| 	amzTeHeader         = "X-Amz-Te" | ||||
| 	amzTxEncodingHeader = "X-Amz-Transfer-Encoding" | ||||
| 
 | ||||
| 	appendMD5TxEncoding = "append-md5" | ||||
| ) | ||||
| 
 | ||||
| // contentMD5 computes and sets the HTTP Content-MD5 header for requests that
 | ||||
| // require it.
 | ||||
| func contentMD5(r *request.Request) { | ||||
| 	h := md5.New() | ||||
| 
 | ||||
| 	if !aws.IsReaderSeekable(r.Body) { | ||||
| 		if r.Config.Logger != nil { | ||||
| 			r.Config.Logger.Log(fmt.Sprintf( | ||||
| 				"Unable to compute Content-MD5 for unseekable body, S3.%s", | ||||
| 				r.Operation.Name)) | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if _, err := copySeekableBody(h, r.Body); err != nil { | ||||
| 		r.Error = awserr.New("ContentMD5", "failed to compute body MD5", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// encode the md5 checksum in base64 and set the request header.
 | ||||
| 	v := base64.StdEncoding.EncodeToString(h.Sum(nil)) | ||||
| 	r.HTTPRequest.Header.Set(contentMD5Header, v) | ||||
| } | ||||
| 
 | ||||
| // computeBodyHashes will add Content MD5 and Content Sha256 hashes to the
 | ||||
| // request. If the body is not seekable or S3DisableContentMD5Validation set
 | ||||
| // this handler will be ignored.
 | ||||
| func computeBodyHashes(r *request.Request) { | ||||
| 	if aws.BoolValue(r.Config.S3DisableContentMD5Validation) { | ||||
| 		return | ||||
| 	} | ||||
| 	if r.IsPresigned() { | ||||
| 		return | ||||
| 	} | ||||
| 	if r.Error != nil || !aws.IsReaderSeekable(r.Body) { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	var md5Hash, sha256Hash hash.Hash | ||||
| 	hashers := make([]io.Writer, 0, 2) | ||||
| 
 | ||||
| 	// Determine upfront which hashes can be set without overriding user
 | ||||
| 	// provide header data.
 | ||||
| 	if v := r.HTTPRequest.Header.Get(contentMD5Header); len(v) == 0 { | ||||
| 		md5Hash = md5.New() | ||||
| 		hashers = append(hashers, md5Hash) | ||||
| 	} | ||||
| 
 | ||||
| 	if v := r.HTTPRequest.Header.Get(contentSha256Header); len(v) == 0 { | ||||
| 		sha256Hash = sha256.New() | ||||
| 		hashers = append(hashers, sha256Hash) | ||||
| 	} | ||||
| 
 | ||||
| 	// Create the destination writer based on the hashes that are not already
 | ||||
| 	// provided by the user.
 | ||||
| 	var dst io.Writer | ||||
| 	switch len(hashers) { | ||||
| 	case 0: | ||||
| 		return | ||||
| 	case 1: | ||||
| 		dst = hashers[0] | ||||
| 	default: | ||||
| 		dst = io.MultiWriter(hashers...) | ||||
| 	} | ||||
| 
 | ||||
| 	if _, err := copySeekableBody(dst, r.Body); err != nil { | ||||
| 		r.Error = awserr.New("BodyHashError", "failed to compute body hashes", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// For the hashes created, set the associated headers that the user did not
 | ||||
| 	// already provide.
 | ||||
| 	if md5Hash != nil { | ||||
| 		sum := make([]byte, md5.Size) | ||||
| 		encoded := make([]byte, md5Base64EncLen) | ||||
| 
 | ||||
| 		base64.StdEncoding.Encode(encoded, md5Hash.Sum(sum[0:0])) | ||||
| 		r.HTTPRequest.Header[contentMD5Header] = []string{string(encoded)} | ||||
| 	} | ||||
| 
 | ||||
| 	if sha256Hash != nil { | ||||
| 		encoded := make([]byte, sha256HexEncLen) | ||||
| 		sum := make([]byte, sha256.Size) | ||||
| 
 | ||||
| 		hex.Encode(encoded, sha256Hash.Sum(sum[0:0])) | ||||
| 		r.HTTPRequest.Header[contentSha256Header] = []string{string(encoded)} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| const ( | ||||
| 	md5Base64EncLen = (md5.Size + 2) / 3 * 4 // base64.StdEncoding.EncodedLen
 | ||||
| 	sha256HexEncLen = sha256.Size * 2        // hex.EncodedLen
 | ||||
| ) | ||||
| 
 | ||||
| func copySeekableBody(dst io.Writer, src io.ReadSeeker) (int64, error) { | ||||
| 	curPos, err := src.Seek(0, sdkio.SeekCurrent) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	// hash the body.  seek back to the first position after reading to reset
 | ||||
| 	// the body for transmission.  copy errors may be assumed to be from the
 | ||||
| 	// body.
 | ||||
| 	n, err := io.Copy(dst, src) | ||||
| 	if err != nil { | ||||
| 		return n, err | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = src.Seek(curPos, sdkio.SeekStart) | ||||
| 	if err != nil { | ||||
| 		return n, err | ||||
| 	} | ||||
| 
 | ||||
| 	return n, nil | ||||
| } | ||||
| 
 | ||||
| // Adds the x-amz-te: append_md5 header to the request. This requests the service
 | ||||
| // responds with a trailing MD5 checksum.
 | ||||
| //
 | ||||
| // Will not ask for append MD5 if disabled, the request is presigned or,
 | ||||
| // or the API operation does not support content MD5 validation.
 | ||||
| func askForTxEncodingAppendMD5(r *request.Request) { | ||||
| 	if aws.BoolValue(r.Config.S3DisableContentMD5Validation) { | ||||
| 		return | ||||
| 	} | ||||
| 	if r.IsPresigned() { | ||||
| 		return | ||||
| 	} | ||||
| 	r.HTTPRequest.Header.Set(amzTeHeader, appendMD5TxEncoding) | ||||
| } | ||||
| 
 | ||||
| func useMD5ValidationReader(r *request.Request) { | ||||
| 	if r.Error != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if v := r.HTTPResponse.Header.Get(amzTxEncodingHeader); v != appendMD5TxEncoding { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	var bodyReader *io.ReadCloser | ||||
| 	var contentLen int64 | ||||
| 	switch tv := r.Data.(type) { | ||||
| 	case *GetObjectOutput: | ||||
| 		bodyReader = &tv.Body | ||||
| 		contentLen = aws.Int64Value(tv.ContentLength) | ||||
| 		// Update ContentLength hiden the trailing MD5 checksum.
 | ||||
| 		tv.ContentLength = aws.Int64(contentLen - md5.Size) | ||||
| 		tv.ContentRange = aws.String(r.HTTPResponse.Header.Get("X-Amz-Content-Range")) | ||||
| 	default: | ||||
| 		r.Error = awserr.New("ChecksumValidationError", | ||||
| 			fmt.Sprintf("%s: %s header received on unsupported API, %s", | ||||
| 				amzTxEncodingHeader, appendMD5TxEncoding, r.Operation.Name, | ||||
| 			), nil) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if contentLen < md5.Size { | ||||
| 		r.Error = awserr.New("ChecksumValidationError", | ||||
| 			fmt.Sprintf("invalid Content-Length %d for %s %s", | ||||
| 				contentLen, appendMD5TxEncoding, amzTxEncodingHeader, | ||||
| 			), nil) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// Wrap and swap the response body reader with the validation reader.
 | ||||
| 	*bodyReader = newMD5ValidationReader(*bodyReader, contentLen-md5.Size) | ||||
| } | ||||
| 
 | ||||
| type md5ValidationReader struct { | ||||
| 	rawReader io.ReadCloser | ||||
| 	payload   io.Reader | ||||
| 	hash      hash.Hash | ||||
| 
 | ||||
| 	payloadLen int64 | ||||
| 	read       int64 | ||||
| } | ||||
| 
 | ||||
| func newMD5ValidationReader(reader io.ReadCloser, payloadLen int64) *md5ValidationReader { | ||||
| 	h := md5.New() | ||||
| 	return &md5ValidationReader{ | ||||
| 		rawReader:  reader, | ||||
| 		payload:    io.TeeReader(&io.LimitedReader{R: reader, N: payloadLen}, h), | ||||
| 		hash:       h, | ||||
| 		payloadLen: payloadLen, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (v *md5ValidationReader) Read(p []byte) (n int, err error) { | ||||
| 	n, err = v.payload.Read(p) | ||||
| 	if err != nil && err != io.EOF { | ||||
| 		return n, err | ||||
| 	} | ||||
| 
 | ||||
| 	v.read += int64(n) | ||||
| 
 | ||||
| 	if err == io.EOF { | ||||
| 		if v.read != v.payloadLen { | ||||
| 			return n, io.ErrUnexpectedEOF | ||||
| 		} | ||||
| 		expectSum := make([]byte, md5.Size) | ||||
| 		actualSum := make([]byte, md5.Size) | ||||
| 		if _, sumReadErr := io.ReadFull(v.rawReader, expectSum); sumReadErr != nil { | ||||
| 			return n, sumReadErr | ||||
| 		} | ||||
| 		actualSum = v.hash.Sum(actualSum[0:0]) | ||||
| 		if !bytes.Equal(expectSum, actualSum) { | ||||
| 			return n, awserr.New("InvalidChecksum", | ||||
| 				fmt.Sprintf("expected MD5 checksum %s, got %s", | ||||
| 					hex.EncodeToString(expectSum), | ||||
| 					hex.EncodeToString(actualSum), | ||||
| 				), | ||||
| 				nil) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return n, err | ||||
| } | ||||
| 
 | ||||
| func (v *md5ValidationReader) Close() error { | ||||
| 	return v.rawReader.Close() | ||||
| } | ||||
|  | @ -1,36 +0,0 @@ | |||
| package s3 | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/md5" | ||||
| 	"encoding/base64" | ||||
| 	"io" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/aws/awserr" | ||||
| 	"github.com/aws/aws-sdk-go/aws/request" | ||||
| ) | ||||
| 
 | ||||
| // contentMD5 computes and sets the HTTP Content-MD5 header for requests that
 | ||||
| // require it.
 | ||||
| func contentMD5(r *request.Request) { | ||||
| 	h := md5.New() | ||||
| 
 | ||||
| 	// hash the body.  seek back to the first position after reading to reset
 | ||||
| 	// the body for transmission.  copy errors may be assumed to be from the
 | ||||
| 	// body.
 | ||||
| 	_, err := io.Copy(h, r.Body) | ||||
| 	if err != nil { | ||||
| 		r.Error = awserr.New("ContentMD5", "failed to read body", err) | ||||
| 		return | ||||
| 	} | ||||
| 	_, err = r.Body.Seek(0, 0) | ||||
| 	if err != nil { | ||||
| 		r.Error = awserr.New("ContentMD5", "failed to seek body", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// encode the md5 checksum in base64 and set the request header.
 | ||||
| 	sum := h.Sum(nil) | ||||
| 	sum64 := make([]byte, base64.StdEncoding.EncodedLen(len(sum))) | ||||
| 	base64.StdEncoding.Encode(sum64, sum) | ||||
| 	r.HTTPRequest.Header.Set("Content-MD5", string(sum64)) | ||||
| } | ||||
|  | @ -42,6 +42,12 @@ func defaultInitRequestFn(r *request.Request) { | |||
| 		r.Handlers.Validate.PushFront(populateLocationConstraint) | ||||
| 	case opCopyObject, opUploadPartCopy, opCompleteMultipartUpload: | ||||
| 		r.Handlers.Unmarshal.PushFront(copyMultipartStatusOKUnmarhsalError) | ||||
| 	case opPutObject, opUploadPart: | ||||
| 		r.Handlers.Build.PushBack(computeBodyHashes) | ||||
| 		// Disabled until #1837 root issue is resolved.
 | ||||
| 		//	case opGetObject:
 | ||||
| 		//		r.Handlers.Build.PushBack(askForTxEncodingAppendMD5)
 | ||||
| 		//		r.Handlers.Unmarshal.PushBack(useMD5ValidationReader)
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -29,8 +29,9 @@ var initRequest func(*request.Request) | |||
| 
 | ||||
| // Service information constants
 | ||||
| const ( | ||||
| 	ServiceName = "s3"        // Service endpoint prefix API calls made to.
 | ||||
| 	EndpointsID = ServiceName // Service ID for Regions and Endpoints metadata.
 | ||||
| 	ServiceName = "s3"        // Name of service.
 | ||||
| 	EndpointsID = ServiceName // ID to lookup a service endpoint with.
 | ||||
| 	ServiceID   = "S3"        // ServiceID is a unique identifer of a specific service.
 | ||||
| ) | ||||
| 
 | ||||
| // New creates a new instance of the S3 client with a session.
 | ||||
|  | @ -55,6 +56,7 @@ func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio | |||
| 			cfg, | ||||
| 			metadata.ClientInfo{ | ||||
| 				ServiceName:   ServiceName, | ||||
| 				ServiceID:     ServiceID, | ||||
| 				SigningName:   signingName, | ||||
| 				SigningRegion: signingRegion, | ||||
| 				Endpoint:      endpoint, | ||||
|  | @ -71,6 +73,8 @@ func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio | |||
| 	svc.Handlers.UnmarshalMeta.PushBackNamed(restxml.UnmarshalMetaHandler) | ||||
| 	svc.Handlers.UnmarshalError.PushBackNamed(restxml.UnmarshalErrorHandler) | ||||
| 
 | ||||
| 	svc.Handlers.UnmarshalStream.PushBackNamed(restxml.UnmarshalHandler) | ||||
| 
 | ||||
| 	// Run custom client initialization if present
 | ||||
| 	if initClient != nil { | ||||
| 		initClient(svc.Client) | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ import ( | |||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/aws/awserr" | ||||
| 	"github.com/aws/aws-sdk-go/aws/request" | ||||
| 	"github.com/aws/aws-sdk-go/internal/sdkio" | ||||
| ) | ||||
| 
 | ||||
| func copyMultipartStatusOKUnmarhsalError(r *request.Request) { | ||||
|  | @ -17,7 +18,7 @@ func copyMultipartStatusOKUnmarhsalError(r *request.Request) { | |||
| 	} | ||||
| 	body := bytes.NewReader(b) | ||||
| 	r.HTTPResponse.Body = ioutil.NopCloser(body) | ||||
| 	defer body.Seek(0, 0) | ||||
| 	defer body.Seek(0, sdkio.SeekStart) | ||||
| 
 | ||||
| 	if body.Len() == 0 { | ||||
| 		// If there is no body don't attempt to parse the body.
 | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ const opAssumeRole = "AssumeRole" | |||
| 
 | ||||
| // AssumeRoleRequest generates a "aws/request.Request" representing the
 | ||||
| // client's request for the AssumeRole operation. The "output" return
 | ||||
| // value will be populated with the request's response once the request complets
 | ||||
| // value will be populated with the request's response once the request completes
 | ||||
| // successfuly.
 | ||||
| //
 | ||||
| // Use "Send" method on the returned Request to send the API call to the service.
 | ||||
|  | @ -35,7 +35,7 @@ const opAssumeRole = "AssumeRole" | |||
| //        fmt.Println(resp)
 | ||||
| //    }
 | ||||
| //
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRole
 | ||||
| // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRole
 | ||||
| func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, output *AssumeRoleOutput) { | ||||
| 	op := &request.Operation{ | ||||
| 		Name:       opAssumeRole, | ||||
|  | @ -88,9 +88,18 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o | |||
| // Scenarios for Temporary Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html#sts-introduction)
 | ||||
| // in the IAM User Guide.
 | ||||
| //
 | ||||
| // The temporary security credentials are valid for the duration that you specified
 | ||||
| // when calling AssumeRole, which can be from 900 seconds (15 minutes) to a
 | ||||
| // maximum of 3600 seconds (1 hour). The default is 1 hour.
 | ||||
| // By default, the temporary security credentials created by AssumeRole last
 | ||||
| // for one hour. However, you can use the optional DurationSeconds parameter
 | ||||
| // to specify the duration of your session. You can provide a value from 900
 | ||||
| // seconds (15 minutes) up to the maximum session duration setting for the role.
 | ||||
| // This setting can have a value from 1 hour to 12 hours. To learn how to view
 | ||||
| // the maximum value for your role, see View the Maximum Session Duration Setting
 | ||||
| // for a Role (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session)
 | ||||
| // in the IAM User Guide. The maximum session duration limit applies when you
 | ||||
| // use the AssumeRole* API operations or the assume-role* CLI operations but
 | ||||
| // does not apply when you use those operations to create a console URL. For
 | ||||
| // more information, see Using IAM Roles (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html)
 | ||||
| // in the IAM User Guide.
 | ||||
| //
 | ||||
| // The temporary security credentials created by AssumeRole can be used to make
 | ||||
| // API calls to any AWS service with the following exception: you cannot call
 | ||||
|  | @ -121,7 +130,12 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o | |||
| // the user to call AssumeRole on the ARN of the role in the other account.
 | ||||
| // If the user is in the same account as the role, then you can either attach
 | ||||
| // a policy to the user (identical to the previous different account user),
 | ||||
| // or you can add the user as a principal directly in the role's trust policy
 | ||||
| // or you can add the user as a principal directly in the role's trust policy.
 | ||||
| // In this case, the trust policy acts as the only resource-based policy in
 | ||||
| // IAM, and users in the same account as the role do not need explicit permission
 | ||||
| // to assume the role. For more information about trust policies and resource-based
 | ||||
| // policies, see IAM Policies (http://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html)
 | ||||
| // in the IAM User Guide.
 | ||||
| //
 | ||||
| // Using MFA with AssumeRole
 | ||||
| //
 | ||||
|  | @ -168,7 +182,7 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o | |||
| //   and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
 | ||||
| //   in the IAM User Guide.
 | ||||
| //
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRole
 | ||||
| // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRole
 | ||||
| func (c *STS) AssumeRole(input *AssumeRoleInput) (*AssumeRoleOutput, error) { | ||||
| 	req, out := c.AssumeRoleRequest(input) | ||||
| 	return out, req.Send() | ||||
|  | @ -194,7 +208,7 @@ const opAssumeRoleWithSAML = "AssumeRoleWithSAML" | |||
| 
 | ||||
| // AssumeRoleWithSAMLRequest generates a "aws/request.Request" representing the
 | ||||
| // client's request for the AssumeRoleWithSAML operation. The "output" return
 | ||||
| // value will be populated with the request's response once the request complets
 | ||||
| // value will be populated with the request's response once the request completes
 | ||||
| // successfuly.
 | ||||
| //
 | ||||
| // Use "Send" method on the returned Request to send the API call to the service.
 | ||||
|  | @ -215,7 +229,7 @@ const opAssumeRoleWithSAML = "AssumeRoleWithSAML" | |||
| //        fmt.Println(resp)
 | ||||
| //    }
 | ||||
| //
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAML
 | ||||
| // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAML
 | ||||
| func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *request.Request, output *AssumeRoleWithSAMLOutput) { | ||||
| 	op := &request.Operation{ | ||||
| 		Name:       opAssumeRoleWithSAML, | ||||
|  | @ -247,11 +261,20 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re | |||
| // an access key ID, a secret access key, and a security token. Applications
 | ||||
| // can use these temporary security credentials to sign calls to AWS services.
 | ||||
| //
 | ||||
| // The temporary security credentials are valid for the duration that you specified
 | ||||
| // when calling AssumeRole, or until the time specified in the SAML authentication
 | ||||
| // response's SessionNotOnOrAfter value, whichever is shorter. The duration
 | ||||
| // can be from 900 seconds (15 minutes) to a maximum of 3600 seconds (1 hour).
 | ||||
| // The default is 1 hour.
 | ||||
| // By default, the temporary security credentials created by AssumeRoleWithSAML
 | ||||
| // last for one hour. However, you can use the optional DurationSeconds parameter
 | ||||
| // to specify the duration of your session. Your role session lasts for the
 | ||||
| // duration that you specify, or until the time specified in the SAML authentication
 | ||||
| // response's SessionNotOnOrAfter value, whichever is shorter. You can provide
 | ||||
| // a DurationSeconds value from 900 seconds (15 minutes) up to the maximum session
 | ||||
| // duration setting for the role. This setting can have a value from 1 hour
 | ||||
| // to 12 hours. To learn how to view the maximum value for your role, see View
 | ||||
| // the Maximum Session Duration Setting for a Role (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session)
 | ||||
| // in the IAM User Guide. The maximum session duration limit applies when you
 | ||||
| // use the AssumeRole* API operations or the assume-role* CLI operations but
 | ||||
| // does not apply when you use those operations to create a console URL. For
 | ||||
| // more information, see Using IAM Roles (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html)
 | ||||
| // in the IAM User Guide.
 | ||||
| //
 | ||||
| // The temporary security credentials created by AssumeRoleWithSAML can be used
 | ||||
| // to make API calls to any AWS service with the following exception: you cannot
 | ||||
|  | @ -341,7 +364,7 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re | |||
| //   and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
 | ||||
| //   in the IAM User Guide.
 | ||||
| //
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAML
 | ||||
| // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAML
 | ||||
| func (c *STS) AssumeRoleWithSAML(input *AssumeRoleWithSAMLInput) (*AssumeRoleWithSAMLOutput, error) { | ||||
| 	req, out := c.AssumeRoleWithSAMLRequest(input) | ||||
| 	return out, req.Send() | ||||
|  | @ -367,7 +390,7 @@ const opAssumeRoleWithWebIdentity = "AssumeRoleWithWebIdentity" | |||
| 
 | ||||
| // AssumeRoleWithWebIdentityRequest generates a "aws/request.Request" representing the
 | ||||
| // client's request for the AssumeRoleWithWebIdentity operation. The "output" return
 | ||||
| // value will be populated with the request's response once the request complets
 | ||||
| // value will be populated with the request's response once the request completes
 | ||||
| // successfuly.
 | ||||
| //
 | ||||
| // Use "Send" method on the returned Request to send the API call to the service.
 | ||||
|  | @ -388,7 +411,7 @@ const opAssumeRoleWithWebIdentity = "AssumeRoleWithWebIdentity" | |||
| //        fmt.Println(resp)
 | ||||
| //    }
 | ||||
| //
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentity
 | ||||
| // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentity
 | ||||
| func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityInput) (req *request.Request, output *AssumeRoleWithWebIdentityOutput) { | ||||
| 	op := &request.Operation{ | ||||
| 		Name:       opAssumeRoleWithWebIdentity, | ||||
|  | @ -438,9 +461,18 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI | |||
| // key ID, a secret access key, and a security token. Applications can use these
 | ||||
| // temporary security credentials to sign calls to AWS service APIs.
 | ||||
| //
 | ||||
| // The credentials are valid for the duration that you specified when calling
 | ||||
| // AssumeRoleWithWebIdentity, which can be from 900 seconds (15 minutes) to
 | ||||
| // a maximum of 3600 seconds (1 hour). The default is 1 hour.
 | ||||
| // By default, the temporary security credentials created by AssumeRoleWithWebIdentity
 | ||||
| // last for one hour. However, you can use the optional DurationSeconds parameter
 | ||||
| // to specify the duration of your session. You can provide a value from 900
 | ||||
| // seconds (15 minutes) up to the maximum session duration setting for the role.
 | ||||
| // This setting can have a value from 1 hour to 12 hours. To learn how to view
 | ||||
| // the maximum value for your role, see View the Maximum Session Duration Setting
 | ||||
| // for a Role (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session)
 | ||||
| // in the IAM User Guide. The maximum session duration limit applies when you
 | ||||
| // use the AssumeRole* API operations or the assume-role* CLI operations but
 | ||||
| // does not apply when you use those operations to create a console URL. For
 | ||||
| // more information, see Using IAM Roles (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html)
 | ||||
| // in the IAM User Guide.
 | ||||
| //
 | ||||
| // The temporary security credentials created by AssumeRoleWithWebIdentity can
 | ||||
| // be used to make API calls to any AWS service with the following exception:
 | ||||
|  | @ -492,7 +524,7 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI | |||
| //    the information from these providers to get and use temporary security
 | ||||
| //    credentials.
 | ||||
| //
 | ||||
| //    * Web Identity Federation with Mobile Applications (http://aws.amazon.com/articles/4617974389850313).
 | ||||
| //    * Web Identity Federation with Mobile Applications (http://aws.amazon.com/articles/web-identity-federation-with-mobile-applications).
 | ||||
| //    This article discusses web identity federation and shows an example of
 | ||||
| //    how to use web identity federation to get access to content in Amazon
 | ||||
| //    S3.
 | ||||
|  | @ -543,7 +575,7 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI | |||
| //   and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
 | ||||
| //   in the IAM User Guide.
 | ||||
| //
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentity
 | ||||
| // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentity
 | ||||
| func (c *STS) AssumeRoleWithWebIdentity(input *AssumeRoleWithWebIdentityInput) (*AssumeRoleWithWebIdentityOutput, error) { | ||||
| 	req, out := c.AssumeRoleWithWebIdentityRequest(input) | ||||
| 	return out, req.Send() | ||||
|  | @ -569,7 +601,7 @@ const opDecodeAuthorizationMessage = "DecodeAuthorizationMessage" | |||
| 
 | ||||
| // DecodeAuthorizationMessageRequest generates a "aws/request.Request" representing the
 | ||||
| // client's request for the DecodeAuthorizationMessage operation. The "output" return
 | ||||
| // value will be populated with the request's response once the request complets
 | ||||
| // value will be populated with the request's response once the request completes
 | ||||
| // successfuly.
 | ||||
| //
 | ||||
| // Use "Send" method on the returned Request to send the API call to the service.
 | ||||
|  | @ -590,7 +622,7 @@ const opDecodeAuthorizationMessage = "DecodeAuthorizationMessage" | |||
| //        fmt.Println(resp)
 | ||||
| //    }
 | ||||
| //
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessage
 | ||||
| // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessage
 | ||||
| func (c *STS) DecodeAuthorizationMessageRequest(input *DecodeAuthorizationMessageInput) (req *request.Request, output *DecodeAuthorizationMessageOutput) { | ||||
| 	op := &request.Operation{ | ||||
| 		Name:       opDecodeAuthorizationMessage, | ||||
|  | @ -655,7 +687,7 @@ func (c *STS) DecodeAuthorizationMessageRequest(input *DecodeAuthorizationMessag | |||
| //   invalid. This can happen if the token contains invalid characters, such as
 | ||||
| //   linebreaks.
 | ||||
| //
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessage
 | ||||
| // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessage
 | ||||
| func (c *STS) DecodeAuthorizationMessage(input *DecodeAuthorizationMessageInput) (*DecodeAuthorizationMessageOutput, error) { | ||||
| 	req, out := c.DecodeAuthorizationMessageRequest(input) | ||||
| 	return out, req.Send() | ||||
|  | @ -681,7 +713,7 @@ const opGetCallerIdentity = "GetCallerIdentity" | |||
| 
 | ||||
| // GetCallerIdentityRequest generates a "aws/request.Request" representing the
 | ||||
| // client's request for the GetCallerIdentity operation. The "output" return
 | ||||
| // value will be populated with the request's response once the request complets
 | ||||
| // value will be populated with the request's response once the request completes
 | ||||
| // successfuly.
 | ||||
| //
 | ||||
| // Use "Send" method on the returned Request to send the API call to the service.
 | ||||
|  | @ -702,7 +734,7 @@ const opGetCallerIdentity = "GetCallerIdentity" | |||
| //        fmt.Println(resp)
 | ||||
| //    }
 | ||||
| //
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentity
 | ||||
| // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentity
 | ||||
| func (c *STS) GetCallerIdentityRequest(input *GetCallerIdentityInput) (req *request.Request, output *GetCallerIdentityOutput) { | ||||
| 	op := &request.Operation{ | ||||
| 		Name:       opGetCallerIdentity, | ||||
|  | @ -730,7 +762,7 @@ func (c *STS) GetCallerIdentityRequest(input *GetCallerIdentityInput) (req *requ | |||
| //
 | ||||
| // See the AWS API reference guide for AWS Security Token Service's
 | ||||
| // API operation GetCallerIdentity for usage and error information.
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentity
 | ||||
| // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentity
 | ||||
| func (c *STS) GetCallerIdentity(input *GetCallerIdentityInput) (*GetCallerIdentityOutput, error) { | ||||
| 	req, out := c.GetCallerIdentityRequest(input) | ||||
| 	return out, req.Send() | ||||
|  | @ -756,7 +788,7 @@ const opGetFederationToken = "GetFederationToken" | |||
| 
 | ||||
| // GetFederationTokenRequest generates a "aws/request.Request" representing the
 | ||||
| // client's request for the GetFederationToken operation. The "output" return
 | ||||
| // value will be populated with the request's response once the request complets
 | ||||
| // value will be populated with the request's response once the request completes
 | ||||
| // successfuly.
 | ||||
| //
 | ||||
| // Use "Send" method on the returned Request to send the API call to the service.
 | ||||
|  | @ -777,7 +809,7 @@ const opGetFederationToken = "GetFederationToken" | |||
| //        fmt.Println(resp)
 | ||||
| //    }
 | ||||
| //
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationToken
 | ||||
| // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationToken
 | ||||
| func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *request.Request, output *GetFederationTokenOutput) { | ||||
| 	op := &request.Operation{ | ||||
| 		Name:       opGetFederationToken, | ||||
|  | @ -899,7 +931,7 @@ func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *re | |||
| //   and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
 | ||||
| //   in the IAM User Guide.
 | ||||
| //
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationToken
 | ||||
| // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationToken
 | ||||
| func (c *STS) GetFederationToken(input *GetFederationTokenInput) (*GetFederationTokenOutput, error) { | ||||
| 	req, out := c.GetFederationTokenRequest(input) | ||||
| 	return out, req.Send() | ||||
|  | @ -925,7 +957,7 @@ const opGetSessionToken = "GetSessionToken" | |||
| 
 | ||||
| // GetSessionTokenRequest generates a "aws/request.Request" representing the
 | ||||
| // client's request for the GetSessionToken operation. The "output" return
 | ||||
| // value will be populated with the request's response once the request complets
 | ||||
| // value will be populated with the request's response once the request completes
 | ||||
| // successfuly.
 | ||||
| //
 | ||||
| // Use "Send" method on the returned Request to send the API call to the service.
 | ||||
|  | @ -946,7 +978,7 @@ const opGetSessionToken = "GetSessionToken" | |||
| //        fmt.Println(resp)
 | ||||
| //    }
 | ||||
| //
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionToken
 | ||||
| // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionToken
 | ||||
| func (c *STS) GetSessionTokenRequest(input *GetSessionTokenInput) (req *request.Request, output *GetSessionTokenOutput) { | ||||
| 	op := &request.Operation{ | ||||
| 		Name:       opGetSessionToken, | ||||
|  | @ -1027,7 +1059,7 @@ func (c *STS) GetSessionTokenRequest(input *GetSessionTokenInput) (req *request. | |||
| //   and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
 | ||||
| //   in the IAM User Guide.
 | ||||
| //
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionToken
 | ||||
| // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionToken
 | ||||
| func (c *STS) GetSessionToken(input *GetSessionTokenInput) (*GetSessionTokenOutput, error) { | ||||
| 	req, out := c.GetSessionTokenRequest(input) | ||||
| 	return out, req.Send() | ||||
|  | @ -1049,20 +1081,27 @@ func (c *STS) GetSessionTokenWithContext(ctx aws.Context, input *GetSessionToken | |||
| 	return out, req.Send() | ||||
| } | ||||
| 
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleRequest
 | ||||
| type AssumeRoleInput struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
| 	// The duration, in seconds, of the role session. The value can range from 900
 | ||||
| 	// seconds (15 minutes) to 3600 seconds (1 hour). By default, the value is set
 | ||||
| 	// to 3600 seconds.
 | ||||
| 	// seconds (15 minutes) up to the maximum session duration setting for the role.
 | ||||
| 	// This setting can have a value from 1 hour to 12 hours. If you specify a value
 | ||||
| 	// higher than this setting, the operation fails. For example, if you specify
 | ||||
| 	// a session duration of 12 hours, but your administrator set the maximum session
 | ||||
| 	// duration to 6 hours, your operation fails. To learn how to view the maximum
 | ||||
| 	// value for your role, see View the Maximum Session Duration Setting for a
 | ||||
| 	// Role (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session)
 | ||||
| 	// in the IAM User Guide.
 | ||||
| 	//
 | ||||
| 	// This is separate from the duration of a console session that you might request
 | ||||
| 	// using the returned credentials. The request to the federation endpoint for
 | ||||
| 	// a console sign-in token takes a SessionDuration parameter that specifies
 | ||||
| 	// the maximum length of the console session, separately from the DurationSeconds
 | ||||
| 	// parameter on this API. For more information, see Creating a URL that Enables
 | ||||
| 	// Federated Users to Access the AWS Management Console (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html)
 | ||||
| 	// By default, the value is set to 3600 seconds.
 | ||||
| 	//
 | ||||
| 	// The DurationSeconds parameter is separate from the duration of a console
 | ||||
| 	// session that you might request using the returned credentials. The request
 | ||||
| 	// to the federation endpoint for a console sign-in token takes a SessionDuration
 | ||||
| 	// parameter that specifies the maximum length of the console session. For more
 | ||||
| 	// information, see Creating a URL that Enables Federated Users to Access the
 | ||||
| 	// AWS Management Console (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html)
 | ||||
| 	// in the IAM User Guide.
 | ||||
| 	DurationSeconds *int64 `min:"900" type:"integer"` | ||||
| 
 | ||||
|  | @ -1241,7 +1280,6 @@ func (s *AssumeRoleInput) SetTokenCode(v string) *AssumeRoleInput { | |||
| 
 | ||||
| // Contains the response to a successful AssumeRole request, including temporary
 | ||||
| // AWS credentials that can be used to make AWS requests.
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleResponse
 | ||||
| type AssumeRoleOutput struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
|  | @ -1295,22 +1333,30 @@ func (s *AssumeRoleOutput) SetPackedPolicySize(v int64) *AssumeRoleOutput { | |||
| 	return s | ||||
| } | ||||
| 
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAMLRequest
 | ||||
| type AssumeRoleWithSAMLInput struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
| 	// The duration, in seconds, of the role session. The value can range from 900
 | ||||
| 	// seconds (15 minutes) to 3600 seconds (1 hour). By default, the value is set
 | ||||
| 	// to 3600 seconds. An expiration can also be specified in the SAML authentication
 | ||||
| 	// response's SessionNotOnOrAfter value. The actual expiration time is whichever
 | ||||
| 	// value is shorter.
 | ||||
| 	// The duration, in seconds, of the role session. Your role session lasts for
 | ||||
| 	// the duration that you specify for the DurationSeconds parameter, or until
 | ||||
| 	// the time specified in the SAML authentication response's SessionNotOnOrAfter
 | ||||
| 	// value, whichever is shorter. You can provide a DurationSeconds value from
 | ||||
| 	// 900 seconds (15 minutes) up to the maximum session duration setting for the
 | ||||
| 	// role. This setting can have a value from 1 hour to 12 hours. If you specify
 | ||||
| 	// a value higher than this setting, the operation fails. For example, if you
 | ||||
| 	// specify a session duration of 12 hours, but your administrator set the maximum
 | ||||
| 	// session duration to 6 hours, your operation fails. To learn how to view the
 | ||||
| 	// maximum value for your role, see View the Maximum Session Duration Setting
 | ||||
| 	// for a Role (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session)
 | ||||
| 	// in the IAM User Guide.
 | ||||
| 	//
 | ||||
| 	// This is separate from the duration of a console session that you might request
 | ||||
| 	// using the returned credentials. The request to the federation endpoint for
 | ||||
| 	// a console sign-in token takes a SessionDuration parameter that specifies
 | ||||
| 	// the maximum length of the console session, separately from the DurationSeconds
 | ||||
| 	// parameter on this API. For more information, see Enabling SAML 2.0 Federated
 | ||||
| 	// Users to Access the AWS Management Console (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-saml.html)
 | ||||
| 	// By default, the value is set to 3600 seconds.
 | ||||
| 	//
 | ||||
| 	// The DurationSeconds parameter is separate from the duration of a console
 | ||||
| 	// session that you might request using the returned credentials. The request
 | ||||
| 	// to the federation endpoint for a console sign-in token takes a SessionDuration
 | ||||
| 	// parameter that specifies the maximum length of the console session. For more
 | ||||
| 	// information, see Creating a URL that Enables Federated Users to Access the
 | ||||
| 	// AWS Management Console (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html)
 | ||||
| 	// in the IAM User Guide.
 | ||||
| 	DurationSeconds *int64 `min:"900" type:"integer"` | ||||
| 
 | ||||
|  | @ -1436,7 +1482,6 @@ func (s *AssumeRoleWithSAMLInput) SetSAMLAssertion(v string) *AssumeRoleWithSAML | |||
| 
 | ||||
| // Contains the response to a successful AssumeRoleWithSAML request, including
 | ||||
| // temporary AWS credentials that can be used to make AWS requests.
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAMLResponse
 | ||||
| type AssumeRoleWithSAMLOutput struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
|  | @ -1548,20 +1593,27 @@ func (s *AssumeRoleWithSAMLOutput) SetSubjectType(v string) *AssumeRoleWithSAMLO | |||
| 	return s | ||||
| } | ||||
| 
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentityRequest
 | ||||
| type AssumeRoleWithWebIdentityInput struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
| 	// The duration, in seconds, of the role session. The value can range from 900
 | ||||
| 	// seconds (15 minutes) to 3600 seconds (1 hour). By default, the value is set
 | ||||
| 	// to 3600 seconds.
 | ||||
| 	// seconds (15 minutes) up to the maximum session duration setting for the role.
 | ||||
| 	// This setting can have a value from 1 hour to 12 hours. If you specify a value
 | ||||
| 	// higher than this setting, the operation fails. For example, if you specify
 | ||||
| 	// a session duration of 12 hours, but your administrator set the maximum session
 | ||||
| 	// duration to 6 hours, your operation fails. To learn how to view the maximum
 | ||||
| 	// value for your role, see View the Maximum Session Duration Setting for a
 | ||||
| 	// Role (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session)
 | ||||
| 	// in the IAM User Guide.
 | ||||
| 	//
 | ||||
| 	// This is separate from the duration of a console session that you might request
 | ||||
| 	// using the returned credentials. The request to the federation endpoint for
 | ||||
| 	// a console sign-in token takes a SessionDuration parameter that specifies
 | ||||
| 	// the maximum length of the console session, separately from the DurationSeconds
 | ||||
| 	// parameter on this API. For more information, see Creating a URL that Enables
 | ||||
| 	// Federated Users to Access the AWS Management Console (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html)
 | ||||
| 	// By default, the value is set to 3600 seconds.
 | ||||
| 	//
 | ||||
| 	// The DurationSeconds parameter is separate from the duration of a console
 | ||||
| 	// session that you might request using the returned credentials. The request
 | ||||
| 	// to the federation endpoint for a console sign-in token takes a SessionDuration
 | ||||
| 	// parameter that specifies the maximum length of the console session. For more
 | ||||
| 	// information, see Creating a URL that Enables Federated Users to Access the
 | ||||
| 	// AWS Management Console (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html)
 | ||||
| 	// in the IAM User Guide.
 | ||||
| 	DurationSeconds *int64 `min:"900" type:"integer"` | ||||
| 
 | ||||
|  | @ -1711,7 +1763,6 @@ func (s *AssumeRoleWithWebIdentityInput) SetWebIdentityToken(v string) *AssumeRo | |||
| 
 | ||||
| // Contains the response to a successful AssumeRoleWithWebIdentity request,
 | ||||
| // including temporary AWS credentials that can be used to make AWS requests.
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentityResponse
 | ||||
| type AssumeRoleWithWebIdentityOutput struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
|  | @ -1804,7 +1855,6 @@ func (s *AssumeRoleWithWebIdentityOutput) SetSubjectFromWebIdentityToken(v strin | |||
| 
 | ||||
| // The identifiers for the temporary security credentials that the operation
 | ||||
| // returns.
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumedRoleUser
 | ||||
| type AssumedRoleUser struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
|  | @ -1847,7 +1897,6 @@ func (s *AssumedRoleUser) SetAssumedRoleId(v string) *AssumedRoleUser { | |||
| } | ||||
| 
 | ||||
| // AWS credentials for API authentication.
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/Credentials
 | ||||
| type Credentials struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
|  | @ -1859,7 +1908,7 @@ type Credentials struct { | |||
| 	// The date on which the current credentials expire.
 | ||||
| 	//
 | ||||
| 	// Expiration is a required field
 | ||||
| 	Expiration *time.Time `type:"timestamp" timestampFormat:"iso8601" required:"true"` | ||||
| 	Expiration *time.Time `type:"timestamp" required:"true"` | ||||
| 
 | ||||
| 	// The secret access key that can be used to sign requests.
 | ||||
| 	//
 | ||||
|  | @ -1906,7 +1955,6 @@ func (s *Credentials) SetSessionToken(v string) *Credentials { | |||
| 	return s | ||||
| } | ||||
| 
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessageRequest
 | ||||
| type DecodeAuthorizationMessageInput struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
|  | @ -1951,7 +1999,6 @@ func (s *DecodeAuthorizationMessageInput) SetEncodedMessage(v string) *DecodeAut | |||
| // A document that contains additional information about the authorization status
 | ||||
| // of a request from an encoded message that is returned in response to an AWS
 | ||||
| // request.
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessageResponse
 | ||||
| type DecodeAuthorizationMessageOutput struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
|  | @ -1976,7 +2023,6 @@ func (s *DecodeAuthorizationMessageOutput) SetDecodedMessage(v string) *DecodeAu | |||
| } | ||||
| 
 | ||||
| // Identifiers for the federated user that is associated with the credentials.
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/FederatedUser
 | ||||
| type FederatedUser struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
|  | @ -2017,7 +2063,6 @@ func (s *FederatedUser) SetFederatedUserId(v string) *FederatedUser { | |||
| 	return s | ||||
| } | ||||
| 
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentityRequest
 | ||||
| type GetCallerIdentityInput struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| } | ||||
|  | @ -2034,7 +2079,6 @@ func (s GetCallerIdentityInput) GoString() string { | |||
| 
 | ||||
| // Contains the response to a successful GetCallerIdentity request, including
 | ||||
| // information about the entity making the request.
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentityResponse
 | ||||
| type GetCallerIdentityOutput struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
|  | @ -2080,7 +2124,6 @@ func (s *GetCallerIdentityOutput) SetUserId(v string) *GetCallerIdentityOutput { | |||
| 	return s | ||||
| } | ||||
| 
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationTokenRequest
 | ||||
| type GetFederationTokenInput struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
|  | @ -2189,7 +2232,6 @@ func (s *GetFederationTokenInput) SetPolicy(v string) *GetFederationTokenInput { | |||
| 
 | ||||
| // Contains the response to a successful GetFederationToken request, including
 | ||||
| // temporary AWS credentials that can be used to make AWS requests.
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationTokenResponse
 | ||||
| type GetFederationTokenOutput struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
|  | @ -2242,7 +2284,6 @@ func (s *GetFederationTokenOutput) SetPackedPolicySize(v int64) *GetFederationTo | |||
| 	return s | ||||
| } | ||||
| 
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionTokenRequest
 | ||||
| type GetSessionTokenInput struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
|  | @ -2327,7 +2368,6 @@ func (s *GetSessionTokenInput) SetTokenCode(v string) *GetSessionTokenInput { | |||
| 
 | ||||
| // Contains the response to a successful GetSessionToken request, including
 | ||||
| // temporary AWS credentials that can be used to make AWS requests.
 | ||||
| // Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionTokenResponse
 | ||||
| type GetSessionTokenOutput struct { | ||||
| 	_ struct{} `type:"structure"` | ||||
| 
 | ||||
|  |  | |||
|  | @ -29,8 +29,9 @@ var initRequest func(*request.Request) | |||
| 
 | ||||
| // Service information constants
 | ||||
| const ( | ||||
| 	ServiceName = "sts"       // Service endpoint prefix API calls made to.
 | ||||
| 	EndpointsID = ServiceName // Service ID for Regions and Endpoints metadata.
 | ||||
| 	ServiceName = "sts"       // Name of service.
 | ||||
| 	EndpointsID = ServiceName // ID to lookup a service endpoint with.
 | ||||
| 	ServiceID   = "STS"       // ServiceID is a unique identifer of a specific service.
 | ||||
| ) | ||||
| 
 | ||||
| // New creates a new instance of the STS client with a session.
 | ||||
|  | @ -55,6 +56,7 @@ func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio | |||
| 			cfg, | ||||
| 			metadata.ClientInfo{ | ||||
| 				ServiceName:   ServiceName, | ||||
| 				ServiceID:     ServiceID, | ||||
| 				SigningName:   signingName, | ||||
| 				SigningRegion: signingRegion, | ||||
| 				Endpoint:      endpoint, | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue