Commit 05d6294b authored by Trevor Pounds's avatar Trevor Pounds

Update Godeps.

parent 7cdf5730
......@@ -49,36 +49,54 @@
"Rev": "87808a37061a4a2e6204ccea5fd2fc930576db94"
},
{
"ImportPath": "github.com/awslabs/aws-sdk-go/aws",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3"
"ImportPath": "github.com/aws/aws-sdk-go/aws",
"Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
},
{
"ImportPath": "github.com/awslabs/aws-sdk-go/internal/endpoints",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3"
"ImportPath": "github.com/aws/aws-sdk-go/internal/apierr",
"Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
},
{
"ImportPath": "github.com/awslabs/aws-sdk-go/internal/protocol/ec2query",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3"
"ImportPath": "github.com/aws/aws-sdk-go/internal/endpoints",
"Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
},
{
"ImportPath": "github.com/awslabs/aws-sdk-go/internal/protocol/query",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3"
"ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/ec2query",
"Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
},
{
"ImportPath": "github.com/awslabs/aws-sdk-go/internal/protocol/xml/xmlutil",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3"
"ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/query",
"Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
},
{
"ImportPath": "github.com/awslabs/aws-sdk-go/internal/signer/v4",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3"
"ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/rest",
"Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
},
{
"ImportPath": "github.com/awslabs/aws-sdk-go/service/ec2",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3"
"ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil",
"Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
},
{
"ImportPath": "github.com/awslabs/aws-sdk-go/service/elb",
"Rev": "c0a38f106248742920a2b786dcae81457af003d3"
"ImportPath": "github.com/aws/aws-sdk-go/internal/signer/v4",
"Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/service/ec2",
"Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/service/elb",
"Comment": "v0.6.0-7-gcea3a42",
"Rev": "cea3a425fc2d887d102e406ec2f8b37a57abd82f"
},
{
"ImportPath": "github.com/beorn7/perks/quantile",
......
// Package awserr represents API error interface accessors for the SDK.
package awserr
// An Error wraps lower level errors with code, message and an original error.
// The underlying concrete error type may also satisfy other interfaces which
// can be to used to obtain more specific information about the error.
//
// Calling Error() or String() will always include the full information about
// an error based on its underlying type.
//
// Example:
//
// output, err := s3manage.Upload(svc, input, opts)
// if err != nil {
// if awsErr, ok := err.(awserr.Error); ok {
// // Get error details
// log.Println("Error:", err.Code(), err.Message())
//
// Prints out full error message, including original error if there was one.
// log.Println("Error:", err.Error())
//
// // Get original error
// if origErr := err.Err(); origErr != nil {
// // operate on original error.
// }
// } else {
// fmt.Println(err.Error())
// }
// }
//
type Error interface {
// Satisfy the generic error interface.
error
// Returns the short phrase depicting the classification of the error.
Code() string
// Returns the error details message.
Message() string
// Returns the original error if one was set. Nil is returned if not set.
OrigErr() error
}
// A RequestFailure is an interface to extract request failure information from
// an Error such as the request ID of the failed request returned by a service.
// RequestFailures may not always have a requestID value if the request failed
// prior to reaching the service such as a connection error.
//
// Example:
//
// output, err := s3manage.Upload(svc, input, opts)
// if err != nil {
// if reqerr, ok := err.(RequestFailure); ok {
// log.Printf("Request failed", reqerr.Code(), reqerr.Message(), reqerr.RequestID())
// } else {
// log.Printf("Error:", err.Error()
// }
// }
//
// Combined with awserr.Error:
//
// output, err := s3manage.Upload(svc, input, opts)
// if err != nil {
// if awsErr, ok := err.(awserr.Error); ok {
// // Generic AWS Error with Code, Message, and original error (if any)
// fmt.Println(awsErr.Code(), awsErr.Message(), awsErr.OrigErr())
//
// if reqErr, ok := err.(awserr.RequestFailure); ok {
// // A service error occurred
// fmt.Println(reqErr.StatusCode(), reqErr.RequestID())
// }
// } else {
// fmt.Println(err.Error())
// }
// }
//
type RequestFailure interface {
Error
// The status code of the HTTP response.
StatusCode() int
// The request ID returned by the service for a request failure. This will
// be empty if no request ID is available such as the request failed due
// to a connection error.
RequestID() string
}
......@@ -7,8 +7,17 @@ import (
// Copy deeply copies a src structure to dst. Useful for copying request and
// response structures.
//
// Can copy between structs of different type, but will only copy fields which
// are assignable, and exist in both structs. Fields which are not assignable,
// or do not exist in both structs are ignored.
func Copy(dst, src interface{}) {
rcopy(reflect.ValueOf(dst), reflect.ValueOf(src))
dstval := reflect.ValueOf(dst)
if !dstval.IsValid() {
panic("Copy dst cannot be nil")
}
rcopy(dstval, reflect.ValueOf(src), true)
}
// CopyOf returns a copy of src while also allocating the memory for dst.
......@@ -16,12 +25,15 @@ func Copy(dst, src interface{}) {
func CopyOf(src interface{}) (dst interface{}) {
dsti := reflect.New(reflect.TypeOf(src).Elem())
dst = dsti.Interface()
rcopy(dsti, reflect.ValueOf(src))
rcopy(dsti, reflect.ValueOf(src), true)
return
}
// rcopy performs a recursive copy of values from the source to destination.
func rcopy(dst, src reflect.Value) {
//
// root is used to skip certain aspects of the copy which are not valid
// for the root node of a object.
func rcopy(dst, src reflect.Value, root bool) {
if !src.IsValid() {
return
}
......@@ -36,23 +48,32 @@ func rcopy(dst, src reflect.Value) {
}
} else {
e := src.Type().Elem()
if dst.CanSet() {
if dst.CanSet() && !src.IsNil() {
dst.Set(reflect.New(e))
}
if src.Elem().IsValid() {
rcopy(dst.Elem(), src.Elem())
// Keep the current root state since the depth hasn't changed
rcopy(dst.Elem(), src.Elem(), root)
}
}
case reflect.Struct:
dst.Set(reflect.New(src.Type()).Elem())
for i := 0; i < src.NumField(); i++ {
rcopy(dst.Field(i), src.Field(i))
if !root {
dst.Set(reflect.New(src.Type()).Elem())
}
t := dst.Type()
for i := 0; i < t.NumField(); i++ {
name := t.Field(i).Name
srcval := src.FieldByName(name)
if srcval.IsValid() {
rcopy(dst.FieldByName(name), srcval, false)
}
}
case reflect.Slice:
s := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
dst.Set(s)
for i := 0; i < src.Len(); i++ {
rcopy(dst.Index(i), src.Index(i))
rcopy(dst.Index(i), src.Index(i), false)
}
case reflect.Map:
s := reflect.MakeMap(src.Type())
......@@ -60,10 +81,15 @@ func rcopy(dst, src reflect.Value) {
for _, k := range src.MapKeys() {
v := src.MapIndex(k)
v2 := reflect.New(v.Type()).Elem()
rcopy(v2, v)
rcopy(v2, v, false)
dst.SetMapIndex(k, v2)
}
default:
dst.Set(src)
// Assign the value if possible. If its not assignable, the value would
// need to be converted and the impact of that may be unexpected, or is
// not compatible with the dst type.
if src.Type().AssignableTo(dst.Type()) {
dst.Set(src)
}
}
}
......@@ -7,7 +7,7 @@ import (
"io/ioutil"
"testing"
"github.com/awslabs/aws-sdk-go/aws/awsutil"
"github.com/aws/aws-sdk-go/aws/awsutil"
"github.com/stretchr/testify/assert"
)
......@@ -77,6 +77,23 @@ func TestCopy(t *testing.T) {
assert.NotEqual(t, f2.C, f1.C)
}
func TestCopyIgnoreNilMembers(t *testing.T) {
type Foo struct {
A *string
}
f := &Foo{}
assert.Nil(t, f.A)
var f2 Foo
awsutil.Copy(&f2, f)
assert.Nil(t, f2.A)
fcopy := awsutil.CopyOf(f)
f3 := fcopy.(*Foo)
assert.Nil(t, f3.A)
}
func TestCopyPrimitive(t *testing.T) {
str := "hello"
var s string
......@@ -104,6 +121,52 @@ func TestCopyReader(t *testing.T) {
assert.Equal(t, []byte(""), b)
}
func TestCopyDifferentStructs(t *testing.T) {
type SrcFoo struct {
A int
B []*string
C map[string]*int
SrcUnique string
SameNameDiffType int
}
type DstFoo struct {
A int
B []*string
C map[string]*int
DstUnique int
SameNameDiffType string
}
// Create the initial value
str1 := "hello"
str2 := "bye bye"
int1 := 1
int2 := 2
f1 := &SrcFoo{
A: 1,
B: []*string{&str1, &str2},
C: map[string]*int{
"A": &int1,
"B": &int2,
},
SrcUnique: "unique",
SameNameDiffType: 1,
}
// Do the copy
var f2 DstFoo
awsutil.Copy(&f2, f1)
// Values are equal
assert.Equal(t, f2.A, f1.A)
assert.Equal(t, f2.B, f1.B)
assert.Equal(t, f2.C, f1.C)
assert.Equal(t, "unique", f1.SrcUnique)
assert.Equal(t, 1, f1.SameNameDiffType)
assert.Equal(t, 0, f2.DstUnique)
assert.Equal(t, "", f2.SameNameDiffType)
}
func ExampleCopyOf() {
type Foo struct {
A int
......
......@@ -11,11 +11,11 @@ var indexRe = regexp.MustCompile(`(.+)\[(-?\d+)?\]$`)
// rValuesAtPath returns a slice of values found in value v. The values
// in v are explored recursively so all nested values are collected.
func rValuesAtPath(v interface{}, path string, create bool) []reflect.Value {
func rValuesAtPath(v interface{}, path string, create bool, caseSensitive bool) []reflect.Value {
pathparts := strings.Split(path, "||")
if len(pathparts) > 1 {
for _, pathpart := range pathparts {
vals := rValuesAtPath(v, pathpart, create)
vals := rValuesAtPath(v, pathpart, create, caseSensitive)
if vals != nil && len(vals) > 0 {
return vals
}
......@@ -31,7 +31,7 @@ func rValuesAtPath(v interface{}, path string, create bool) []reflect.Value {
c := strings.TrimSpace(components[0])
if c == "" { // no actual component, illegal syntax
return nil
} else if c != "*" && strings.ToLower(c[0:1]) == c[0:1] {
} else if caseSensitive && c != "*" && strings.ToLower(c[0:1]) == c[0:1] {
// TODO normalize case for user
return nil // don't support unexported fields
}
......@@ -65,7 +65,15 @@ func rValuesAtPath(v interface{}, path string, create bool) []reflect.Value {
continue
}
value = value.FieldByName(c)
value = value.FieldByNameFunc(func(name string) bool {
if c == name {
return true
} else if !caseSensitive && strings.ToLower(name) == strings.ToLower(c) {
return true
}
return false
})
if create && value.Kind() == reflect.Ptr && value.IsNil() {
value.Set(reflect.New(value.Type().Elem()))
value = value.Elem()
......@@ -124,7 +132,20 @@ func rValuesAtPath(v interface{}, path string, create bool) []reflect.Value {
// ValuesAtPath returns a list of objects at the lexical path inside of a structure
func ValuesAtPath(i interface{}, path string) []interface{} {
if rvals := rValuesAtPath(i, path, false); rvals != nil {
if rvals := rValuesAtPath(i, path, false, true); rvals != nil {
vals := make([]interface{}, len(rvals))
for i, rval := range rvals {
vals[i] = rval.Interface()
}
return vals
}
return nil
}
// ValuesAtAnyPath returns a list of objects at the case-insensitive lexical
// path inside of a structure
func ValuesAtAnyPath(i interface{}, path string) []interface{} {
if rvals := rValuesAtPath(i, path, false, false); rvals != nil {
vals := make([]interface{}, len(rvals))
for i, rval := range rvals {
vals[i] = rval.Interface()
......@@ -136,7 +157,17 @@ func ValuesAtPath(i interface{}, path string) []interface{} {
// SetValueAtPath sets an object at the lexical path inside of a structure
func SetValueAtPath(i interface{}, path string, v interface{}) {
if rvals := rValuesAtPath(i, path, true); rvals != nil {
if rvals := rValuesAtPath(i, path, true, true); rvals != nil {
for _, rval := range rvals {
rval.Set(reflect.ValueOf(v))
}
}
}
// SetValueAtAnyPath sets an object at the case insensitive lexical path inside
// of a structure
func SetValueAtAnyPath(i interface{}, path string, v interface{}) {
if rvals := rValuesAtPath(i, path, true, false); rvals != nil {
for _, rval := range rvals {
rval.Set(reflect.ValueOf(v))
}
......
......@@ -3,13 +3,13 @@ package awsutil_test
import (
"testing"
"github.com/awslabs/aws-sdk-go/aws/awsutil"
"github.com/aws/aws-sdk-go/aws/awsutil"
"github.com/stretchr/testify/assert"
)
type Struct struct {
A []Struct
a []Struct
z []Struct
B *Struct
D *Struct
C string
......@@ -17,7 +17,7 @@ type Struct struct {
var data = Struct{
A: []Struct{Struct{C: "value1"}, Struct{C: "value2"}, Struct{C: "value3"}},
a: []Struct{Struct{C: "value1"}, Struct{C: "value2"}, Struct{C: "value3"}},
z: []Struct{Struct{C: "value1"}, Struct{C: "value2"}, Struct{C: "value3"}},
B: &Struct{B: &Struct{C: "terminal"}, D: &Struct{C: "terminal2"}},
C: "initial",
}
......@@ -27,6 +27,7 @@ func TestValueAtPathSuccess(t *testing.T) {
assert.Equal(t, []interface{}{"value1"}, awsutil.ValuesAtPath(data, "A[0].C"))
assert.Equal(t, []interface{}{"value2"}, awsutil.ValuesAtPath(data, "A[1].C"))
assert.Equal(t, []interface{}{"value3"}, awsutil.ValuesAtPath(data, "A[2].C"))
assert.Equal(t, []interface{}{"value3"}, awsutil.ValuesAtAnyPath(data, "a[2].c"))
assert.Equal(t, []interface{}{"value3"}, awsutil.ValuesAtPath(data, "A[-1].C"))
assert.Equal(t, []interface{}{"value1", "value2", "value3"}, awsutil.ValuesAtPath(data, "A[].C"))
assert.Equal(t, []interface{}{"terminal"}, awsutil.ValuesAtPath(data, "B . B . C"))
......@@ -41,7 +42,7 @@ func TestValueAtPathFailure(t *testing.T) {
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "A[100].C"))
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "A[3].C"))
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "B.B.C.Z"))
assert.Equal(t, []interface{}(nil), awsutil.ValuesAtPath(data, "a[-1].C"))
assert.Equal(t, []interface{}(nil), awsutil.ValuesAtPath(data, "z[-1].C"))
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(nil, "A.B.C"))
}
......@@ -57,4 +58,8 @@ func TestSetValueAtPathSuccess(t *testing.T) {
awsutil.SetValueAtPath(&s, "B.*.C", "test0")
assert.Equal(t, "test0", s.B.B.C)
assert.Equal(t, "test0", s.B.D.C)
var s2 Struct
awsutil.SetValueAtAnyPath(&s2, "b.b.c", "test0")
assert.Equal(t, "test0", s2.B.B.C)
}
......@@ -42,7 +42,7 @@ func stringValue(v reflect.Value, indent int, buf *bytes.Buffer) {
if name[0:1] == strings.ToLower(name[0:1]) {
continue // ignore unexported fields
}
if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice) && f.IsNil() {
if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice || f.Kind() == reflect.Map) && f.IsNil() {
continue // ignore unset fields
}
names = append(names, name)
......
......@@ -4,8 +4,9 @@ import (
"io"
"net/http"
"os"
"time"
"github.com/awslabs/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/credentials"
)
// DefaultChainCredentials is a Credentials which will find the first available
......@@ -17,7 +18,7 @@ var DefaultChainCredentials = credentials.NewChainCredentials(
[]credentials.Provider{
&credentials.EnvProvider{},
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
&credentials.EC2RoleProvider{},
&credentials.EC2RoleProvider{ExpiryWindow: 5 * time.Minute},
})
// The default number of retries for a service. The value of -1 indicates that
......@@ -83,6 +84,10 @@ func (c Config) Copy() Config {
// example bool attributes cannot be cleared using Merge, and must be explicitly
// set on the Config structure.
func (c Config) Merge(newcfg *Config) *Config {
if newcfg == nil {
return &c
}
cfg := Config{}
if newcfg != nil && newcfg.Credentials != nil {
......
package credentials
import (
"fmt"
"github.com/aws/aws-sdk-go/internal/apierr"
)
var (
// ErrNoValidProvidersFoundInChain Is returned when there are no valid
// providers in the ChainProvider.
ErrNoValidProvidersFoundInChain = fmt.Errorf("no valid providers in chain")
ErrNoValidProvidersFoundInChain = apierr.New("NoCredentialProviders", "no valid providers in chain", nil)
)
// A ChainProvider will search for a provider which returns credentials
......
package credentials
import (
"errors"
"github.com/stretchr/testify/assert"
"testing"
"github.com/aws/aws-sdk-go/internal/apierr"
"github.com/stretchr/testify/assert"
)
func TestChainProviderGet(t *testing.T) {
p := &ChainProvider{
Providers: []Provider{
&stubProvider{err: errors.New("first provider error")},
&stubProvider{err: errors.New("second provider error")},
&stubProvider{err: apierr.New("FirstError", "first provider error", nil)},
&stubProvider{err: apierr.New("SecondError", "second provider error", nil)},
&stubProvider{
creds: Value{
AccessKeyID: "AKID",
......@@ -61,12 +62,12 @@ func TestChainProviderWithNoProvider(t *testing.T) {
func TestChainProviderWithNoValidProvider(t *testing.T) {
p := &ChainProvider{
Providers: []Provider{
&stubProvider{err: errors.New("first provider error")},
&stubProvider{err: errors.New("second provider error")},
&stubProvider{err: apierr.New("FirstError", "first provider error", nil)},
&stubProvider{err: apierr.New("SecondError", "second provider error", nil)},
},
}
assert.True(t, p.IsExpired(), "Expect expired with no providers")
_, err := p.Retrieve()
assert.Contains(t, "no valid providers in chain", err.Error(), "Expect no providers error returned")
assert.Equal(t, ErrNoValidProvidersFoundInChain, err, "Expect no providers error returned")
}
package credentials
import (
"errors"
"github.com/stretchr/testify/assert"
"testing"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/internal/apierr"
"github.com/stretchr/testify/assert"
)
type stubProvider struct {
......@@ -38,10 +40,10 @@ func TestCredentialsGet(t *testing.T) {
}
func TestCredentialsGetWithError(t *testing.T) {
c := NewCredentials(&stubProvider{err: errors.New("provider error"), expired: true})
c := NewCredentials(&stubProvider{err: apierr.New("provider error", "", nil), expired: true})
_, err := c.Get()
assert.Equal(t, "provider error", err.Error(), "Expected provider error")
assert.Equal(t, "provider error", err.(awserr.Error).Code(), "Expected provider error")
}
func TestCredentialsExpire(t *testing.T) {
......
......@@ -6,6 +6,8 @@ import (
"fmt"
"net/http"
"time"
"github.com/aws/aws-sdk-go/internal/apierr"
)
const metadataCredentialsEndpoint = "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
......@@ -89,7 +91,7 @@ func (m *EC2RoleProvider) Retrieve() (Value, error) {
}
if len(credsList) == 0 {
return Value{}, fmt.Errorf("empty MetadataService credentials list")
return Value{}, apierr.New("EmptyEC2RoleList", "empty EC2 Role list", nil)
}
credsName := credsList[0]
......@@ -130,7 +132,7 @@ type ec2RoleCredRespBody struct {
func requestCredList(client *http.Client, endpoint string) ([]string, error) {
resp, err := client.Get(endpoint)
if err != nil {
return nil, fmt.Errorf("%s listing MetadataService credentials", err)
return nil, apierr.New("ListEC2Role", "failed to list EC2 Roles", err)
}
defer resp.Body.Close()
......@@ -141,7 +143,7 @@ func requestCredList(client *http.Client, endpoint string) ([]string, error) {
}
if err := s.Err(); err != nil {
return nil, fmt.Errorf("%s reading list of MetadataService credentials", err)
return nil, apierr.New("ReadEC2Role", "failed to read list of EC2 Roles", err)
}
return credsList, nil
......@@ -154,13 +156,17 @@ func requestCredList(client *http.Client, endpoint string) ([]string, error) {
func requestCred(client *http.Client, endpoint, credsName string) (*ec2RoleCredRespBody, error) {
resp, err := client.Get(endpoint + credsName)
if err != nil {
return nil, fmt.Errorf("getting %s MetadataService credentials", credsName)
return nil, apierr.New("GetEC2RoleCredentials",
fmt.Sprintf("failed to get %s EC2 Role credentials", credsName),
err)
}
defer resp.Body.Close()
respCreds := &ec2RoleCredRespBody{}
if err := json.NewDecoder(resp.Body).Decode(respCreds); err != nil {
return nil, fmt.Errorf("decoding %s MetadataService credentials", credsName)
return nil, apierr.New("DecodeEC2RoleCredentials",
fmt.Sprintf("failed to decode %s EC2 Role credentials", credsName),
err)
}
return respCreds, nil
......
package credentials
import (
"fmt"
"os"
"github.com/aws/aws-sdk-go/internal/apierr"
)
var (
// ErrAccessKeyIDNotFound is returned when the AWS Access Key ID can't be
// found in the process's environment.
ErrAccessKeyIDNotFound = fmt.Errorf("AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment")
ErrAccessKeyIDNotFound = apierr.New("EnvAccessKeyNotFound", "AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment", nil)
// ErrSecretAccessKeyNotFound is returned when the AWS Secret Access Key
// can't be found in the process's environment.
ErrSecretAccessKeyNotFound = fmt.Errorf("AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment")
ErrSecretAccessKeyNotFound = apierr.New("EnvSecretNotFound", "AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment", nil)
)
// A EnvProvider retrieves credentials from the environment variables of the
......
......@@ -14,7 +14,7 @@ func TestEnvProviderRetrieve(t *testing.T) {
e := EnvProvider{}
creds, err := e.Retrieve()
assert.Nil(t, err, "Expect no error", err)
assert.Nil(t, err, "Expect no error")
assert.Equal(t, "access", creds.AccessKeyID, "Expect access key ID to match")
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
......@@ -32,7 +32,7 @@ func TestEnvProviderIsExpired(t *testing.T) {
assert.True(t, e.IsExpired(), "Expect creds to be expired before retrieve.")
_, err := e.Retrieve()
assert.Nil(t, err, "Expect no error", err)
assert.Nil(t, err, "Expect no error")
assert.False(t, e.IsExpired(), "Expect creds to not be expired after retrieve.")
}
......
......@@ -6,11 +6,13 @@ import (
"path/filepath"
"github.com/vaughan0/go-ini"
"github.com/aws/aws-sdk-go/internal/apierr"
)
var (
// ErrSharedCredentialsHomeNotFound is emitted when the user directory cannot be found.
ErrSharedCredentialsHomeNotFound = fmt.Errorf("User home directory not found.")
ErrSharedCredentialsHomeNotFound = apierr.New("UserHomeNotFound", "user home directory not found.", nil)
)
// A SharedCredentialsProvider retrieves credentials from the current user's home
......@@ -70,18 +72,22 @@ func (p *SharedCredentialsProvider) IsExpired() bool {
func loadProfile(filename, profile string) (Value, error) {
config, err := ini.LoadFile(filename)
if err != nil {
return Value{}, err
return Value{}, apierr.New("SharedCredsLoad", "failed to load shared credentials file", err)
}
iniProfile := config.Section(profile)
id, ok := iniProfile["aws_access_key_id"]
if !ok {
return Value{}, fmt.Errorf("shared credentials %s in %s did not contain aws_access_key_id", profile, filename)
return Value{}, apierr.New("SharedCredsAccessKey",
fmt.Sprintf("shared credentials %s in %s did not contain aws_access_key_id", profile, filename),
nil)
}
secret, ok := iniProfile["aws_secret_access_key"]
if !ok {
return Value{}, fmt.Errorf("shared credentials %s in %s did not contain aws_secret_access_key", profile, filename)
return Value{}, apierr.New("SharedCredsSecret",
fmt.Sprintf("shared credentials %s in %s did not contain aws_secret_access_key", profile, filename),
nil)
}
token := iniProfile["aws_session_token"]
......
package credentials
import (
"fmt"
"github.com/aws/aws-sdk-go/internal/apierr"
)
var (
// ErrStaticCredentialsEmpty is emitted when static credentials are empty.
ErrStaticCredentialsEmpty = fmt.Errorf("static credentials are empty")
ErrStaticCredentialsEmpty = apierr.New("EmptyStaticCreds", "static credentials are empty", nil)
)
// A StaticProvider is a set of credentials which are set pragmatically,
......
......@@ -10,6 +10,9 @@ import (
"regexp"
"strconv"
"time"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/internal/apierr"
)
var sleepDelay = func(delay time.Duration) {
......@@ -59,19 +62,27 @@ var reStatusCode = regexp.MustCompile(`^(\d+)`)
// SendHandler is a request handler to send service request using HTTP client.
func SendHandler(r *Request) {
r.HTTPResponse, r.Error = r.Service.Config.HTTPClient.Do(r.HTTPRequest)
if r.Error != nil {
if e, ok := r.Error.(*url.Error); ok {
if s := reStatusCode.FindStringSubmatch(e.Err.Error()); s != nil {
var err error
r.HTTPResponse, err = r.Service.Config.HTTPClient.Do(r.HTTPRequest)
if err != nil {
// Capture the case where url.Error is returned for error processing
// response. e.g. 301 without location header comes back as string
// error and r.HTTPResponse is nil. Other url redirect errors will
// comeback in a similar method.
if e, ok := err.(*url.Error); ok {
if s := reStatusCode.FindStringSubmatch(e.Error()); s != nil {
code, _ := strconv.ParseInt(s[1], 10, 64)
r.Error = nil
r.HTTPResponse = &http.Response{
StatusCode: int(code),
Status: http.StatusText(int(code)),
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
}
return
}
}
// Catch all other request errors.
r.Error = apierr.New("RequestError", "send request failed", err)
r.Retryable.Set(true) // network errors are retryable
}
}
......@@ -79,11 +90,7 @@ func SendHandler(r *Request) {
func ValidateResponseHandler(r *Request) {
if r.HTTPResponse.StatusCode == 0 || r.HTTPResponse.StatusCode >= 300 {
// this may be replaced by an UnmarshalError handler
r.Error = &APIError{
StatusCode: r.HTTPResponse.StatusCode,
Code: "UnknownError",
Message: "unknown error",
}
r.Error = apierr.New("UnknownError", "unknown error", nil)
}
}
......@@ -103,10 +110,14 @@ func AfterRetryHandler(r *Request) {
// when the expired token exception occurs the credentials
// need to be expired locally so that the next request to
// get credentials will trigger a credentials refresh.
if err := Error(r.Error); err != nil && err.Code == "ExpiredTokenException" {
r.Config.Credentials.Expire()
// The credentials will need to be resigned with new credentials
r.signed = false
if r.Error != nil {
if err, ok := r.Error.(awserr.Error); ok {
if isCodeExpiredCreds(err.Code()) {
r.Config.Credentials.Expire()
// The credentials will need to be resigned with new credentials
r.signed = false
}
}
}
r.RetryCount++
......@@ -117,11 +128,11 @@ func AfterRetryHandler(r *Request) {
var (
// ErrMissingRegion is an error that is returned if region configuration is
// not found.
ErrMissingRegion = fmt.Errorf("could not find region configuration")
ErrMissingRegion error = apierr.New("MissingRegion", "could not find region configuration", nil)
// ErrMissingEndpoint is an error that is returned if an endpoint cannot be
// resolved for a service.
ErrMissingEndpoint = fmt.Errorf("`Endpoint' configuration is required for this service")
ErrMissingEndpoint error = apierr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil)
)
// ValidateEndpointHandler is a request handler to validate a request had the
......
......@@ -5,7 +5,8 @@ import (
"os"
"testing"
"github.com/awslabs/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/internal/apierr"
"github.com/stretchr/testify/assert"
)
......@@ -55,11 +56,11 @@ func TestAfterRetryRefreshCreds(t *testing.T) {
svc.Handlers.Clear()
svc.Handlers.ValidateResponse.PushBack(func(r *Request) {
r.Error = &APIError{Code: "UnknownError"}
r.Error = apierr.New("UnknownError", "", nil)
r.HTTPResponse = &http.Response{StatusCode: 400}
})
svc.Handlers.UnmarshalError.PushBack(func(r *Request) {
r.Error = &APIError{Code: "ExpiredTokenException"}
r.Error = apierr.New("ExpiredTokenException", "", nil)
})
svc.Handlers.AfterRetry.PushBack(func(r *Request) {
AfterRetryHandler(r)
......
......@@ -4,6 +4,8 @@ import (
"fmt"
"reflect"
"strings"
"github.com/aws/aws-sdk-go/internal/apierr"
)
// ValidateParameters is a request handler to validate the input parameters.
......@@ -16,7 +18,7 @@ func ValidateParameters(r *Request) {
if count := len(v.errors); count > 0 {
format := "%d validation errors:\n- %s"
msg := fmt.Sprintf(format, count, strings.Join(v.errors, "\n- "))
r.Error = APIError{Code: "InvalidParameter", Message: msg}
r.Error = apierr.New("InvalidParameter", msg, nil)
}
}
}
......@@ -66,7 +68,7 @@ func (v *validator) validateStruct(value reflect.Value, path string) {
notset := false
if f.Tag.Get("required") != "" {
switch fvalue.Kind() {
case reflect.Ptr, reflect.Slice:
case reflect.Ptr, reflect.Slice, reflect.Map:
if fvalue.IsNil() {
notset = true
}
......
......@@ -3,7 +3,8 @@ package aws_test
import (
"testing"
"github.com/awslabs/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/stretchr/testify/assert"
)
......@@ -17,9 +18,9 @@ var service = func() *aws.Service {
}()
type StructShape struct {
RequiredList []*ConditionalStructShape `required:"true"`
RequiredMap *map[string]*ConditionalStructShape `required:"true"`
RequiredBool *bool `required:"true"`
RequiredList []*ConditionalStructShape `required:"true"`
RequiredMap map[string]*ConditionalStructShape `required:"true"`
RequiredBool *bool `required:"true"`
OptionalStruct *ConditionalStructShape
hiddenParameter *string
......@@ -39,7 +40,7 @@ type ConditionalStructShape struct {
func TestNoErrors(t *testing.T) {
input := &StructShape{
RequiredList: []*ConditionalStructShape{},
RequiredMap: &map[string]*ConditionalStructShape{
RequiredMap: map[string]*ConditionalStructShape{
"key1": &ConditionalStructShape{Name: aws.String("Name")},
"key2": &ConditionalStructShape{Name: aws.String("Name")},
},
......@@ -56,17 +57,16 @@ func TestMissingRequiredParameters(t *testing.T) {
input := &StructShape{}
req := aws.NewRequest(service, &aws.Operation{}, input, nil)
aws.ValidateParameters(req)
err := aws.Error(req.Error)
assert.Error(t, err)
assert.Equal(t, "InvalidParameter", err.Code)
assert.Equal(t, "3 validation errors:\n- missing required parameter: RequiredList\n- missing required parameter: RequiredMap\n- missing required parameter: RequiredBool", err.Message)
assert.Error(t, req.Error)
assert.Equal(t, "InvalidParameter", req.Error.(awserr.Error).Code())
assert.Equal(t, "3 validation errors:\n- missing required parameter: RequiredList\n- missing required parameter: RequiredMap\n- missing required parameter: RequiredBool", req.Error.(awserr.Error).Message())
}
func TestNestedMissingRequiredParameters(t *testing.T) {
input := &StructShape{
RequiredList: []*ConditionalStructShape{&ConditionalStructShape{}},
RequiredMap: &map[string]*ConditionalStructShape{
RequiredMap: map[string]*ConditionalStructShape{
"key1": &ConditionalStructShape{Name: aws.String("Name")},
"key2": &ConditionalStructShape{},
},
......@@ -76,10 +76,9 @@ func TestNestedMissingRequiredParameters(t *testing.T) {
req := aws.NewRequest(service, &aws.Operation{}, input, nil)
aws.ValidateParameters(req)
err := aws.Error(req.Error)
assert.Error(t, err)
assert.Equal(t, "InvalidParameter", err.Code)
assert.Equal(t, "3 validation errors:\n- missing required parameter: RequiredList[0].Name\n- missing required parameter: RequiredMap[\"key2\"].Name\n- missing required parameter: OptionalStruct.Name", err.Message)
assert.Error(t, req.Error)
assert.Equal(t, "InvalidParameter", req.Error.(awserr.Error).Code())
assert.Equal(t, "3 validation errors:\n- missing required parameter: RequiredList[0].Name\n- missing required parameter: RequiredMap[\"key2\"].Name\n- missing required parameter: OptionalStruct.Name", req.Error.(awserr.Error).Message())
}
......@@ -9,6 +9,8 @@ import (
"reflect"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws/awsutil"
)
// A Request is the service request to be made.
......@@ -39,6 +41,15 @@ type Operation struct {
Name string
HTTPMethod string
HTTPPath string
*Paginator
}
// Paginator keeps track of pagination configuration for an API operation.
type Paginator struct {
InputTokens []string
OutputTokens []string
LimitToken string
TruncationToken string
}
// NewRequest returns a new Request pointer for the service API
......@@ -187,7 +198,12 @@ func (r *Request) Send() error {
r.Handlers.Send.Run(r)
if r.Error != nil {
return r.Error
r.Handlers.Retry.Run(r)
r.Handlers.AfterRetry.Run(r)
if r.Error != nil {
return r.Error
}
continue
}
r.Handlers.UnmarshalMeta.Run(r)
......@@ -217,3 +233,86 @@ func (r *Request) Send() error {
return nil
}
// HasNextPage returns true if this request has more pages of data available.
func (r *Request) HasNextPage() bool {
return r.nextPageTokens() != nil
}
// nextPageTokens returns the tokens to use when asking for the next page of
// data.
func (r *Request) nextPageTokens() []interface{} {
if r.Operation.Paginator == nil {
return nil
}
if r.Operation.TruncationToken != "" {
tr := awsutil.ValuesAtAnyPath(r.Data, r.Operation.TruncationToken)
if tr == nil || len(tr) == 0 {
return nil
}
switch v := tr[0].(type) {
case bool:
if v == false {
return nil
}
}
}
found := false
tokens := make([]interface{}, len(r.Operation.OutputTokens))
for i, outtok := range r.Operation.OutputTokens {
v := awsutil.ValuesAtAnyPath(r.Data, outtok)
if v != nil && len(v) > 0 {
found = true
tokens[i] = v[0]
}
}
if found {
return tokens
}
return nil
}
// NextPage returns a new Request that can be executed to return the next
// page of result data. Call .Send() on this request to execute it.
func (r *Request) NextPage() *Request {
tokens := r.nextPageTokens()
if tokens == nil {
return nil
}
data := reflect.New(reflect.TypeOf(r.Data).Elem()).Interface()
nr := NewRequest(r.Service, r.Operation, awsutil.CopyOf(r.Params), data)
for i, intok := range nr.Operation.InputTokens {
awsutil.SetValueAtAnyPath(nr.Params, intok, tokens[i])
}
return nr
}
// EachPage iterates over each page of a paginated request object. The fn
// parameter should be a function with the following sample signature:
//
// func(page *T, lastPage bool) bool {
// return true // return false to stop iterating
// }
//
// Where "T" is the structure type matching the output structure of the given
// operation. For example, a request object generated by
// DynamoDB.ListTablesRequest() would expect to see dynamodb.ListTablesOutput
// as the structure "T". The lastPage value represents whether the page is
// the last page of data or not. The return value of this function should
// return true to keep iterating or false to stop.
func (r *Request) EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error {
for page := r; page != nil; page = page.NextPage() {
page.Send()
shouldContinue := fn(page.Data, !page.HasNextPage())
if page.Error != nil || !shouldContinue {
return page.Error
}
}
return nil
}
......@@ -3,6 +3,7 @@ package aws
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
......@@ -10,7 +11,9 @@ import (
"testing"
"time"
"github.com/awslabs/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/internal/apierr"
"github.com/stretchr/testify/assert"
)
......@@ -33,26 +36,27 @@ func unmarshal(req *Request) {
func unmarshalError(req *Request) {
bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body)
if err != nil {
req.Error = err
req.Error = apierr.New("UnmarshaleError", req.HTTPResponse.Status, err)
return
}
if len(bodyBytes) == 0 {
req.Error = APIError{
StatusCode: req.HTTPResponse.StatusCode,
Message: req.HTTPResponse.Status,
}
req.Error = apierr.NewRequestError(
apierr.New("UnmarshaleError", req.HTTPResponse.Status, fmt.Errorf("empty body")),
req.HTTPResponse.StatusCode,
"",
)
return
}
var jsonErr jsonErrorResponse
if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil {
req.Error = err
req.Error = apierr.New("UnmarshaleError", "JSON unmarshal", err)
return
}
req.Error = APIError{
StatusCode: req.HTTPResponse.StatusCode,
Code: jsonErr.Code,
Message: jsonErr.Message,
}
req.Error = apierr.NewRequestError(
apierr.New(jsonErr.Code, jsonErr.Message, nil),
req.HTTPResponse.StatusCode,
"",
)
}
type jsonErrorResponse struct {
......@@ -125,12 +129,14 @@ func TestRequest4xxUnretryable(t *testing.T) {
out := &testData{}
r := NewRequest(s, &Operation{Name: "Operation"}, nil, out)
err := r.Send()
apiErr := Error(err)
assert.NotNil(t, err)
assert.NotNil(t, apiErr)
assert.Equal(t, 401, apiErr.StatusCode)
assert.Equal(t, "SignatureDoesNotMatch", apiErr.Code)
assert.Equal(t, "Signature does not match.", apiErr.Message)
if e, ok := err.(awserr.RequestFailure); ok {
assert.Equal(t, 401, e.StatusCode())
} else {
assert.Fail(t, "Expected error to be a service failure")
}
assert.Equal(t, "SignatureDoesNotMatch", err.(awserr.Error).Code())
assert.Equal(t, "Signature does not match.", err.(awserr.Error).Message())
assert.Equal(t, 0, int(r.RetryCount))
}
......@@ -159,12 +165,14 @@ func TestRequestExhaustRetries(t *testing.T) {
})
r := NewRequest(s, &Operation{Name: "Operation"}, nil, nil)
err := r.Send()
apiErr := Error(err)
assert.NotNil(t, err)
assert.NotNil(t, apiErr)
assert.Equal(t, 500, apiErr.StatusCode)
assert.Equal(t, "UnknownError", apiErr.Code)
assert.Equal(t, "An error occurred.", apiErr.Message)
if e, ok := err.(awserr.RequestFailure); ok {
assert.Equal(t, 500, e.StatusCode())
} else {
assert.Fail(t, "Expected error to be a service failure")
}
assert.Equal(t, "UnknownError", err.(awserr.Error).Code())
assert.Equal(t, "An error occurred.", err.(awserr.Error).Message())
assert.Equal(t, 3, int(r.RetryCount))
assert.True(t, reflect.DeepEqual([]time.Duration{30 * time.Millisecond, 60 * time.Millisecond, 120 * time.Millisecond}, delays))
}
......@@ -185,12 +193,6 @@ func TestRequestRecoverExpiredCreds(t *testing.T) {
credExpiredBeforeRetry := false
credExpiredAfterRetry := false
s.Handlers.Retry.PushBack(func(r *Request) {
if err := Error(r.Error); err != nil && err.Code == "ExpiredTokenException" {
credExpiredBeforeRetry = r.Config.Credentials.IsExpired()
}
})
s.Handlers.AfterRetry.PushBack(func(r *Request) {
credExpiredAfterRetry = r.Config.Credentials.IsExpired()
})
......
......@@ -8,7 +8,8 @@ import (
"regexp"
"time"
"github.com/awslabs/aws-sdk-go/internal/endpoints"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/internal/endpoints"
)
// A Service implements the base service request and response handling
......@@ -132,22 +133,44 @@ func retryRules(r *Request) time.Duration {
return delay * time.Millisecond
}
// Collection of service response codes which are generically
// retryable for all services.
// retryableCodes is a collection of service response codes which are retry-able
// without any further action.
var retryableCodes = map[string]struct{}{
"ExpiredTokenException": struct{}{},
"RequestError": struct{}{},
"ProvisionedThroughputExceededException": struct{}{},
"Throttling": struct{}{},
}
// credsExpiredCodes is a collection of error codes which signify the credentials
// need to be refreshed. Expired tokens require refreshing of credentials, and
// resigning before the request can be retried.
var credsExpiredCodes = map[string]struct{}{
"ExpiredToken": struct{}{},
"ExpiredTokenException": struct{}{},
"RequestExpired": struct{}{}, // EC2 Only
}
func isCodeRetryable(code string) bool {
if _, ok := retryableCodes[code]; ok {
return true
}
return isCodeExpiredCreds(code)
}
func isCodeExpiredCreds(code string) bool {
_, ok := credsExpiredCodes[code]
return ok
}
// shouldRetry returns if the request should be retried.
func shouldRetry(r *Request) bool {
if r.HTTPResponse.StatusCode >= 500 {
return true
}
if err := Error(r.Error); err != nil {
if _, ok := retryableCodes[err.Code]; ok {
return true
if r.Error != nil {
if err, ok := r.Error.(awserr.Error); ok {
return isCodeRetryable(err.Code())
}
}
return false
......
......@@ -5,4 +5,4 @@ package aws
const SDKName = "aws-sdk-go"
// SDKVersion is the version of this SDK
const SDKVersion = "0.5.0"
const SDKVersion = "0.6.0"
// Package apierr represents API error types.
package apierr
import "fmt"
// A BaseError wraps the code and message which defines an error. It also
// can be used to wrap an original error object.
//
// Should be used as the root for errors satisfying the awserr.Error. Also
// for any error which does not fit into a specific error wrapper type.
type BaseError struct {
// Classification of error
code string
// Detailed information about error
message string
// Optional original error this error is based off of. Allows building
// chained errors.
origErr error
}
// New returns an error object for the code, message, and err.
//
// code is a short no whitespace phrase depicting the classification of
// the error that is being created.
//
// message is the free flow string containing detailed information about the error.
//
// origErr is the error object which will be nested under the new error to be returned.
func New(code, message string, origErr error) *BaseError {
return &BaseError{
code: code,
message: message,
origErr: origErr,
}
}
// Error returns the string representation of the error.
//
// See ErrorWithExtra for formatting.
//
// Satisfies the error interface.
func (b *BaseError) Error() string {
return b.ErrorWithExtra("")
}
// String returns the string representation of the error.
// Alias for Error to satisfy the stringer interface.
func (b *BaseError) String() string {
return b.Error()
}
// Code returns the short phrase depicting the classification of the error.
func (b *BaseError) Code() string {
return b.code
}
// Message returns the error details message.
func (b *BaseError) Message() string {
return b.message
}
// OrigErr returns the original error if one was set. Nil is returned if no error
// was set.
func (b *BaseError) OrigErr() error {
return b.origErr
}
// ErrorWithExtra is a helper method to add an extra string to the stratified
// error message. The extra message will be added on the next line below the
// error message like the following:
//
// <error code>: <error message>
// <extra message>
//
// If there is a original error the error will be included on a new line.
//
// <error code>: <error message>
// <extra message>
// caused by: <original error>
func (b *BaseError) ErrorWithExtra(extra string) string {
msg := fmt.Sprintf("%s: %s", b.code, b.message)
if extra != "" {
msg = fmt.Sprintf("%s\n\t%s", msg, extra)
}
if b.origErr != nil {
msg = fmt.Sprintf("%s\ncaused by: %s", msg, b.origErr.Error())
}
return msg
}
// A RequestError wraps a request or service error.
//
// Composed of BaseError for code, message, and original error.
type RequestError struct {
*BaseError
statusCode int
requestID string
}
// NewRequestError returns a wrapped error with additional information for request
// status code, and service requestID.
//
// Should be used to wrap all request which involve service requests. Even if
// the request failed without a service response, but had an HTTP status code
// that may be meaningful.
//
// Also wraps original errors via the BaseError.
func NewRequestError(base *BaseError, statusCode int, requestID string) *RequestError {
return &RequestError{
BaseError: base,
statusCode: statusCode,
requestID: requestID,
}
}
// Error returns the string representation of the error.
// Satisfies the error interface.
func (r *RequestError) Error() string {
return r.ErrorWithExtra(fmt.Sprintf("status code: %d, request id: [%s]",
r.statusCode, r.requestID))
}
// String returns the string representation of the error.
// Alias for Error to satisfy the stringer interface.
func (r *RequestError) String() string {
return r.Error()
}
// StatusCode returns the wrapped status code for the error
func (r *RequestError) StatusCode() int {
return r.statusCode
}
// RequestID returns the wrapped requestID
func (r *RequestError) RequestID() string {
return r.requestID
}
// Package endpoints validates regional endpoints for services.
package endpoints
//go:generate go run ../model/cli/gen-endpoints/main.go endpoints.json endpoints_map.go
......
// Package ec2query provides serialisation of AWS EC2 requests and responses.
package ec2query
//go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/input/ec2.json build_test.go
......@@ -5,8 +6,9 @@ package ec2query
import (
"net/url"
"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/protocol/query/queryutil"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/apierr"
"github.com/aws/aws-sdk-go/internal/protocol/query/queryutil"
)
// Build builds a request for the EC2 protocol.
......@@ -16,8 +18,7 @@ func Build(r *aws.Request) {
"Version": {r.Service.APIVersion},
}
if err := queryutil.Parse(body, r.Params, true); err != nil {
r.Error = err
return
r.Error = apierr.New("Marshal", "failed encoding EC2 Query request", err)
}
if r.ExpireTime == 0 {
......
package ec2query_test
import (
"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/protocol/ec2query"
"github.com/awslabs/aws-sdk-go/internal/signer/v4"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/protocol/ec2query"
"github.com/aws/aws-sdk-go/internal/signer/v4"
"bytes"
"encoding/json"
"encoding/xml"
"github.com/awslabs/aws-sdk-go/internal/protocol/xml/xmlutil"
"github.com/awslabs/aws-sdk-go/internal/util"
"github.com/stretchr/testify/assert"
"io"
"io/ioutil"
"net/http"
"net/url"
"testing"
"time"
"github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil"
"github.com/aws/aws-sdk-go/internal/util"
"github.com/stretchr/testify/assert"
)
var _ bytes.Buffer // always import bytes
......@@ -37,10 +38,6 @@ type InputService1ProtocolTest struct {
// New returns a new InputService1ProtocolTest client.
func NewInputService1ProtocolTest(config *aws.Config) *InputService1ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice1protocoltest",
......@@ -85,11 +82,10 @@ func (c *InputService1ProtocolTest) InputService1TestCaseOperation1Request(input
return
}
func (c *InputService1ProtocolTest) InputService1TestCaseOperation1(input *InputService1TestShapeInputShape) (output *InputService1TestShapeInputService1TestCaseOperation1Output, err error) {
func (c *InputService1ProtocolTest) InputService1TestCaseOperation1(input *InputService1TestShapeInputShape) (*InputService1TestShapeInputService1TestCaseOperation1Output, error) {
req, out := c.InputService1TestCaseOperation1Request(input)
output = out
err = req.Send()
return
err := req.Send()
return out, err
}
var opInputService1TestCaseOperation1 *aws.Operation
......@@ -121,10 +117,6 @@ type InputService2ProtocolTest struct {
// New returns a new InputService2ProtocolTest client.
func NewInputService2ProtocolTest(config *aws.Config) *InputService2ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice2protocoltest",
......@@ -169,11 +161,10 @@ func (c *InputService2ProtocolTest) InputService2TestCaseOperation1Request(input
return
}
func (c *InputService2ProtocolTest) InputService2TestCaseOperation1(input *InputService2TestShapeInputShape) (output *InputService2TestShapeInputService2TestCaseOperation1Output, err error) {
func (c *InputService2ProtocolTest) InputService2TestCaseOperation1(input *InputService2TestShapeInputShape) (*InputService2TestShapeInputService2TestCaseOperation1Output, error) {
req, out := c.InputService2TestCaseOperation1Request(input)
output = out
err = req.Send()
return
err := req.Send()
return out, err
}
var opInputService2TestCaseOperation1 *aws.Operation
......@@ -207,10 +198,6 @@ type InputService3ProtocolTest struct {
// New returns a new InputService3ProtocolTest client.
func NewInputService3ProtocolTest(config *aws.Config) *InputService3ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice3protocoltest",
......@@ -255,11 +242,10 @@ func (c *InputService3ProtocolTest) InputService3TestCaseOperation1Request(input
return
}
func (c *InputService3ProtocolTest) InputService3TestCaseOperation1(input *InputService3TestShapeInputShape) (output *InputService3TestShapeInputService3TestCaseOperation1Output, err error) {
func (c *InputService3ProtocolTest) InputService3TestCaseOperation1(input *InputService3TestShapeInputShape) (*InputService3TestShapeInputService3TestCaseOperation1Output, error) {
req, out := c.InputService3TestCaseOperation1Request(input)
output = out
err = req.Send()
return
err := req.Send()
return out, err
}
var opInputService3TestCaseOperation1 *aws.Operation
......@@ -299,10 +285,6 @@ type InputService4ProtocolTest struct {
// New returns a new InputService4ProtocolTest client.
func NewInputService4ProtocolTest(config *aws.Config) *InputService4ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice4protocoltest",
......@@ -347,11 +329,10 @@ func (c *InputService4ProtocolTest) InputService4TestCaseOperation1Request(input
return
}
func (c *InputService4ProtocolTest) InputService4TestCaseOperation1(input *InputService4TestShapeInputShape) (output *InputService4TestShapeInputService4TestCaseOperation1Output, err error) {
func (c *InputService4ProtocolTest) InputService4TestCaseOperation1(input *InputService4TestShapeInputShape) (*InputService4TestShapeInputService4TestCaseOperation1Output, error) {
req, out := c.InputService4TestCaseOperation1Request(input)
output = out
err = req.Send()
return
err := req.Send()
return out, err
}
var opInputService4TestCaseOperation1 *aws.Operation
......@@ -381,10 +362,6 @@ type InputService5ProtocolTest struct {
// New returns a new InputService5ProtocolTest client.
func NewInputService5ProtocolTest(config *aws.Config) *InputService5ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice5protocoltest",
......@@ -429,11 +406,10 @@ func (c *InputService5ProtocolTest) InputService5TestCaseOperation1Request(input
return
}
func (c *InputService5ProtocolTest) InputService5TestCaseOperation1(input *InputService5TestShapeInputShape) (output *InputService5TestShapeInputService5TestCaseOperation1Output, err error) {
func (c *InputService5ProtocolTest) InputService5TestCaseOperation1(input *InputService5TestShapeInputShape) (*InputService5TestShapeInputService5TestCaseOperation1Output, error) {
req, out := c.InputService5TestCaseOperation1Request(input)
output = out
err = req.Send()
return
err := req.Send()
return out, err
}
var opInputService5TestCaseOperation1 *aws.Operation
......@@ -463,10 +439,6 @@ type InputService6ProtocolTest struct {
// New returns a new InputService6ProtocolTest client.
func NewInputService6ProtocolTest(config *aws.Config) *InputService6ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice6protocoltest",
......@@ -511,11 +483,10 @@ func (c *InputService6ProtocolTest) InputService6TestCaseOperation1Request(input
return
}
func (c *InputService6ProtocolTest) InputService6TestCaseOperation1(input *InputService6TestShapeInputShape) (output *InputService6TestShapeInputService6TestCaseOperation1Output, err error) {
func (c *InputService6ProtocolTest) InputService6TestCaseOperation1(input *InputService6TestShapeInputShape) (*InputService6TestShapeInputService6TestCaseOperation1Output, error) {
req, out := c.InputService6TestCaseOperation1Request(input)
output = out
err = req.Send()
return
err := req.Send()
return out, err
}
var opInputService6TestCaseOperation1 *aws.Operation
......@@ -545,10 +516,6 @@ type InputService7ProtocolTest struct {
// New returns a new InputService7ProtocolTest client.
func NewInputService7ProtocolTest(config *aws.Config) *InputService7ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice7protocoltest",
......@@ -593,11 +560,10 @@ func (c *InputService7ProtocolTest) InputService7TestCaseOperation1Request(input
return
}
func (c *InputService7ProtocolTest) InputService7TestCaseOperation1(input *InputService7TestShapeInputShape) (output *InputService7TestShapeInputService7TestCaseOperation1Output, err error) {
func (c *InputService7ProtocolTest) InputService7TestCaseOperation1(input *InputService7TestShapeInputShape) (*InputService7TestShapeInputService7TestCaseOperation1Output, error) {
req, out := c.InputService7TestCaseOperation1Request(input)
output = out
err = req.Send()
return
err := req.Send()
return out, err
}
var opInputService7TestCaseOperation1 *aws.Operation
......@@ -627,10 +593,6 @@ type InputService8ProtocolTest struct {
// New returns a new InputService8ProtocolTest client.
func NewInputService8ProtocolTest(config *aws.Config) *InputService8ProtocolTest {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice8protocoltest",
......@@ -675,11 +637,10 @@ func (c *InputService8ProtocolTest) InputService8TestCaseOperation1Request(input
return
}
func (c *InputService8ProtocolTest) InputService8TestCaseOperation1(input *InputService8TestShapeInputShape) (output *InputService8TestShapeInputService8TestCaseOperation1Output, err error) {
func (c *InputService8ProtocolTest) InputService8TestCaseOperation1(input *InputService8TestShapeInputShape) (*InputService8TestShapeInputService8TestCaseOperation1Output, error) {
req, out := c.InputService8TestCaseOperation1Request(input)
output = out
err = req.Send()
return
err := req.Send()
return out, err
}
var opInputService8TestCaseOperation1 *aws.Operation
......@@ -930,4 +891,3 @@ func TestInputService8ProtocolTestTimestampValuesCase1(t *testing.T) {
// assert headers
}
......@@ -6,8 +6,9 @@ import (
"encoding/xml"
"io"
"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/protocol/xml/xmlutil"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/apierr"
"github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil"
)
// Unmarshal unmarshals a response body for the EC2 protocol.
......@@ -17,7 +18,7 @@ func Unmarshal(r *aws.Request) {
decoder := xml.NewDecoder(r.HTTPResponse.Body)
err := xmlutil.UnmarshalXML(r.Data, decoder, "")
if err != nil {
r.Error = err
r.Error = apierr.New("Unmarshal", "failed decoding EC2 Query response", err)
return
}
}
......@@ -42,12 +43,12 @@ func UnmarshalError(r *aws.Request) {
resp := &xmlErrorResponse{}
err := xml.NewDecoder(r.HTTPResponse.Body).Decode(resp)
if err != nil && err != io.EOF {
r.Error = err
r.Error = apierr.New("Unmarshal", "failed decoding EC2 Query error response", err)
} else {
r.Error = aws.APIError{
StatusCode: r.HTTPResponse.StatusCode,
Code: resp.Code,
Message: resp.Message,
}
r.Error = apierr.NewRequestError(
apierr.New(resp.Code, resp.Message, nil),
r.HTTPResponse.StatusCode,
resp.RequestID,
)
}
}
// Package query provides serialisation of AWS query requests, and responses.
package query
//go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/input/query.json build_test.go
......@@ -5,8 +6,9 @@ package query
import (
"net/url"
"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/protocol/query/queryutil"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/apierr"
"github.com/aws/aws-sdk-go/internal/protocol/query/queryutil"
)
// Build builds a request for an AWS Query service.
......@@ -16,7 +18,7 @@ func Build(r *aws.Request) {
"Version": {r.Service.APIVersion},
}
if err := queryutil.Parse(body, r.Params, false); err != nil {
r.Error = err
r.Error = apierr.New("Marshal", "failed encoding Query request", err)
return
}
......
......@@ -5,8 +5,9 @@ package query
import (
"encoding/xml"
"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/protocol/xml/xmlutil"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/apierr"
"github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil"
)
// Unmarshal unmarshals a response for an AWS Query service.
......@@ -16,7 +17,7 @@ func Unmarshal(r *aws.Request) {
decoder := xml.NewDecoder(r.HTTPResponse.Body)
err := xmlutil.UnmarshalXML(r.Data, decoder, r.Operation.Name+"Result")
if err != nil {
r.Error = err
r.Error = apierr.New("Unmarshal", "failed decoding Query response", err)
return
}
}
......
......@@ -4,7 +4,8 @@ import (
"encoding/xml"
"io"
"github.com/awslabs/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/apierr"
)
type xmlErrorResponse struct {
......@@ -21,12 +22,12 @@ func UnmarshalError(r *aws.Request) {
resp := &xmlErrorResponse{}
err := xml.NewDecoder(r.HTTPResponse.Body).Decode(resp)
if err != nil && err != io.EOF {
r.Error = err
r.Error = apierr.New("Unmarshal", "failed to decode query XML error response", err)
} else {
r.Error = aws.APIError{
StatusCode: r.HTTPResponse.StatusCode,
Code: resp.Code,
Message: resp.Message,
}
r.Error = apierr.NewRequestError(
apierr.New(resp.Code, resp.Message, nil),
r.HTTPResponse.StatusCode,
resp.RequestID,
)
}
}
// Package rest provides RESTful serialisation of AWS requests and responses.
package rest
import (
"bytes"
"encoding/base64"
"fmt"
"io"
"net/url"
"path"
"reflect"
"strconv"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/apierr"
)
// 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
func init() {
for i := 0; i < len(noEscape); i++ {
// AWS expects every character except these to be escaped
noEscape[i] = (i >= 'A' && i <= 'Z') ||
(i >= 'a' && i <= 'z') ||
(i >= '0' && i <= '9') ||
i == '-' ||
i == '.' ||
i == '_' ||
i == '~'
}
}
// Build builds the REST component of a service request.
func Build(r *aws.Request) {
if r.ParamsFilled() {
v := reflect.ValueOf(r.Params).Elem()
buildLocationElements(r, v)
buildBody(r, v)
}
}
func buildLocationElements(r *aws.Request, v reflect.Value) {
query := r.HTTPRequest.URL.Query()
for i := 0; i < v.NumField(); i++ {
m := v.Field(i)
if n := v.Type().Field(i).Name; n[0:1] == strings.ToLower(n[0:1]) {
continue
}
if m.IsValid() {
field := v.Type().Field(i)
name := field.Tag.Get("locationName")
if name == "" {
name = field.Name
}
if m.Kind() == reflect.Ptr {
m = m.Elem()
}
if !m.IsValid() {
continue
}
switch field.Tag.Get("location") {
case "headers": // header maps
buildHeaderMap(r, m, field.Tag.Get("locationName"))
case "header":
buildHeader(r, m, name)
case "uri":
buildURI(r, m, name)
case "querystring":
buildQueryString(r, m, name, query)
}
}
if r.Error != nil {
return
}
}
r.HTTPRequest.URL.RawQuery = query.Encode()
updatePath(r.HTTPRequest.URL, r.HTTPRequest.URL.Path)
}
func buildBody(r *aws.Request, v reflect.Value) {
if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
if payloadName := field.Tag.Get("payload"); payloadName != "" {
pfield, _ := v.Type().FieldByName(payloadName)
if ptag := pfield.Tag.Get("type"); ptag != "" && ptag != "structure" {
payload := reflect.Indirect(v.FieldByName(payloadName))
if payload.IsValid() && payload.Interface() != nil {
switch reader := payload.Interface().(type) {
case io.ReadSeeker:
r.SetReaderBody(reader)
case []byte:
r.SetBufferBody(reader)
case string:
r.SetStringBody(reader)
default:
r.Error = apierr.New("Marshal",
"failed to encode REST request",
fmt.Errorf("unknown payload type %s", payload.Type()))
}
}
}
}
}
}
func buildHeader(r *aws.Request, v reflect.Value, name string) {
str, err := convertType(v)
if err != nil {
r.Error = apierr.New("Marshal", "failed to encode REST request", err)
} else if str != nil {
r.HTTPRequest.Header.Add(name, *str)
}
}
func buildHeaderMap(r *aws.Request, v reflect.Value, prefix string) {
for _, key := range v.MapKeys() {
str, err := convertType(v.MapIndex(key))
if err != nil {
r.Error = apierr.New("Marshal", "failed to encode REST request", err)
} else if str != nil {
r.HTTPRequest.Header.Add(prefix+key.String(), *str)
}
}
}
func buildURI(r *aws.Request, v reflect.Value, name string) {
value, err := convertType(v)
if err != nil {
r.Error = apierr.New("Marshal", "failed to encode REST request", err)
} else if value != nil {
uri := r.HTTPRequest.URL.Path
uri = strings.Replace(uri, "{"+name+"}", EscapePath(*value, true), -1)
uri = strings.Replace(uri, "{"+name+"+}", EscapePath(*value, false), -1)
r.HTTPRequest.URL.Path = uri
}
}
func buildQueryString(r *aws.Request, v reflect.Value, name string, query url.Values) {
str, err := convertType(v)
if err != nil {
r.Error = apierr.New("Marshal", "failed to encode REST request", err)
} else if str != nil {
query.Set(name, *str)
}
}
func updatePath(url *url.URL, urlPath string) {
scheme, query := url.Scheme, url.RawQuery
// clean up path
urlPath = path.Clean(urlPath)
// get formatted URL minus scheme so we can build this into Opaque
url.Scheme, url.Path, url.RawQuery = "", "", ""
s := url.String()
url.Scheme = scheme
url.RawQuery = query
// build opaque URI
url.Opaque = s + urlPath
}
// EscapePath escapes part of a URL path in Amazon style
func EscapePath(path string, encodeSep bool) string {
var buf bytes.Buffer
for i := 0; i < len(path); i++ {
c := path[i]
if noEscape[c] || (c == '/' && !encodeSep) {
buf.WriteByte(c)
} else {
buf.WriteByte('%')
buf.WriteString(strings.ToUpper(strconv.FormatUint(uint64(c), 16)))
}
}
return buf.String()
}
func convertType(v reflect.Value) (*string, error) {
v = reflect.Indirect(v)
if !v.IsValid() {
return nil, nil
}
var str string
switch value := v.Interface().(type) {
case string:
str = value
case []byte:
str = base64.StdEncoding.EncodeToString(value)
case bool:
str = strconv.FormatBool(value)
case int64:
str = strconv.FormatInt(value, 10)
case float64:
str = strconv.FormatFloat(value, 'f', -1, 64)
case time.Time:
str = value.UTC().Format(RFC822)
default:
err := fmt.Errorf("Unsupported value for param %v (%s)", v.Interface(), v.Type())
return nil, err
}
return &str, nil
}
package rest
import "reflect"
// PayloadMember returns the payload field member of i if there is one, or nil.
func PayloadMember(i interface{}) interface{} {
if i == nil {
return nil
}
v := reflect.ValueOf(i).Elem()
if !v.IsValid() {
return nil
}
if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
if payloadName := field.Tag.Get("payload"); payloadName != "" {
field, _ := v.Type().FieldByName(payloadName)
if field.Tag.Get("type") != "structure" {
return nil
}
payload := v.FieldByName(payloadName)
if payload.IsValid() || (payload.Kind() == reflect.Ptr && !payload.IsNil()) {
return payload.Interface()
}
}
}
return nil
}
// PayloadType returns the type of a payload field member of i if there is one, or "".
func PayloadType(i interface{}) string {
v := reflect.Indirect(reflect.ValueOf(i))
if !v.IsValid() {
return ""
}
if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
if payloadName := field.Tag.Get("payload"); payloadName != "" {
if member, ok := v.Type().FieldByName(payloadName); ok {
return member.Tag.Get("type")
}
}
}
return ""
}
package rest
import (
"encoding/base64"
"fmt"
"io/ioutil"
"net/http"
"reflect"
"strconv"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/apierr"
)
// Unmarshal unmarshals the REST component of a response in a REST service.
func Unmarshal(r *aws.Request) {
if r.DataFilled() {
v := reflect.Indirect(reflect.ValueOf(r.Data))
unmarshalBody(r, v)
unmarshalLocationElements(r, v)
}
}
func unmarshalBody(r *aws.Request, v reflect.Value) {
if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
if payloadName := field.Tag.Get("payload"); payloadName != "" {
pfield, _ := v.Type().FieldByName(payloadName)
if ptag := pfield.Tag.Get("type"); ptag != "" && ptag != "structure" {
payload := v.FieldByName(payloadName)
if payload.IsValid() {
switch payload.Interface().(type) {
case []byte:
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil {
r.Error = apierr.New("Unmarshal", "failed to decode REST response", err)
} else {
payload.Set(reflect.ValueOf(b))
}
case *string:
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil {
r.Error = apierr.New("Unmarshal", "failed to decode REST response", err)
} else {
str := string(b)
payload.Set(reflect.ValueOf(&str))
}
default:
switch payload.Type().String() {
case "io.ReadSeeker":
payload.Set(reflect.ValueOf(aws.ReadSeekCloser(r.HTTPResponse.Body)))
case "aws.ReadSeekCloser", "io.ReadCloser":
payload.Set(reflect.ValueOf(r.HTTPResponse.Body))
default:
r.Error = apierr.New("Unmarshal",
"failed to decode REST response",
fmt.Errorf("unknown payload type %s", payload.Type()))
}
}
}
}
}
}
}
func unmarshalLocationElements(r *aws.Request, v reflect.Value) {
for i := 0; i < v.NumField(); i++ {
m, field := v.Field(i), v.Type().Field(i)
if n := field.Name; n[0:1] == strings.ToLower(n[0:1]) {
continue
}
if m.IsValid() {
name := field.Tag.Get("locationName")
if name == "" {
name = field.Name
}
switch field.Tag.Get("location") {
case "statusCode":
unmarshalStatusCode(m, r.HTTPResponse.StatusCode)
case "header":
err := unmarshalHeader(m, r.HTTPResponse.Header.Get(name))
if err != nil {
r.Error = apierr.New("Unmarshal", "failed to decode REST response", err)
break
}
case "headers":
prefix := field.Tag.Get("locationName")
err := unmarshalHeaderMap(m, r.HTTPResponse.Header, prefix)
if err != nil {
r.Error = apierr.New("Unmarshal", "failed to decode REST response", err)
break
}
}
}
if r.Error != nil {
return
}
}
}
func unmarshalStatusCode(v reflect.Value, statusCode int) {
if !v.IsValid() {
return
}
switch v.Interface().(type) {
case *int64:
s := int64(statusCode)
v.Set(reflect.ValueOf(&s))
}
}
func unmarshalHeaderMap(r reflect.Value, headers http.Header, prefix string) error {
switch r.Interface().(type) {
case map[string]*string: // we only support string map value types
out := map[string]*string{}
for k, v := range headers {
k = http.CanonicalHeaderKey(k)
if strings.HasPrefix(strings.ToLower(k), strings.ToLower(prefix)) {
out[k[len(prefix):]] = &v[0]
}
}
r.Set(reflect.ValueOf(out))
}
return nil
}
func unmarshalHeader(v reflect.Value, header string) error {
if !v.IsValid() || (header == "" && v.Elem().Kind() != reflect.String) {
return nil
}
switch v.Interface().(type) {
case *string:
v.Set(reflect.ValueOf(&header))
case []byte:
b, err := base64.StdEncoding.DecodeString(header)
if err != nil {
return err
}
v.Set(reflect.ValueOf(&b))
case *bool:
b, err := strconv.ParseBool(header)
if err != nil {
return err
}
v.Set(reflect.ValueOf(&b))
case *int64:
i, err := strconv.ParseInt(header, 10, 64)
if err != nil {
return err
}
v.Set(reflect.ValueOf(&i))
case *float64:
f, err := strconv.ParseFloat(header, 64)
if err != nil {
return err
}
v.Set(reflect.ValueOf(&f))
case *time.Time:
t, err := time.Parse(RFC822, header)
if err != nil {
return err
}
v.Set(reflect.ValueOf(&t))
default:
err := fmt.Errorf("Unsupported value for param %v (%s)", v.Interface(), v.Type())
return err
}
return nil
}
......@@ -172,15 +172,8 @@ func parseList(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
// parseMap deserializes a map from an XMLNode. The direct children of the XMLNode
// will also be deserialized as map entries.
func parseMap(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
t := r.Type()
if r.Kind() == reflect.Ptr {
t = t.Elem()
if r.IsNil() {
r.Set(reflect.New(t))
r.Elem().Set(reflect.MakeMap(t))
}
r = r.Elem()
if r.IsNil() {
r.Set(reflect.MakeMap(r.Type()))
}
if tag.Get("flattened") == "" { // look at all child entries
......
// +build !integration
package v4_test
import (
......@@ -7,9 +5,9 @@ import (
"testing"
"time"
"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/test/unit"
"github.com/awslabs/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/test/unit"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/stretchr/testify/assert"
)
......
// Package v4 implements signing for AWS V4 signer
package v4
import (
......@@ -13,9 +14,10 @@ import (
"strings"
"time"
"github.com/awslabs/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/internal/protocol/rest"
"github.com/awslabs/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws"
)
const (
......@@ -243,6 +245,10 @@ func (v4 *signer) buildCanonicalString() {
uri = "/"
}
if v4.ServiceName != "s3" {
uri = rest.EscapePath(uri, false)
}
v4.canonicalString = strings.Join([]string{
v4.Request.Method,
uri,
......
......@@ -6,8 +6,8 @@ import (
"testing"
"time"
"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/stretchr/testify/assert"
)
......@@ -54,7 +54,7 @@ func TestPresignRequest(t *testing.T) {
expectedDate := "19700101T000000Z"
expectedHeaders := "host;x-amz-meta-other-header;x-amz-target"
expectedSig := "4c86bacebb78e458e8e898e93547513079d67ab95d3d5c02236889e21ea0df2b"
expectedSig := "5eeedebf6f995145ce56daa02902d10485246d3defb34f97b973c1f40ab82d36"
expectedCred := "AKID/19700101/us-east-1/dynamodb/aws4_request"
q := signer.Request.URL.Query()
......@@ -69,7 +69,7 @@ func TestSignRequest(t *testing.T) {
signer.sign()
expectedDate := "19700101T000000Z"
expectedSig := "AWS4-HMAC-SHA256 Credential=AKID/19700101/us-east-1/dynamodb/aws4_request, SignedHeaders=host;x-amz-date;x-amz-meta-other-header;x-amz-security-token;x-amz-target, Signature=d4df864b291252d2c9206be75963db54db09ca70265622cc787cbe50ca0efcc8"
expectedSig := "AWS4-HMAC-SHA256 Credential=AKID/19700101/us-east-1/dynamodb/aws4_request, SignedHeaders=host;x-amz-date;x-amz-meta-other-header;x-amz-security-token;x-amz-target, Signature=69ada33fec48180dab153576e4dd80c4e04124f80dda3eccfed8a67c2b91ed5e"
q := signer.Request.Header
assert.Equal(t, expectedSig, q.Get("Authorization"))
......
......@@ -3,8 +3,8 @@ package ec2
import (
"time"
"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/aws/awsutil"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awsutil"
)
func init() {
......
// +build !integration
package ec2_test
import (
......@@ -7,9 +5,9 @@ import (
"net/url"
"testing"
"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/test/unit"
"github.com/awslabs/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/test/unit"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/stretchr/testify/assert"
)
......
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
// Package ec2iface provides an interface for the Amazon Elastic Compute Cloud.
package ec2iface
import (
"github.com/awslabs/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ec2"
)
// EC2API is the interface type for ec2.EC2.
type EC2API interface {
AcceptVPCPeeringConnection(*ec2.AcceptVPCPeeringConnectionInput) (*ec2.AcceptVPCPeeringConnectionOutput, error)
......@@ -43,6 +47,8 @@ type EC2API interface {
CancelReservedInstancesListing(*ec2.CancelReservedInstancesListingInput) (*ec2.CancelReservedInstancesListingOutput, error)
CancelSpotFleetRequests(*ec2.CancelSpotFleetRequestsInput) (*ec2.CancelSpotFleetRequestsOutput, error)
CancelSpotInstanceRequests(*ec2.CancelSpotInstanceRequestsInput) (*ec2.CancelSpotInstanceRequestsOutput, error)
ConfirmProductInstance(*ec2.ConfirmProductInstanceInput) (*ec2.ConfirmProductInstanceOutput, error)
......@@ -89,6 +95,8 @@ type EC2API interface {
CreateVPC(*ec2.CreateVPCInput) (*ec2.CreateVPCOutput, error)
CreateVPCEndpoint(*ec2.CreateVPCEndpointInput) (*ec2.CreateVPCEndpointOutput, error)
CreateVPCPeeringConnection(*ec2.CreateVPCPeeringConnectionInput) (*ec2.CreateVPCPeeringConnectionOutput, error)
CreateVPNConnection(*ec2.CreateVPNConnectionInput) (*ec2.CreateVPNConnectionOutput, error)
......@@ -131,6 +139,8 @@ type EC2API interface {
DeleteVPC(*ec2.DeleteVPCInput) (*ec2.DeleteVPCOutput, error)
DeleteVPCEndpoints(*ec2.DeleteVPCEndpointsInput) (*ec2.DeleteVPCEndpointsOutput, error)
DeleteVPCPeeringConnection(*ec2.DeleteVPCPeeringConnectionInput) (*ec2.DeleteVPCPeeringConnectionOutput, error)
DeleteVPNConnection(*ec2.DeleteVPNConnectionInput) (*ec2.DeleteVPNConnectionOutput, error)
......@@ -179,6 +189,8 @@ type EC2API interface {
DescribeKeyPairs(*ec2.DescribeKeyPairsInput) (*ec2.DescribeKeyPairsOutput, error)
DescribeMovingAddresses(*ec2.DescribeMovingAddressesInput) (*ec2.DescribeMovingAddressesOutput, error)
DescribeNetworkACLs(*ec2.DescribeNetworkACLsInput) (*ec2.DescribeNetworkACLsOutput, error)
DescribeNetworkInterfaceAttribute(*ec2.DescribeNetworkInterfaceAttributeInput) (*ec2.DescribeNetworkInterfaceAttributeOutput, error)
......@@ -187,6 +199,8 @@ type EC2API interface {
DescribePlacementGroups(*ec2.DescribePlacementGroupsInput) (*ec2.DescribePlacementGroupsOutput, error)
DescribePrefixLists(*ec2.DescribePrefixListsInput) (*ec2.DescribePrefixListsOutput, error)
DescribeRegions(*ec2.DescribeRegionsInput) (*ec2.DescribeRegionsOutput, error)
DescribeReservedInstances(*ec2.DescribeReservedInstancesInput) (*ec2.DescribeReservedInstancesOutput, error)
......@@ -207,6 +221,12 @@ type EC2API interface {
DescribeSpotDatafeedSubscription(*ec2.DescribeSpotDatafeedSubscriptionInput) (*ec2.DescribeSpotDatafeedSubscriptionOutput, error)
DescribeSpotFleetInstances(*ec2.DescribeSpotFleetInstancesInput) (*ec2.DescribeSpotFleetInstancesOutput, error)
DescribeSpotFleetRequestHistory(*ec2.DescribeSpotFleetRequestHistoryInput) (*ec2.DescribeSpotFleetRequestHistoryOutput, error)
DescribeSpotFleetRequests(*ec2.DescribeSpotFleetRequestsInput) (*ec2.DescribeSpotFleetRequestsOutput, error)
DescribeSpotInstanceRequests(*ec2.DescribeSpotInstanceRequestsInput) (*ec2.DescribeSpotInstanceRequestsOutput, error)
DescribeSpotPriceHistory(*ec2.DescribeSpotPriceHistoryInput) (*ec2.DescribeSpotPriceHistoryOutput, error)
......@@ -219,6 +239,10 @@ type EC2API interface {
DescribeVPCClassicLink(*ec2.DescribeVPCClassicLinkInput) (*ec2.DescribeVPCClassicLinkOutput, error)
DescribeVPCEndpointServices(*ec2.DescribeVPCEndpointServicesInput) (*ec2.DescribeVPCEndpointServicesOutput, error)
DescribeVPCEndpoints(*ec2.DescribeVPCEndpointsInput) (*ec2.DescribeVPCEndpointsOutput, error)
DescribeVPCPeeringConnections(*ec2.DescribeVPCPeeringConnectionsInput) (*ec2.DescribeVPCPeeringConnectionsOutput, error)
DescribeVPCs(*ec2.DescribeVPCsInput) (*ec2.DescribeVPCsOutput, error)
......@@ -285,10 +309,14 @@ type EC2API interface {
ModifyVPCAttribute(*ec2.ModifyVPCAttributeInput) (*ec2.ModifyVPCAttributeOutput, error)
ModifyVPCEndpoint(*ec2.ModifyVPCEndpointInput) (*ec2.ModifyVPCEndpointOutput, error)
ModifyVolumeAttribute(*ec2.ModifyVolumeAttributeInput) (*ec2.ModifyVolumeAttributeOutput, error)
MonitorInstances(*ec2.MonitorInstancesInput) (*ec2.MonitorInstancesOutput, error)
MoveAddressToVPC(*ec2.MoveAddressToVPCInput) (*ec2.MoveAddressToVPCOutput, error)
PurchaseReservedInstancesOffering(*ec2.PurchaseReservedInstancesOfferingInput) (*ec2.PurchaseReservedInstancesOfferingOutput, error)
RebootInstances(*ec2.RebootInstancesInput) (*ec2.RebootInstancesOutput, error)
......@@ -309,6 +337,8 @@ type EC2API interface {
ReportInstanceStatus(*ec2.ReportInstanceStatusInput) (*ec2.ReportInstanceStatusOutput, error)
RequestSpotFleet(*ec2.RequestSpotFleetInput) (*ec2.RequestSpotFleetOutput, error)
RequestSpotInstances(*ec2.RequestSpotInstancesInput) (*ec2.RequestSpotInstancesOutput, error)
ResetImageAttribute(*ec2.ResetImageAttributeInput) (*ec2.ResetImageAttributeOutput, error)
......@@ -319,6 +349,8 @@ type EC2API interface {
ResetSnapshotAttribute(*ec2.ResetSnapshotAttributeInput) (*ec2.ResetSnapshotAttributeOutput, error)
RestoreAddressToClassic(*ec2.RestoreAddressToClassicInput) (*ec2.RestoreAddressToClassicOutput, error)
RevokeSecurityGroupEgress(*ec2.RevokeSecurityGroupEgressInput) (*ec2.RevokeSecurityGroupEgressOutput, error)
RevokeSecurityGroupIngress(*ec2.RevokeSecurityGroupIngressInput) (*ec2.RevokeSecurityGroupIngressOutput, error)
......
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
package ec2iface_test
import (
"testing"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
"github.com/stretchr/testify/assert"
)
func TestInterface(t *testing.T) {
assert.Implements(t, (*ec2iface.EC2API)(nil), ec2.New(nil))
}
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
package ec2
import (
"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/protocol/ec2query"
"github.com/awslabs/aws-sdk-go/internal/signer/v4"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/protocol/ec2query"
"github.com/aws/aws-sdk-go/internal/signer/v4"
)
// EC2 is a client for Amazon EC2.
......@@ -19,14 +21,10 @@ var initRequest func(*aws.Request)
// New returns a new EC2 client.
func New(config *aws.Config) *EC2 {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "ec2",
APIVersion: "2015-03-01",
APIVersion: "2015-04-15",
}
service.Initialize()
......
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
// Package elbiface provides an interface for the Elastic Load Balancing.
package elbiface
import (
"github.com/awslabs/aws-sdk-go/service/elb"
"github.com/aws/aws-sdk-go/service/elb"
)
// ELBAPI is the interface type for elb.ELB.
type ELBAPI interface {
AddTags(*elb.AddTagsInput) (*elb.AddTagsOutput, error)
......
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
package elbiface_test
import (
"testing"
"github.com/aws/aws-sdk-go/service/elb"
"github.com/aws/aws-sdk-go/service/elb/elbiface"
"github.com/stretchr/testify/assert"
)
func TestInterface(t *testing.T) {
assert.Implements(t, (*elbiface.ELBAPI)(nil), elb.New(nil))
}
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
package elb
import (
"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/protocol/query"
"github.com/awslabs/aws-sdk-go/internal/signer/v4"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/protocol/query"
"github.com/aws/aws-sdk-go/internal/signer/v4"
)
// ELB is a client for Elastic Load Balancing.
......@@ -19,10 +21,6 @@ var initRequest func(*aws.Request)
// New returns a new ELB client.
func New(config *aws.Config) *ELB {
if config == nil {
config = &aws.Config{}
}
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "elasticloadbalancing",
......
package aws
// An APIError is an error returned by an AWS API.
type APIError struct {
StatusCode int // HTTP status code e.g. 200
Code string
Message string
RequestID string
}
// Error returns the error as a string. Satisfies error interface.
func (e APIError) Error() string {
return e.Code + ": " + e.Message
}
// Error returns an APIError pointer if the error e is an APIError type.
// If the error is not an APIError nil will be returned.
func Error(e error) *APIError {
if err, ok := e.(*APIError); ok {
return err
} else if err, ok := e.(APIError); ok {
return &err
} else {
return nil
}
}
// +build integration
package ec2_test
import (
"testing"
"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/internal/test/integration"
"github.com/awslabs/aws-sdk-go/internal/util/utilassert"
"github.com/awslabs/aws-sdk-go/service/ec2"
"github.com/stretchr/testify/assert"
)
var (
_ = assert.Equal
_ = utilassert.Match
_ = integration.Imported
)
func TestMakingABasicRequest(t *testing.T) {
client := ec2.New(nil)
resp, e := client.DescribeRegions(&ec2.DescribeRegionsInput{})
err := aws.Error(e)
_, _, _ = resp, e, err // avoid unused warnings
assert.NoError(t, nil, err)
}
func TestErrorHandling(t *testing.T) {
client := ec2.New(nil)
resp, e := client.DescribeInstances(&ec2.DescribeInstancesInput{
InstanceIDs: []*string{
aws.String("i-12345678"),
},
})
err := aws.Error(e)
_, _, _ = resp, e, err // avoid unused warnings
assert.NotEqual(t, nil, err)
assert.Equal(t, "InvalidInstanceID.NotFound", err.Code)
utilassert.Match(t, "The instance ID 'i-12345678' does not exist", err.Message)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment