* update github.com/aws/aws-sdk-go to v1.30.9

* deps: github.com/aws/aws-sdk-go@v1.30.12

Reference: https://github.com/hashicorp/terraform/issues/24710
Reference: https://github.com/hashicorp/terraform/issues/24741

Changes:

```
NOTES:

* backend/s3: Region validation now automatically supports the new `af-south-1` (Africa (Cape Town)) region. For AWS operations to work in the new region, the region must be explicitly enabled as outlined in the [AWS Documentation](https://docs.aws.amazon.com/general/latest/gr/rande-manage.html#rande-manage-enable). When the region is not enabled, the Terraform S3 Backend will return errors during credential validation (e.g. `error validating provider credentials: error calling sts:GetCallerIdentity: InvalidClientTokenId: The security token included in the request is invalid`).

ENHANCEMENTS:

* backend/s3: Support automatic region validation for `af-south-1`
```

Updated via:

```console
$ go get github.com/aws/aws-sdk-go@v1.30.12
$ go mod tidy
$ go mod vendor
```

Output from acceptance testing:

```console
$ TF_ACC=1 go test -v ./backend/remote-state/s3 | grep '^--- '
--- PASS: TestBackend_impl (0.00s)
--- PASS: TestBackendConfig (1.68s)
--- PASS: TestBackendConfig_invalidKey (0.00s)
--- PASS: TestBackendConfig_invalidSSECustomerKeyLength (0.00s)
--- PASS: TestBackendConfig_invalidSSECustomerKeyEncoding (0.00s)
--- PASS: TestBackendConfig_conflictingEncryptionSchema (0.00s)
--- PASS: TestBackend (15.07s)
--- PASS: TestBackendLocked (26.40s)
--- PASS: TestBackendSSECustomerKey (16.99s)
--- PASS: TestBackendExtraPaths (12.05s)
--- PASS: TestBackendPrefixInWorkspace (5.55s)
--- PASS: TestKeyEnv (45.07s)
--- PASS: TestRemoteClient_impl (0.00s)
--- PASS: TestRemoteClient (5.39s)
--- PASS: TestRemoteClientLocks (14.30s)
--- PASS: TestForceUnlock (20.08s)
--- PASS: TestRemoteClient_clientMD5 (16.43s)
--- PASS: TestRemoteClient_stateChecksum (24.58s)
```

Co-authored-by: Nicola Senno <nicola.senno@workday.com>
This commit is contained in:
Brian Flad 2020-04-24 12:20:04 -04:00 committed by GitHub
parent 7d494b1b03
commit 2681ccf87f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
117 changed files with 23749 additions and 3037 deletions

8
go.mod
View File

@ -18,7 +18,7 @@ require (
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect
github.com/armon/go-radix v1.0.0 // indirect github.com/armon/go-radix v1.0.0 // indirect
github.com/aws/aws-sdk-go v1.25.3 github.com/aws/aws-sdk-go v1.30.12
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
github.com/blang/semver v3.5.1+incompatible github.com/blang/semver v3.5.1+incompatible
github.com/bmatcuk/doublestar v1.1.5 github.com/bmatcuk/doublestar v1.1.5
@ -76,7 +76,7 @@ require (
github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7 github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7
github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596 github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596
github.com/hashicorp/vault v0.10.4 github.com/hashicorp/vault v0.10.4
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af github.com/jmespath/go-jmespath v0.3.0
github.com/jonboulle/clockwork v0.1.0 // indirect github.com/jonboulle/clockwork v0.1.0 // indirect
github.com/joyent/triton-go v0.0.0-20180313100802-d8f9c0314926 github.com/joyent/triton-go v0.0.0-20180313100802-d8f9c0314926
github.com/json-iterator/go v1.1.5 // indirect github.com/json-iterator/go v1.1.5 // indirect
@ -106,7 +106,7 @@ require (
github.com/packer-community/winrmcp v0.0.0-20180102160824-81144009af58 github.com/packer-community/winrmcp v0.0.0-20180102160824-81144009af58
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c // indirect github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c // indirect
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4
github.com/pkg/errors v0.8.0 github.com/pkg/errors v0.9.1
github.com/posener/complete v1.2.1 github.com/posener/complete v1.2.1
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 // indirect github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 // indirect
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
@ -130,7 +130,7 @@ require (
go.uber.org/zap v1.9.1 // indirect go.uber.org/zap v1.9.1 // indirect
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/mod v0.2.0 golang.org/x/mod v0.2.0
golang.org/x/net v0.0.0-20191009170851-d66e71096ffb golang.org/x/net v0.0.0-20200202094626-16171245cfb2
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e

15
go.sum
View File

@ -86,6 +86,8 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI
github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
github.com/aws/aws-sdk-go v1.25.3 h1:uM16hIw9BotjZKMZlX05SN2EFtaWfi/NonPKIARiBLQ= github.com/aws/aws-sdk-go v1.25.3 h1:uM16hIw9BotjZKMZlX05SN2EFtaWfi/NonPKIARiBLQ=
github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.30.12 h1:KrjyosZvkpJjcwMk0RNxMZewQ47v7+ZkbQDXjWsJMs8=
github.com/aws/aws-sdk-go v1.30.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
@ -137,6 +139,7 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
@ -244,8 +247,6 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f h1:UdxlrJz4JOnY8W+DbLISwf2B8WXEolNRA8BGCwI9jws= github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f h1:UdxlrJz4JOnY8W+DbLISwf2B8WXEolNRA8BGCwI9jws=
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90= github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90=
github.com/hashicorp/hcl/v2 v2.3.0 h1:iRly8YaMwTBAKhn1Ybk7VSdzbnopghktCD031P8ggUE=
github.com/hashicorp/hcl/v2 v2.3.0/go.mod h1:d+FwDBbOLvpAM3Z6J7gPj/VoAGkNe/gm352ZhjJ/Zv8=
github.com/hashicorp/hcl/v2 v2.4.0 h1:xwVa1aj4nCSoAjUnFPBAIfqlzPgSZEVMdkJv/mgj4jY= github.com/hashicorp/hcl/v2 v2.4.0 h1:xwVa1aj4nCSoAjUnFPBAIfqlzPgSZEVMdkJv/mgj4jY=
github.com/hashicorp/hcl/v2 v2.4.0/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY= github.com/hashicorp/hcl/v2 v2.4.0/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY=
github.com/hashicorp/hil v0.0.0-20190212112733-ab17b08d6590 h1:2yzhWGdgQUWZUCNK+AoO35V+HTsgEmcM4J9IkArh7PI= github.com/hashicorp/hil v0.0.0-20190212112733-ab17b08d6590 h1:2yzhWGdgQUWZUCNK+AoO35V+HTsgEmcM4J9IkArh7PI=
@ -265,6 +266,8 @@ github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKe
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/joyent/triton-go v0.0.0-20180313100802-d8f9c0314926 h1:kie3qOosvRKqwij2HGzXWffwpXvcqfPPXRUw8I4F/mg= github.com/joyent/triton-go v0.0.0-20180313100802-d8f9c0314926 h1:kie3qOosvRKqwij2HGzXWffwpXvcqfPPXRUw8I4F/mg=
@ -366,6 +369,8 @@ github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7T
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
@ -409,6 +414,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d h1:Z4EH+5EffvBEhh37F0C0DnpklTMh00JOkjW5zK3ofBI= github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d h1:Z4EH+5EffvBEhh37F0C0DnpklTMh00JOkjW5zK3ofBI=
github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d/go.mod h1:BSTlc8jOjh0niykqEGVXOLXdi9o0r0kR8tCYiMvjFgw= github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d/go.mod h1:BSTlc8jOjh0niykqEGVXOLXdi9o0r0kR8tCYiMvjFgw=
github.com/tencentcloud/tencentcloud-sdk-go v3.0.82+incompatible h1:5Td2b0yfaOvw9M9nZ5Oav6Li9bxUNxt4DgxMfIPpsa0= github.com/tencentcloud/tencentcloud-sdk-go v3.0.82+incompatible h1:5Td2b0yfaOvw9M9nZ5Oav6Li9bxUNxt4DgxMfIPpsa0=
@ -437,8 +444,6 @@ github.com/zclconf/go-cty v1.1.0 h1:uJwc9HiBOCpoKIObTQaLR+tsEXx1HBHnOsOOpcdhZgw=
github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zclconf/go-cty v1.2.0 h1:sPHsy7ADcIZQP3vILvTjrh74ZA175TFP5vqiNK1UmlI= github.com/zclconf/go-cty v1.2.0 h1:sPHsy7ADcIZQP3vILvTjrh74ZA175TFP5vqiNK1UmlI=
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zclconf/go-cty v1.3.1 h1:QIOZl+CKKdkv4l2w3lG23nNzXgLoxsWLSEdg1MlX4p0=
github.com/zclconf/go-cty v1.3.1/go.mod h1:YO23e2L18AG+ZYQfSobnY4G65nvwvprPCxBHkufUH1k=
github.com/zclconf/go-cty v1.4.0 h1:+q+tmgyUB94HIdH/uVTIi/+kt3pt4sHwEZAcTyLoGsQ= github.com/zclconf/go-cty v1.4.0 h1:+q+tmgyUB94HIdH/uVTIi/+kt3pt4sHwEZAcTyLoGsQ=
github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ= github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ=
github.com/zclconf/go-cty-yaml v1.0.1 h1:up11wlgAaDvlAGENcFDnZgkn0qUJurso7k6EpURKNF8= github.com/zclconf/go-cty-yaml v1.0.1 h1:up11wlgAaDvlAGENcFDnZgkn0qUJurso7k6EpURKNF8=
@ -488,6 +493,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191009170851-d66e71096ffb h1:TR699M2v0qoKTOHxeLgp6zPqaQNs74f01a/ob9W0qko= golang.org/x/net v0.0.0-20191009170851-d66e71096ffb h1:TR699M2v0qoKTOHxeLgp6zPqaQNs74f01a/ob9W0qko=
golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=

View File

@ -75,6 +75,13 @@ func Parse(arn string) (ARN, error) {
}, nil }, nil
} }
// IsARN returns whether the given string is an ARN by looking for
// whether the string starts with "arn:" and contains the correct number
// of sections delimited by colons(:).
func IsARN(arn string) bool {
return strings.HasPrefix(arn, arnPrefix) && strings.Count(arn, ":") >= arnSections-1
}
// String returns the canonical representation of the ARN // String returns the canonical representation of the ARN
func (arn ARN) String() string { func (arn ARN) String() string {
return arnPrefix + return arnPrefix +

View File

@ -70,7 +70,7 @@ func rValuesAtPath(v interface{}, path string, createPath, caseSensitive, nilTer
value = value.FieldByNameFunc(func(name string) bool { value = value.FieldByNameFunc(func(name string) bool {
if c == name { if c == name {
return true return true
} else if !caseSensitive && strings.ToLower(name) == strings.ToLower(c) { } else if !caseSensitive && strings.EqualFold(name, c) {
return true return true
} }
return false return false

View File

@ -12,6 +12,7 @@ import (
type Config struct { type Config struct {
Config *aws.Config Config *aws.Config
Handlers request.Handlers Handlers request.Handlers
PartitionID string
Endpoint string Endpoint string
SigningRegion string SigningRegion string
SigningName string SigningName string

View File

@ -16,11 +16,11 @@ import (
type DefaultRetryer struct { type DefaultRetryer struct {
// Num max Retries is the number of max retries that will be performed. // Num max Retries is the number of max retries that will be performed.
// By default, this is zero. // By default, this is zero.
NumMaxRetries int NumMaxRetries int
// MinRetryDelay is the minimum retry delay after which retry will be performed. // MinRetryDelay is the minimum retry delay after which retry will be performed.
// If not set, the value is 0ns. // If not set, the value is 0ns.
MinRetryDelay time.Duration MinRetryDelay time.Duration
// MinThrottleRetryDelay is the minimum retry delay when throttled. // MinThrottleRetryDelay is the minimum retry delay when throttled.
// If not set, the value is 0ns. // If not set, the value is 0ns.
@ -28,7 +28,7 @@ type DefaultRetryer struct {
// MaxRetryDelay is the maximum retry delay before which retry must be performed. // MaxRetryDelay is the maximum retry delay before which retry must be performed.
// If not set, the value is 0ns. // If not set, the value is 0ns.
MaxRetryDelay time.Duration MaxRetryDelay time.Duration
// MaxThrottleDelay is the maximum retry delay when throttled. // MaxThrottleDelay is the maximum retry delay when throttled.
// If not set, the value is 0ns. // If not set, the value is 0ns.

View File

@ -5,6 +5,7 @@ type ClientInfo struct {
ServiceName string ServiceName string
ServiceID string ServiceID string
APIVersion string APIVersion string
PartitionID string
Endpoint string Endpoint string
SigningName string SigningName string
SigningRegion string SigningRegion string

View File

@ -161,6 +161,17 @@ type Config struct {
// on GetObject API calls. // on GetObject API calls.
S3DisableContentMD5Validation *bool S3DisableContentMD5Validation *bool
// Set this to `true` to have the S3 service client to use the region specified
// in the ARN, when an ARN is provided as an argument to a bucket parameter.
S3UseARNRegion *bool
// Set this to `true` to enable the SDK to unmarshal API response header maps to
// normalized lower case map keys.
//
// For example S3's X-Amz-Meta prefixed header will be unmarshaled to lower case
// Metadata member's map keys. The value of the header in the map is unaffected.
LowerCaseHeaderMaps *bool
// Set this to `true` to disable the EC2Metadata client from overriding the // 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 // 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 // EC2Metadata client to create a new http.Client. This options is only
@ -246,6 +257,12 @@ type Config struct {
// Disabling this feature is useful when you want to use local endpoints // Disabling this feature is useful when you want to use local endpoints
// for testing that do not support the modeled host prefix pattern. // for testing that do not support the modeled host prefix pattern.
DisableEndpointHostPrefix *bool DisableEndpointHostPrefix *bool
// STSRegionalEndpoint will enable regional or legacy endpoint resolving
STSRegionalEndpoint endpoints.STSRegionalEndpoint
// S3UsEast1RegionalEndpoint will enable regional or legacy endpoint resolving
S3UsEast1RegionalEndpoint endpoints.S3UsEast1RegionalEndpoint
} }
// NewConfig returns a new Config pointer that can be chained with builder // NewConfig returns a new Config pointer that can be chained with builder
@ -379,6 +396,13 @@ func (c *Config) WithS3DisableContentMD5Validation(enable bool) *Config {
} }
// WithS3UseARNRegion sets a config S3UseARNRegion value and
// returning a Config pointer for chaining
func (c *Config) WithS3UseARNRegion(enable bool) *Config {
c.S3UseARNRegion = &enable
return c
}
// WithUseDualStack sets a config UseDualStack value returning a Config // WithUseDualStack sets a config UseDualStack value returning a Config
// pointer for chaining. // pointer for chaining.
func (c *Config) WithUseDualStack(enable bool) *Config { func (c *Config) WithUseDualStack(enable bool) *Config {
@ -420,6 +444,20 @@ func (c *Config) MergeIn(cfgs ...*Config) {
} }
} }
// WithSTSRegionalEndpoint will set whether or not to use regional endpoint flag
// when resolving the endpoint for a service
func (c *Config) WithSTSRegionalEndpoint(sre endpoints.STSRegionalEndpoint) *Config {
c.STSRegionalEndpoint = sre
return c
}
// WithS3UsEast1RegionalEndpoint will set whether or not to use regional endpoint flag
// when resolving the endpoint for a service
func (c *Config) WithS3UsEast1RegionalEndpoint(sre endpoints.S3UsEast1RegionalEndpoint) *Config {
c.S3UsEast1RegionalEndpoint = sre
return c
}
func mergeInConfig(dst *Config, other *Config) { func mergeInConfig(dst *Config, other *Config) {
if other == nil { if other == nil {
return return
@ -493,6 +531,10 @@ func mergeInConfig(dst *Config, other *Config) {
dst.S3DisableContentMD5Validation = other.S3DisableContentMD5Validation dst.S3DisableContentMD5Validation = other.S3DisableContentMD5Validation
} }
if other.S3UseARNRegion != nil {
dst.S3UseARNRegion = other.S3UseARNRegion
}
if other.UseDualStack != nil { if other.UseDualStack != nil {
dst.UseDualStack = other.UseDualStack dst.UseDualStack = other.UseDualStack
} }
@ -520,6 +562,14 @@ func mergeInConfig(dst *Config, other *Config) {
if other.DisableEndpointHostPrefix != nil { if other.DisableEndpointHostPrefix != nil {
dst.DisableEndpointHostPrefix = other.DisableEndpointHostPrefix dst.DisableEndpointHostPrefix = other.DisableEndpointHostPrefix
} }
if other.STSRegionalEndpoint != endpoints.UnsetSTSEndpoint {
dst.STSRegionalEndpoint = other.STSRegionalEndpoint
}
if other.S3UsEast1RegionalEndpoint != endpoints.UnsetS3UsEast1Endpoint {
dst.S3UsEast1RegionalEndpoint = other.S3UsEast1RegionalEndpoint
}
} }
// Copy will return a shallow copy of the Config object. If any additional // Copy will return a shallow copy of the Config object. If any additional

View File

@ -2,42 +2,8 @@
package aws package aws
import "time" import (
"github.com/aws/aws-sdk-go/internal/context"
// An emptyCtx is a copy of the Go 1.7 context.emptyCtx type. This is copied to
// provide a 1.6 and 1.5 safe version of context that is compatible with Go
// 1.7's Context.
//
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
// struct{}, since vars of this type must have distinct addresses.
type emptyCtx int
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
return
}
func (*emptyCtx) Done() <-chan struct{} {
return nil
}
func (*emptyCtx) Err() error {
return nil
}
func (*emptyCtx) Value(key interface{}) interface{} {
return nil
}
func (e *emptyCtx) String() string {
switch e {
case backgroundCtx:
return "aws.BackgroundContext"
}
return "unknown empty Context"
}
var (
backgroundCtx = new(emptyCtx)
) )
// BackgroundContext returns a context that will never be canceled, has no // BackgroundContext returns a context that will never be canceled, has no
@ -52,5 +18,5 @@ var (
// //
// See https://golang.org/pkg/context for more information on Contexts. // See https://golang.org/pkg/context for more information on Contexts.
func BackgroundContext() Context { func BackgroundContext() Context {
return backgroundCtx return context.BackgroundCtx
} }

View File

@ -161,7 +161,7 @@ func handleSendError(r *request.Request, err error) {
} }
// Catch all request errors, and let the default retrier determine // Catch all request errors, and let the default retrier determine
// if the error is retryable. // if the error is retryable.
r.Error = awserr.New("RequestError", "send request failed", err) r.Error = awserr.New(request.ErrCodeRequestError, "send request failed", err)
// Override the error with a context canceled error, if that was canceled. // Override the error with a context canceled error, if that was canceled.
ctx := r.Context() ctx := r.Context()

View File

@ -0,0 +1,22 @@
// +build !go1.7
package credentials
import (
"github.com/aws/aws-sdk-go/internal/context"
)
// backgroundContext returns a context that will never be canceled, has no
// values, and no deadline. This context is used by the SDK to provide
// backwards compatibility with non-context API operations and functionality.
//
// Go 1.6 and before:
// This context function is equivalent to context.Background in the Go stdlib.
//
// Go 1.7 and later:
// The context returned will be the value returned by context.Background()
//
// See https://golang.org/pkg/context for more information on Contexts.
func backgroundContext() Context {
return context.BackgroundCtx
}

View File

@ -0,0 +1,20 @@
// +build go1.7
package credentials
import "context"
// backgroundContext returns a context that will never be canceled, has no
// values, and no deadline. This context is used by the SDK to provide
// backwards compatibility with non-context API operations and functionality.
//
// Go 1.6 and before:
// This context function is equivalent to context.Background in the Go stdlib.
//
// Go 1.7 and later:
// The context returned will be the value returned by context.Background()
//
// See https://golang.org/pkg/context for more information on Contexts.
func backgroundContext() Context {
return context.Background()
}

View File

@ -0,0 +1,39 @@
// +build !go1.9
package credentials
import "time"
// Context is an copy of the Go v1.7 stdlib's context.Context interface.
// It is represented as a SDK interface to enable you to use the "WithContext"
// API methods with Go v1.6 and a Context type such as golang.org/x/net/context.
//
// This type, aws.Context, and context.Context are equivalent.
//
// See https://golang.org/pkg/context on how to use contexts.
type Context interface {
// Deadline returns the time when work done on behalf of this context
// should be canceled. Deadline returns ok==false when no deadline is
// set. Successive calls to Deadline return the same results.
Deadline() (deadline time.Time, ok bool)
// Done returns a channel that's closed when work done on behalf of this
// context should be canceled. Done may return nil if this context can
// never be canceled. Successive calls to Done return the same value.
Done() <-chan struct{}
// Err returns a non-nil error value after Done is closed. Err returns
// Canceled if the context was canceled or DeadlineExceeded if the
// context's deadline passed. No other values for Err are defined.
// After Done is closed, successive calls to Err return the same value.
Err() error
// Value returns the value associated with this context for key, or nil
// if no value is associated with key. Successive calls to Value with
// the same key returns the same result.
//
// Use context values only for request-scoped data that transits
// processes and API boundaries, not for passing optional parameters to
// functions.
Value(key interface{}) interface{}
}

View File

@ -0,0 +1,13 @@
// +build go1.9
package credentials
import "context"
// Context is an alias of the Go stdlib's context.Context interface.
// It can be used within the SDK's API operation "WithContext" methods.
//
// This type, aws.Context, and context.Context are equivalent.
//
// See https://golang.org/pkg/context on how to use contexts.
type Context = context.Context

View File

@ -50,10 +50,11 @@ package credentials
import ( import (
"fmt" "fmt"
"sync" "sync/atomic"
"time" "time"
"github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/internal/sync/singleflight"
) )
// AnonymousCredentials is an empty Credential object that can be used as // AnonymousCredentials is an empty Credential object that can be used as
@ -106,6 +107,13 @@ type Provider interface {
IsExpired() bool IsExpired() bool
} }
// ProviderWithContext is a Provider that can retrieve credentials with a Context
type ProviderWithContext interface {
Provider
RetrieveWithContext(Context) (Value, error)
}
// An Expirer is an interface that Providers can implement to expose the expiration // An Expirer is an interface that Providers can implement to expose the expiration
// time, if known. If the Provider cannot accurately provide this info, // time, if known. If the Provider cannot accurately provide this info,
// it should not implement this interface. // it should not implement this interface.
@ -197,20 +205,68 @@ func (e *Expiry) ExpiresAt() time.Time {
// first instance of the credentials Value. All calls to Get() after that // first instance of the credentials Value. All calls to Get() after that
// will return the cached credentials Value until IsExpired() returns true. // will return the cached credentials Value until IsExpired() returns true.
type Credentials struct { type Credentials struct {
creds Value creds atomic.Value
forceRefresh bool sf singleflight.Group
m sync.RWMutex
provider Provider provider Provider
} }
// NewCredentials returns a pointer to a new Credentials with the provider set. // NewCredentials returns a pointer to a new Credentials with the provider set.
func NewCredentials(provider Provider) *Credentials { func NewCredentials(provider Provider) *Credentials {
return &Credentials{ c := &Credentials{
provider: provider, provider: provider,
forceRefresh: true,
} }
c.creds.Store(Value{})
return c
}
// GetWithContext returns the credentials value, or error if the credentials
// Value failed to be retrieved. Will return early if the passed in context is
// canceled.
//
// Will return the cached credentials Value if it has not expired. If the
// credentials Value has expired the Provider's Retrieve() will be called
// to refresh the 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.
//
// Passed in Context is equivalent to aws.Context, and context.Context.
func (c *Credentials) GetWithContext(ctx Context) (Value, error) {
if curCreds := c.creds.Load(); !c.isExpired(curCreds) {
return curCreds.(Value), nil
}
// Cannot pass context down to the actual retrieve, because the first
// context would cancel the whole group when there is not direct
// association of items in the group.
resCh := c.sf.DoChan("", func() (interface{}, error) {
return c.singleRetrieve(&suppressedContext{ctx})
})
select {
case res := <-resCh:
return res.Val.(Value), res.Err
case <-ctx.Done():
return Value{}, awserr.New("RequestCanceled",
"request context canceled", ctx.Err())
}
}
func (c *Credentials) singleRetrieve(ctx Context) (creds interface{}, err error) {
if curCreds := c.creds.Load(); !c.isExpired(curCreds) {
return curCreds.(Value), nil
}
if p, ok := c.provider.(ProviderWithContext); ok {
creds, err = p.RetrieveWithContext(ctx)
} else {
creds, err = c.provider.Retrieve()
}
if err == nil {
c.creds.Store(creds)
}
return creds, err
} }
// Get returns the credentials value, or error if the credentials Value failed // Get returns the credentials value, or error if the credentials Value failed
@ -223,30 +279,7 @@ func NewCredentials(provider Provider) *Credentials {
// If Credentials.Expire() was called the credentials Value will be force // If Credentials.Expire() was called the credentials Value will be force
// expired, and the next call to Get() will cause them to be refreshed. // expired, and the next call to Get() will cause them to be refreshed.
func (c *Credentials) Get() (Value, error) { func (c *Credentials) Get() (Value, error) {
// Check the cached credentials first with just the read lock. return c.GetWithContext(backgroundContext())
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()
if c.isExpired() {
creds, err := c.provider.Retrieve()
if err != nil {
return Value{}, err
}
c.creds = creds
c.forceRefresh = false
}
return c.creds, nil
} }
// Expire expires the credentials and forces them to be retrieved on the // Expire expires the credentials and forces them to be retrieved on the
@ -255,10 +288,7 @@ func (c *Credentials) Get() (Value, error) {
// This will override the Provider's expired state, and force Credentials // This will override the Provider's expired state, and force Credentials
// to call the Provider's Retrieve(). // to call the Provider's Retrieve().
func (c *Credentials) Expire() { func (c *Credentials) Expire() {
c.m.Lock() c.creds.Store(Value{})
defer c.m.Unlock()
c.forceRefresh = true
} }
// IsExpired returns if the credentials are no longer valid, and need // IsExpired returns if the credentials are no longer valid, and need
@ -267,33 +297,43 @@ func (c *Credentials) Expire() {
// If the Credentials were forced to be expired with Expire() this will // If the Credentials were forced to be expired with Expire() this will
// reflect that override. // reflect that override.
func (c *Credentials) IsExpired() bool { func (c *Credentials) IsExpired() bool {
c.m.RLock() return c.isExpired(c.creds.Load())
defer c.m.RUnlock()
return c.isExpired()
} }
// isExpired helper method wrapping the definition of expired credentials. // isExpired helper method wrapping the definition of expired credentials.
func (c *Credentials) isExpired() bool { func (c *Credentials) isExpired(creds interface{}) bool {
return c.forceRefresh || c.provider.IsExpired() return creds == nil || creds.(Value) == Value{} || c.provider.IsExpired()
} }
// ExpiresAt provides access to the functionality of the Expirer interface of // ExpiresAt provides access to the functionality of the Expirer interface of
// the underlying Provider, if it supports that interface. Otherwise, it returns // the underlying Provider, if it supports that interface. Otherwise, it returns
// an error. // an error.
func (c *Credentials) ExpiresAt() (time.Time, error) { func (c *Credentials) ExpiresAt() (time.Time, error) {
c.m.RLock()
defer c.m.RUnlock()
expirer, ok := c.provider.(Expirer) expirer, ok := c.provider.(Expirer)
if !ok { if !ok {
return time.Time{}, awserr.New("ProviderNotExpirer", return time.Time{}, awserr.New("ProviderNotExpirer",
fmt.Sprintf("provider %s does not support ExpiresAt()", c.creds.ProviderName), fmt.Sprintf("provider %s does not support ExpiresAt()", c.creds.Load().(Value).ProviderName),
nil) nil)
} }
if c.forceRefresh { if c.creds.Load().(Value) == (Value{}) {
// set expiration time to the distant past // set expiration time to the distant past
return time.Time{}, nil return time.Time{}, nil
} }
return expirer.ExpiresAt(), nil return expirer.ExpiresAt(), nil
} }
type suppressedContext struct {
Context
}
func (s *suppressedContext) Deadline() (deadline time.Time, ok bool) {
return time.Time{}, false
}
func (s *suppressedContext) Done() <-chan struct{} {
return nil
}
func (s *suppressedContext) Err() error {
return nil
}

View File

@ -7,6 +7,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/client" "github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials"
@ -87,7 +88,14 @@ func NewCredentialsWithClient(client *ec2metadata.EC2Metadata, options ...func(*
// Error will be returned if the request fails, or unable to extract // Error will be returned if the request fails, or unable to extract
// the desired credentials. // the desired credentials.
func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) { func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) {
credsList, err := requestCredList(m.Client) return m.RetrieveWithContext(aws.BackgroundContext())
}
// RetrieveWithContext retrieves credentials from the EC2 service.
// Error will be returned if the request fails, or unable to extract
// the desired credentials.
func (m *EC2RoleProvider) RetrieveWithContext(ctx credentials.Context) (credentials.Value, error) {
credsList, err := requestCredList(ctx, m.Client)
if err != nil { if err != nil {
return credentials.Value{ProviderName: ProviderName}, err return credentials.Value{ProviderName: ProviderName}, err
} }
@ -97,7 +105,7 @@ func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) {
} }
credsName := credsList[0] credsName := credsList[0]
roleCreds, err := requestCred(m.Client, credsName) roleCreds, err := requestCred(ctx, m.Client, credsName)
if err != nil { if err != nil {
return credentials.Value{ProviderName: ProviderName}, err return credentials.Value{ProviderName: ProviderName}, err
} }
@ -130,8 +138,8 @@ const iamSecurityCredsPath = "iam/security-credentials/"
// requestCredList requests a list of credentials from the EC2 service. // 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 // If there are no credentials, or there is an error making or receiving the request
func requestCredList(client *ec2metadata.EC2Metadata) ([]string, error) { func requestCredList(ctx aws.Context, client *ec2metadata.EC2Metadata) ([]string, error) {
resp, err := client.GetMetadata(iamSecurityCredsPath) resp, err := client.GetMetadataWithContext(ctx, iamSecurityCredsPath)
if err != nil { if err != nil {
return nil, awserr.New("EC2RoleRequestError", "no EC2 instance role found", err) return nil, awserr.New("EC2RoleRequestError", "no EC2 instance role found", err)
} }
@ -154,8 +162,8 @@ func requestCredList(client *ec2metadata.EC2Metadata) ([]string, error) {
// //
// If the credentials cannot be found, or there is an error reading the response // If the credentials cannot be found, or there is an error reading the response
// and error will be returned. // and error will be returned.
func requestCred(client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCredRespBody, error) { func requestCred(ctx aws.Context, client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCredRespBody, error) {
resp, err := client.GetMetadata(sdkuri.PathJoin(iamSecurityCredsPath, credsName)) resp, err := client.GetMetadataWithContext(ctx, sdkuri.PathJoin(iamSecurityCredsPath, credsName))
if err != nil { if err != nil {
return ec2RoleCredRespBody{}, return ec2RoleCredRespBody{},
awserr.New("EC2RoleRequestError", awserr.New("EC2RoleRequestError",

View File

@ -116,7 +116,13 @@ func (p *Provider) IsExpired() bool {
// Retrieve will attempt to request the credentials from the endpoint the Provider // Retrieve will attempt to request the credentials from the endpoint the Provider
// was configured for. And error will be returned if the retrieval fails. // was configured for. And error will be returned if the retrieval fails.
func (p *Provider) Retrieve() (credentials.Value, error) { func (p *Provider) Retrieve() (credentials.Value, error) {
resp, err := p.getCredentials() return p.RetrieveWithContext(aws.BackgroundContext())
}
// RetrieveWithContext will attempt to request the credentials from the endpoint the Provider
// was configured for. And error will be returned if the retrieval fails.
func (p *Provider) RetrieveWithContext(ctx credentials.Context) (credentials.Value, error) {
resp, err := p.getCredentials(ctx)
if err != nil { if err != nil {
return credentials.Value{ProviderName: ProviderName}, return credentials.Value{ProviderName: ProviderName},
awserr.New("CredentialsEndpointError", "failed to load credentials", err) awserr.New("CredentialsEndpointError", "failed to load credentials", err)
@ -148,7 +154,7 @@ type errorOutput struct {
Message string `json:"message"` Message string `json:"message"`
} }
func (p *Provider) getCredentials() (*getCredentialsOutput, error) { func (p *Provider) getCredentials(ctx aws.Context) (*getCredentialsOutput, error) {
op := &request.Operation{ op := &request.Operation{
Name: "GetCredentials", Name: "GetCredentials",
HTTPMethod: "GET", HTTPMethod: "GET",
@ -156,6 +162,7 @@ func (p *Provider) getCredentials() (*getCredentialsOutput, error) {
out := &getCredentialsOutput{} out := &getCredentialsOutput{}
req := p.Client.NewRequest(op, nil, out) req := p.Client.NewRequest(op, nil, out)
req.SetContext(ctx)
req.HTTPRequest.Header.Set("Accept", "application/json") req.HTTPRequest.Header.Set("Accept", "application/json")
if authToken := p.AuthorizationToken; len(authToken) != 0 { if authToken := p.AuthorizationToken; len(authToken) != 0 {
req.HTTPRequest.Header.Set("Authorization", authToken) req.HTTPRequest.Header.Set("Authorization", authToken)

View File

@ -90,6 +90,7 @@ import (
"github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/internal/sdkio"
) )
const ( const (
@ -142,7 +143,7 @@ const (
// DefaultBufSize limits buffer size from growing to an enormous // DefaultBufSize limits buffer size from growing to an enormous
// amount due to a faulty process. // amount due to a faulty process.
DefaultBufSize = 1024 DefaultBufSize = int(8 * sdkio.KibiByte)
// DefaultTimeout default limit on time a process can run. // DefaultTimeout default limit on time a process can run.
DefaultTimeout = time.Duration(1) * time.Minute DefaultTimeout = time.Duration(1) * time.Minute

View File

@ -19,7 +19,9 @@ type StaticProvider struct {
} }
// NewStaticCredentials returns a pointer to a new Credentials object // NewStaticCredentials returns a pointer to a new Credentials object
// wrapping a static credentials value provider. // wrapping a static credentials value provider. Token is only required
// for temporary security credentials retrieved via STS, otherwise an empty
// string can be passed for this parameter.
func NewStaticCredentials(id, secret, token string) *Credentials { func NewStaticCredentials(id, secret, token string) *Credentials {
return NewCredentials(&StaticProvider{Value: Value{ return NewCredentials(&StaticProvider{Value: Value{
AccessKeyID: id, AccessKeyID: id,

View File

@ -87,6 +87,7 @@ import (
"github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/client" "github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/internal/sdkrand" "github.com/aws/aws-sdk-go/internal/sdkrand"
"github.com/aws/aws-sdk-go/service/sts" "github.com/aws/aws-sdk-go/service/sts"
) )
@ -118,6 +119,10 @@ type AssumeRoler interface {
AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
} }
type assumeRolerWithContext interface {
AssumeRoleWithContext(aws.Context, *sts.AssumeRoleInput, ...request.Option) (*sts.AssumeRoleOutput, error)
}
// DefaultDuration is the default amount of time in minutes that the credentials // DefaultDuration is the default amount of time in minutes that the credentials
// will be valid for. // will be valid for.
var DefaultDuration = time.Duration(15) * time.Minute var DefaultDuration = time.Duration(15) * time.Minute
@ -144,6 +149,13 @@ type AssumeRoleProvider struct {
// Session name, if you wish to reuse the credentials elsewhere. // Session name, if you wish to reuse the credentials elsewhere.
RoleSessionName string RoleSessionName string
// Optional, you can pass tag key-value pairs to your session. These tags are called session tags.
Tags []*sts.Tag
// A list of keys for session tags that you want to set as transitive.
// If you set a tag key as transitive, the corresponding key and value passes to subsequent sessions in a role chain.
TransitiveTagKeys []*string
// Expiry duration of the STS credentials. Defaults to 15 minutes if not set. // Expiry duration of the STS credentials. Defaults to 15 minutes if not set.
Duration time.Duration Duration time.Duration
@ -258,6 +270,11 @@ func NewCredentialsWithClient(svc AssumeRoler, roleARN string, options ...func(*
// Retrieve generates a new set of temporary credentials using STS. // Retrieve generates a new set of temporary credentials using STS.
func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) { func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) {
return p.RetrieveWithContext(aws.BackgroundContext())
}
// RetrieveWithContext generates a new set of temporary credentials using STS.
func (p *AssumeRoleProvider) RetrieveWithContext(ctx credentials.Context) (credentials.Value, error) {
// Apply defaults where parameters are not set. // Apply defaults where parameters are not set.
if p.RoleSessionName == "" { if p.RoleSessionName == "" {
// Try to work out a role name that will hopefully end up unique. // Try to work out a role name that will hopefully end up unique.
@ -269,10 +286,12 @@ func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) {
} }
jitter := time.Duration(sdkrand.SeededRand.Float64() * p.MaxJitterFrac * float64(p.Duration)) jitter := time.Duration(sdkrand.SeededRand.Float64() * p.MaxJitterFrac * float64(p.Duration))
input := &sts.AssumeRoleInput{ input := &sts.AssumeRoleInput{
DurationSeconds: aws.Int64(int64((p.Duration - jitter) / time.Second)), DurationSeconds: aws.Int64(int64((p.Duration - jitter) / time.Second)),
RoleArn: aws.String(p.RoleARN), RoleArn: aws.String(p.RoleARN),
RoleSessionName: aws.String(p.RoleSessionName), RoleSessionName: aws.String(p.RoleSessionName),
ExternalId: p.ExternalID, ExternalId: p.ExternalID,
Tags: p.Tags,
TransitiveTagKeys: p.TransitiveTagKeys,
} }
if p.Policy != nil { if p.Policy != nil {
input.Policy = p.Policy input.Policy = p.Policy
@ -295,7 +314,15 @@ func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) {
} }
} }
roleOutput, err := p.Client.AssumeRole(input) var roleOutput *sts.AssumeRoleOutput
var err error
if c, ok := p.Client.(assumeRolerWithContext); ok {
roleOutput, err = c.AssumeRoleWithContext(ctx, input)
} else {
roleOutput, err = p.Client.AssumeRole(input)
}
if err != nil { if err != nil {
return credentials.Value{ProviderName: ProviderName}, err return credentials.Value{ProviderName: ProviderName}, err
} }

View File

@ -28,6 +28,24 @@ const (
// compare test values. // compare test values.
var now = time.Now var now = time.Now
// TokenFetcher shuold return WebIdentity token bytes or an error
type TokenFetcher interface {
FetchToken(credentials.Context) ([]byte, error)
}
// FetchTokenPath is a path to a WebIdentity token file
type FetchTokenPath string
// FetchToken returns a token by reading from the filesystem
func (f FetchTokenPath) FetchToken(ctx credentials.Context) ([]byte, error) {
data, err := ioutil.ReadFile(string(f))
if err != nil {
errMsg := fmt.Sprintf("unable to read file at %s", f)
return nil, awserr.New(ErrCodeWebIdentity, errMsg, err)
}
return data, nil
}
// WebIdentityRoleProvider is used to retrieve credentials using // WebIdentityRoleProvider is used to retrieve credentials using
// an OIDC token. // an OIDC token.
type WebIdentityRoleProvider struct { type WebIdentityRoleProvider struct {
@ -36,7 +54,7 @@ type WebIdentityRoleProvider struct {
client stsiface.STSAPI client stsiface.STSAPI
ExpiryWindow time.Duration ExpiryWindow time.Duration
tokenFilePath string tokenFetcher TokenFetcher
roleARN string roleARN string
roleSessionName string roleSessionName string
} }
@ -52,9 +70,15 @@ func NewWebIdentityCredentials(c client.ConfigProvider, roleARN, roleSessionName
// NewWebIdentityRoleProvider will return a new WebIdentityRoleProvider with the // NewWebIdentityRoleProvider will return a new WebIdentityRoleProvider with the
// provided stsiface.STSAPI // provided stsiface.STSAPI
func NewWebIdentityRoleProvider(svc stsiface.STSAPI, roleARN, roleSessionName, path string) *WebIdentityRoleProvider { func NewWebIdentityRoleProvider(svc stsiface.STSAPI, roleARN, roleSessionName, path string) *WebIdentityRoleProvider {
return NewWebIdentityRoleProviderWithToken(svc, roleARN, roleSessionName, FetchTokenPath(path))
}
// NewWebIdentityRoleProviderWithToken will return a new WebIdentityRoleProvider with the
// provided stsiface.STSAPI and a TokenFetcher
func NewWebIdentityRoleProviderWithToken(svc stsiface.STSAPI, roleARN, roleSessionName string, tokenFetcher TokenFetcher) *WebIdentityRoleProvider {
return &WebIdentityRoleProvider{ return &WebIdentityRoleProvider{
client: svc, client: svc,
tokenFilePath: path, tokenFetcher: tokenFetcher,
roleARN: roleARN, roleARN: roleARN,
roleSessionName: roleSessionName, roleSessionName: roleSessionName,
} }
@ -64,10 +88,16 @@ func NewWebIdentityRoleProvider(svc stsiface.STSAPI, roleARN, roleSessionName, p
// 'WebIdentityTokenFilePath' specified destination and if that is empty an // 'WebIdentityTokenFilePath' specified destination and if that is empty an
// error will be returned. // error will be returned.
func (p *WebIdentityRoleProvider) Retrieve() (credentials.Value, error) { func (p *WebIdentityRoleProvider) Retrieve() (credentials.Value, error) {
b, err := ioutil.ReadFile(p.tokenFilePath) return p.RetrieveWithContext(aws.BackgroundContext())
}
// RetrieveWithContext will attempt to assume a role from a token which is located at
// 'WebIdentityTokenFilePath' specified destination and if that is empty an
// error will be returned.
func (p *WebIdentityRoleProvider) RetrieveWithContext(ctx credentials.Context) (credentials.Value, error) {
b, err := p.tokenFetcher.FetchToken(ctx)
if err != nil { if err != nil {
errMsg := fmt.Sprintf("unable to read file at %s", p.tokenFilePath) return credentials.Value{}, awserr.New(ErrCodeWebIdentity, "failed fetching WebIdentity token: ", err)
return credentials.Value{}, awserr.New(ErrCodeWebIdentity, errMsg, err)
} }
sessionName := p.roleSessionName sessionName := p.roleSessionName
@ -81,6 +111,9 @@ func (p *WebIdentityRoleProvider) Retrieve() (credentials.Value, error) {
RoleSessionName: &sessionName, RoleSessionName: &sessionName,
WebIdentityToken: aws.String(string(b)), WebIdentityToken: aws.String(string(b)),
}) })
req.SetContext(ctx)
// InvalidIdentityToken error is a temporary error that can occur // InvalidIdentityToken error is a temporary error that can occur
// when assuming an Role with a JWT web identity token. // when assuming an Role with a JWT web identity token.
req.RetryErrorCodes = append(req.RetryErrorCodes, sts.ErrCodeInvalidIdentityTokenException) req.RetryErrorCodes = append(req.RetryErrorCodes, sts.ErrCodeInvalidIdentityTokenException)

View File

@ -66,7 +66,6 @@ func (rep *Reporter) sendAPICallAttemptMetric(r *request.Request) {
XAmzRequestID: aws.String(r.RequestID), XAmzRequestID: aws.String(r.RequestID),
AttemptCount: aws.Int(r.RetryCount + 1),
AttemptLatency: aws.Int(int(now.Sub(r.AttemptTime).Nanoseconds() / int64(time.Millisecond))), AttemptLatency: aws.Int(int(now.Sub(r.AttemptTime).Nanoseconds() / int64(time.Millisecond))),
AccessKey: aws.String(creds.AccessKeyID), AccessKey: aws.String(creds.AccessKeyID),
} }
@ -90,7 +89,7 @@ func getMetricException(err awserr.Error) metricException {
code := err.Code() code := err.Code()
switch code { switch code {
case "RequestError", case request.ErrCodeRequestError,
request.ErrCodeSerialization, request.ErrCodeSerialization,
request.CanceledErrorCode: request.CanceledErrorCode:
return sdkException{ return sdkException{

View File

@ -4,28 +4,73 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"strconv"
"strings" "strings"
"time" "time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/internal/sdkuri" "github.com/aws/aws-sdk-go/internal/sdkuri"
) )
// getToken uses the duration to return a token for EC2 metadata service,
// or an error if the request failed.
func (c *EC2Metadata) getToken(ctx aws.Context, duration time.Duration) (tokenOutput, error) {
op := &request.Operation{
Name: "GetToken",
HTTPMethod: "PUT",
HTTPPath: "/api/token",
}
var output tokenOutput
req := c.NewRequest(op, nil, &output)
req.SetContext(ctx)
// remove the fetch token handler from the request handlers to avoid infinite recursion
req.Handlers.Sign.RemoveByName(fetchTokenHandlerName)
// Swap the unmarshalMetadataHandler with unmarshalTokenHandler on this request.
req.Handlers.Unmarshal.Swap(unmarshalMetadataHandlerName, unmarshalTokenHandler)
ttl := strconv.FormatInt(int64(duration/time.Second), 10)
req.HTTPRequest.Header.Set(ttlHeader, ttl)
err := req.Send()
// Errors with bad request status should be returned.
if err != nil {
err = awserr.NewRequestFailure(
awserr.New(req.HTTPResponse.Status, http.StatusText(req.HTTPResponse.StatusCode), err),
req.HTTPResponse.StatusCode, req.RequestID)
}
return output, err
}
// GetMetadata uses the path provided to request information from the EC2 // GetMetadata uses the path provided to request information from the EC2
// instance metdata service. The content will be returned as a string, or // instance metadata service. The content will be returned as a string, or
// error if the request failed. // error if the request failed.
func (c *EC2Metadata) GetMetadata(p string) (string, error) { func (c *EC2Metadata) GetMetadata(p string) (string, error) {
return c.GetMetadataWithContext(aws.BackgroundContext(), p)
}
// GetMetadataWithContext uses the path provided to request information from the EC2
// instance metadata service. The content will be returned as a string, or
// error if the request failed.
func (c *EC2Metadata) GetMetadataWithContext(ctx aws.Context, p string) (string, error) {
op := &request.Operation{ op := &request.Operation{
Name: "GetMetadata", Name: "GetMetadata",
HTTPMethod: "GET", HTTPMethod: "GET",
HTTPPath: sdkuri.PathJoin("/meta-data", p), HTTPPath: sdkuri.PathJoin("/meta-data", p),
} }
output := &metadataOutput{} output := &metadataOutput{}
req := c.NewRequest(op, nil, output)
err := req.Send()
req := c.NewRequest(op, nil, output)
req.SetContext(ctx)
err := req.Send()
return output.Content, err return output.Content, err
} }
@ -33,6 +78,13 @@ func (c *EC2Metadata) GetMetadata(p string) (string, error) {
// there is no user-data setup for the EC2 instance a "NotFoundError" error // there is no user-data setup for the EC2 instance a "NotFoundError" error
// code will be returned. // code will be returned.
func (c *EC2Metadata) GetUserData() (string, error) { func (c *EC2Metadata) GetUserData() (string, error) {
return c.GetUserDataWithContext(aws.BackgroundContext())
}
// GetUserDataWithContext returns the userdata that was configured for the service. If
// there is no user-data setup for the EC2 instance a "NotFoundError" error
// code will be returned.
func (c *EC2Metadata) GetUserDataWithContext(ctx aws.Context) (string, error) {
op := &request.Operation{ op := &request.Operation{
Name: "GetUserData", Name: "GetUserData",
HTTPMethod: "GET", HTTPMethod: "GET",
@ -41,13 +93,9 @@ func (c *EC2Metadata) GetUserData() (string, error) {
output := &metadataOutput{} output := &metadataOutput{}
req := c.NewRequest(op, nil, output) req := c.NewRequest(op, nil, output)
req.Handlers.UnmarshalError.PushBack(func(r *request.Request) { req.SetContext(ctx)
if r.HTTPResponse.StatusCode == http.StatusNotFound {
r.Error = awserr.New("NotFoundError", "user-data not found", r.Error)
}
})
err := req.Send()
err := req.Send()
return output.Content, err return output.Content, err
} }
@ -55,6 +103,13 @@ func (c *EC2Metadata) GetUserData() (string, error) {
// instance metadata service for dynamic data. The content will be returned // instance metadata service for dynamic data. The content will be returned
// as a string, or error if the request failed. // as a string, or error if the request failed.
func (c *EC2Metadata) GetDynamicData(p string) (string, error) { func (c *EC2Metadata) GetDynamicData(p string) (string, error) {
return c.GetDynamicDataWithContext(aws.BackgroundContext(), p)
}
// GetDynamicDataWithContext uses the path provided to request information from the EC2
// instance metadata service for dynamic data. The content will be returned
// as a string, or error if the request failed.
func (c *EC2Metadata) GetDynamicDataWithContext(ctx aws.Context, p string) (string, error) {
op := &request.Operation{ op := &request.Operation{
Name: "GetDynamicData", Name: "GetDynamicData",
HTTPMethod: "GET", HTTPMethod: "GET",
@ -63,8 +118,9 @@ func (c *EC2Metadata) GetDynamicData(p string) (string, error) {
output := &metadataOutput{} output := &metadataOutput{}
req := c.NewRequest(op, nil, output) req := c.NewRequest(op, nil, output)
err := req.Send() req.SetContext(ctx)
err := req.Send()
return output.Content, err return output.Content, err
} }
@ -72,7 +128,14 @@ func (c *EC2Metadata) GetDynamicData(p string) (string, error) {
// instance. Error is returned if the request fails or is unable to parse // instance. Error is returned if the request fails or is unable to parse
// the response. // the response.
func (c *EC2Metadata) GetInstanceIdentityDocument() (EC2InstanceIdentityDocument, error) { func (c *EC2Metadata) GetInstanceIdentityDocument() (EC2InstanceIdentityDocument, error) {
resp, err := c.GetDynamicData("instance-identity/document") return c.GetInstanceIdentityDocumentWithContext(aws.BackgroundContext())
}
// GetInstanceIdentityDocumentWithContext retrieves an identity document describing an
// instance. Error is returned if the request fails or is unable to parse
// the response.
func (c *EC2Metadata) GetInstanceIdentityDocumentWithContext(ctx aws.Context) (EC2InstanceIdentityDocument, error) {
resp, err := c.GetDynamicDataWithContext(ctx, "instance-identity/document")
if err != nil { if err != nil {
return EC2InstanceIdentityDocument{}, return EC2InstanceIdentityDocument{},
awserr.New("EC2MetadataRequestError", awserr.New("EC2MetadataRequestError",
@ -91,7 +154,12 @@ func (c *EC2Metadata) GetInstanceIdentityDocument() (EC2InstanceIdentityDocument
// IAMInfo retrieves IAM info from the metadata API // IAMInfo retrieves IAM info from the metadata API
func (c *EC2Metadata) IAMInfo() (EC2IAMInfo, error) { func (c *EC2Metadata) IAMInfo() (EC2IAMInfo, error) {
resp, err := c.GetMetadata("iam/info") return c.IAMInfoWithContext(aws.BackgroundContext())
}
// IAMInfoWithContext retrieves IAM info from the metadata API
func (c *EC2Metadata) IAMInfoWithContext(ctx aws.Context) (EC2IAMInfo, error) {
resp, err := c.GetMetadataWithContext(ctx, "iam/info")
if err != nil { if err != nil {
return EC2IAMInfo{}, return EC2IAMInfo{},
awserr.New("EC2MetadataRequestError", awserr.New("EC2MetadataRequestError",
@ -116,24 +184,36 @@ func (c *EC2Metadata) IAMInfo() (EC2IAMInfo, error) {
// Region returns the region the instance is running in. // Region returns the region the instance is running in.
func (c *EC2Metadata) Region() (string, error) { func (c *EC2Metadata) Region() (string, error) {
resp, err := c.GetMetadata("placement/availability-zone") return c.RegionWithContext(aws.BackgroundContext())
}
// RegionWithContext returns the region the instance is running in.
func (c *EC2Metadata) RegionWithContext(ctx aws.Context) (string, error) {
ec2InstanceIdentityDocument, err := c.GetInstanceIdentityDocumentWithContext(ctx)
if err != nil { if err != nil {
return "", err return "", err
} }
// extract region from the ec2InstanceIdentityDocument
if len(resp) == 0 { region := ec2InstanceIdentityDocument.Region
return "", awserr.New("EC2MetadataError", "invalid Region response", nil) if len(region) == 0 {
return "", awserr.New("EC2MetadataError", "invalid region received for ec2metadata instance", nil)
} }
// returns region
// returns region without the suffix. Eg: us-west-2a becomes us-west-2 return region, nil
return resp[:len(resp)-1], nil
} }
// Available returns if the application has access to the EC2 Metadata service. // Available returns if the application has access to the EC2 Metadata service.
// Can be used to determine if application is running within an EC2 Instance and // Can be used to determine if application is running within an EC2 Instance and
// the metadata service is available. // the metadata service is available.
func (c *EC2Metadata) Available() bool { func (c *EC2Metadata) Available() bool {
if _, err := c.GetMetadata("instance-id"); err != nil { return c.AvailableWithContext(aws.BackgroundContext())
}
// AvailableWithContext returns if the application has access to the EC2 Metadata service.
// Can be used to determine if application is running within an EC2 Instance and
// the metadata service is available.
func (c *EC2Metadata) AvailableWithContext(ctx aws.Context) bool {
if _, err := c.GetMetadataWithContext(ctx, "instance-id"); err != nil {
return false return false
} }

View File

@ -13,6 +13,7 @@ import (
"io" "io"
"net/http" "net/http"
"os" "os"
"strconv"
"strings" "strings"
"time" "time"
@ -24,9 +25,25 @@ import (
"github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/request"
) )
// ServiceName is the name of the service. const (
const ServiceName = "ec2metadata" // ServiceName is the name of the service.
const disableServiceEnvVar = "AWS_EC2_METADATA_DISABLED" ServiceName = "ec2metadata"
disableServiceEnvVar = "AWS_EC2_METADATA_DISABLED"
// Headers for Token and TTL
ttlHeader = "x-aws-ec2-metadata-token-ttl-seconds"
tokenHeader = "x-aws-ec2-metadata-token"
// Named Handler constants
fetchTokenHandlerName = "FetchTokenHandler"
unmarshalMetadataHandlerName = "unmarshalMetadataHandler"
unmarshalTokenHandlerName = "unmarshalTokenHandler"
enableTokenProviderHandlerName = "enableTokenProviderHandler"
// TTL constants
defaultTTL = 21600 * time.Second
ttlExpirationWindow = 30 * time.Second
)
// A EC2Metadata is an EC2 Metadata service Client. // A EC2Metadata is an EC2 Metadata service Client.
type EC2Metadata struct { type EC2Metadata struct {
@ -63,8 +80,10 @@ func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
// use a shorter timeout than default because the metadata // use a shorter timeout than default because the metadata
// service is local if it is running, and to fail faster // service is local if it is running, and to fail faster
// if not running on an ec2 instance. // if not running on an ec2 instance.
Timeout: 5 * time.Second, Timeout: 1 * time.Second,
} }
// max number of retries on the client operation
cfg.MaxRetries = aws.Int(2)
} }
svc := &EC2Metadata{ svc := &EC2Metadata{
@ -80,13 +99,27 @@ func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
), ),
} }
svc.Handlers.Unmarshal.PushBack(unmarshalHandler) // token provider instance
tp := newTokenProvider(svc, defaultTTL)
// NamedHandler for fetching token
svc.Handlers.Sign.PushBackNamed(request.NamedHandler{
Name: fetchTokenHandlerName,
Fn: tp.fetchTokenHandler,
})
// NamedHandler for enabling token provider
svc.Handlers.Complete.PushBackNamed(request.NamedHandler{
Name: enableTokenProviderHandlerName,
Fn: tp.enableTokenProviderHandler,
})
svc.Handlers.Unmarshal.PushBackNamed(unmarshalHandler)
svc.Handlers.UnmarshalError.PushBack(unmarshalError) svc.Handlers.UnmarshalError.PushBack(unmarshalError)
svc.Handlers.Validate.Clear() svc.Handlers.Validate.Clear()
svc.Handlers.Validate.PushBack(validateEndpointHandler) svc.Handlers.Validate.PushBack(validateEndpointHandler)
// Disable the EC2 Metadata service if the environment variable is set. // Disable the EC2 Metadata service if the environment variable is set.
// This shortcirctes the service's functionality to always fail to send // This short-circuits the service's functionality to always fail to send
// requests. // requests.
if strings.ToLower(os.Getenv(disableServiceEnvVar)) == "true" { if strings.ToLower(os.Getenv(disableServiceEnvVar)) == "true" {
svc.Handlers.Send.SwapNamed(request.NamedHandler{ svc.Handlers.Send.SwapNamed(request.NamedHandler{
@ -107,7 +140,6 @@ func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
for _, option := range opts { for _, option := range opts {
option(svc.Client) option(svc.Client)
} }
return svc return svc
} }
@ -119,30 +151,74 @@ type metadataOutput struct {
Content string Content string
} }
func unmarshalHandler(r *request.Request) { type tokenOutput struct {
defer r.HTTPResponse.Body.Close() Token string
b := &bytes.Buffer{} TTL time.Duration
if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil { }
r.Error = awserr.New(request.ErrCodeSerialization, "unable to unmarshal EC2 metadata response", err)
return
}
if data, ok := r.Data.(*metadataOutput); ok { // unmarshal token handler is used to parse the response of a getToken operation
data.Content = b.String() var unmarshalTokenHandler = request.NamedHandler{
} Name: unmarshalTokenHandlerName,
Fn: func(r *request.Request) {
defer r.HTTPResponse.Body.Close()
var b bytes.Buffer
if _, err := io.Copy(&b, r.HTTPResponse.Body); err != nil {
r.Error = awserr.NewRequestFailure(awserr.New(request.ErrCodeSerialization,
"unable to unmarshal EC2 metadata response", err), r.HTTPResponse.StatusCode, r.RequestID)
return
}
v := r.HTTPResponse.Header.Get(ttlHeader)
data, ok := r.Data.(*tokenOutput)
if !ok {
return
}
data.Token = b.String()
// TTL is in seconds
i, err := strconv.ParseInt(v, 10, 64)
if err != nil {
r.Error = awserr.NewRequestFailure(awserr.New(request.ParamFormatErrCode,
"unable to parse EC2 token TTL response", err), r.HTTPResponse.StatusCode, r.RequestID)
return
}
t := time.Duration(i) * time.Second
data.TTL = t
},
}
var unmarshalHandler = request.NamedHandler{
Name: unmarshalMetadataHandlerName,
Fn: func(r *request.Request) {
defer r.HTTPResponse.Body.Close()
var b bytes.Buffer
if _, err := io.Copy(&b, r.HTTPResponse.Body); err != nil {
r.Error = awserr.NewRequestFailure(awserr.New(request.ErrCodeSerialization,
"unable to unmarshal EC2 metadata response", err), r.HTTPResponse.StatusCode, r.RequestID)
return
}
if data, ok := r.Data.(*metadataOutput); ok {
data.Content = b.String()
}
},
} }
func unmarshalError(r *request.Request) { func unmarshalError(r *request.Request) {
defer r.HTTPResponse.Body.Close() defer r.HTTPResponse.Body.Close()
b := &bytes.Buffer{} var b bytes.Buffer
if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil {
r.Error = awserr.New(request.ErrCodeSerialization, "unable to unmarshal EC2 metadata error response", err) if _, err := io.Copy(&b, r.HTTPResponse.Body); err != nil {
r.Error = awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization, "unable to unmarshal EC2 metadata error response", err),
r.HTTPResponse.StatusCode, r.RequestID)
return return
} }
// Response body format is not consistent between metadata endpoints. // Response body format is not consistent between metadata endpoints.
// Grab the error message as a string and include that as the source error // Grab the error message as a string and include that as the source error
r.Error = awserr.New("EC2MetadataError", "failed to make EC2Metadata request", errors.New(b.String())) r.Error = awserr.NewRequestFailure(awserr.New("EC2MetadataError", "failed to make EC2Metadata request", errors.New(b.String())),
r.HTTPResponse.StatusCode, r.RequestID)
} }
func validateEndpointHandler(r *request.Request) { func validateEndpointHandler(r *request.Request) {

View File

@ -0,0 +1,92 @@
package ec2metadata
import (
"net/http"
"sync/atomic"
"time"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/request"
)
// A tokenProvider struct provides access to EC2Metadata client
// and atomic instance of a token, along with configuredTTL for it.
// tokenProvider also provides an atomic flag to disable the
// fetch token operation.
// The disabled member will use 0 as false, and 1 as true.
type tokenProvider struct {
client *EC2Metadata
token atomic.Value
configuredTTL time.Duration
disabled uint32
}
// A ec2Token struct helps use of token in EC2 Metadata service ops
type ec2Token struct {
token string
credentials.Expiry
}
// newTokenProvider provides a pointer to a tokenProvider instance
func newTokenProvider(c *EC2Metadata, duration time.Duration) *tokenProvider {
return &tokenProvider{client: c, configuredTTL: duration}
}
// fetchTokenHandler fetches token for EC2Metadata service client by default.
func (t *tokenProvider) fetchTokenHandler(r *request.Request) {
// short-circuits to insecure data flow if tokenProvider is disabled.
if v := atomic.LoadUint32(&t.disabled); v == 1 {
return
}
if ec2Token, ok := t.token.Load().(ec2Token); ok && !ec2Token.IsExpired() {
r.HTTPRequest.Header.Set(tokenHeader, ec2Token.token)
return
}
output, err := t.client.getToken(r.Context(), t.configuredTTL)
if err != nil {
// change the disabled flag on token provider to true,
// when error is request timeout error.
if requestFailureError, ok := err.(awserr.RequestFailure); ok {
switch requestFailureError.StatusCode() {
case http.StatusForbidden, http.StatusNotFound, http.StatusMethodNotAllowed:
atomic.StoreUint32(&t.disabled, 1)
case http.StatusBadRequest:
r.Error = requestFailureError
}
// Check if request timed out while waiting for response
if e, ok := requestFailureError.OrigErr().(awserr.Error); ok {
if e.Code() == request.ErrCodeRequestError {
atomic.StoreUint32(&t.disabled, 1)
}
}
}
return
}
newToken := ec2Token{
token: output.Token,
}
newToken.SetExpiration(time.Now().Add(output.TTL), ttlExpirationWindow)
t.token.Store(newToken)
// Inject token header to the request.
if ec2Token, ok := t.token.Load().(ec2Token); ok {
r.HTTPRequest.Header.Set(tokenHeader, ec2Token.token)
}
}
// enableTokenProviderHandler enables the token provider
func (t *tokenProvider) enableTokenProviderHandler(r *request.Request) {
// If the error code status is 401, we enable the token provider
if e, ok := r.Error.(awserr.RequestFailure); ok && e != nil &&
e.StatusCode() == http.StatusUnauthorized {
atomic.StoreUint32(&t.disabled, 0)
}
}

View File

@ -83,6 +83,7 @@ func decodeV3Endpoints(modelDef modelDefinition, opts DecodeModelOptions) (Resol
p := &ps[i] p := &ps[i]
custAddEC2Metadata(p) custAddEC2Metadata(p)
custAddS3DualStack(p) custAddS3DualStack(p)
custRegionalS3(p)
custRmIotDataService(p) custRmIotDataService(p)
custFixAppAutoscalingChina(p) custFixAppAutoscalingChina(p)
custFixAppAutoscalingUsGov(p) custFixAppAutoscalingUsGov(p)
@ -100,6 +101,33 @@ func custAddS3DualStack(p *partition) {
custAddDualstack(p, "s3-control") custAddDualstack(p, "s3-control")
} }
func custRegionalS3(p *partition) {
if p.ID != "aws" {
return
}
service, ok := p.Services["s3"]
if !ok {
return
}
// If global endpoint already exists no customization needed.
if _, ok := service.Endpoints["aws-global"]; ok {
return
}
service.PartitionEndpoint = "aws-global"
service.Endpoints["us-east-1"] = endpoint{}
service.Endpoints["aws-global"] = endpoint{
Hostname: "s3.amazonaws.com",
CredentialScope: credentialScope{
Region: "us-east-1",
},
}
p.Services["s3"] = service
}
func custAddDualstack(p *partition, svcName string) { func custAddDualstack(p *partition, svcName string) {
s, ok := p.Services[svcName] s, ok := p.Services[svcName]
if !ok { if !ok {

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@ package endpoints
import ( import (
"fmt" "fmt"
"regexp" "regexp"
"strings"
"github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/awserr"
) )
@ -46,6 +47,108 @@ type Options struct {
// //
// This option is ignored if StrictMatching is enabled. // This option is ignored if StrictMatching is enabled.
ResolveUnknownService bool ResolveUnknownService bool
// STS Regional Endpoint flag helps with resolving the STS endpoint
STSRegionalEndpoint STSRegionalEndpoint
// S3 Regional Endpoint flag helps with resolving the S3 endpoint
S3UsEast1RegionalEndpoint S3UsEast1RegionalEndpoint
}
// STSRegionalEndpoint is an enum for the states of the STS Regional Endpoint
// options.
type STSRegionalEndpoint int
func (e STSRegionalEndpoint) String() string {
switch e {
case LegacySTSEndpoint:
return "legacy"
case RegionalSTSEndpoint:
return "regional"
case UnsetSTSEndpoint:
return ""
default:
return "unknown"
}
}
const (
// UnsetSTSEndpoint represents that STS Regional Endpoint flag is not specified.
UnsetSTSEndpoint STSRegionalEndpoint = iota
// LegacySTSEndpoint represents when STS Regional Endpoint flag is specified
// to use legacy endpoints.
LegacySTSEndpoint
// RegionalSTSEndpoint represents when STS Regional Endpoint flag is specified
// to use regional endpoints.
RegionalSTSEndpoint
)
// GetSTSRegionalEndpoint function returns the STSRegionalEndpointFlag based
// on the input string provided in env config or shared config by the user.
//
// `legacy`, `regional` are the only case-insensitive valid strings for
// resolving the STS regional Endpoint flag.
func GetSTSRegionalEndpoint(s string) (STSRegionalEndpoint, error) {
switch {
case strings.EqualFold(s, "legacy"):
return LegacySTSEndpoint, nil
case strings.EqualFold(s, "regional"):
return RegionalSTSEndpoint, nil
default:
return UnsetSTSEndpoint, fmt.Errorf("unable to resolve the value of STSRegionalEndpoint for %v", s)
}
}
// S3UsEast1RegionalEndpoint is an enum for the states of the S3 us-east-1
// Regional Endpoint options.
type S3UsEast1RegionalEndpoint int
func (e S3UsEast1RegionalEndpoint) String() string {
switch e {
case LegacyS3UsEast1Endpoint:
return "legacy"
case RegionalS3UsEast1Endpoint:
return "regional"
case UnsetS3UsEast1Endpoint:
return ""
default:
return "unknown"
}
}
const (
// UnsetS3UsEast1Endpoint represents that S3 Regional Endpoint flag is not
// specified.
UnsetS3UsEast1Endpoint S3UsEast1RegionalEndpoint = iota
// LegacyS3UsEast1Endpoint represents when S3 Regional Endpoint flag is
// specified to use legacy endpoints.
LegacyS3UsEast1Endpoint
// RegionalS3UsEast1Endpoint represents when S3 Regional Endpoint flag is
// specified to use regional endpoints.
RegionalS3UsEast1Endpoint
)
// GetS3UsEast1RegionalEndpoint function returns the S3UsEast1RegionalEndpointFlag based
// on the input string provided in env config or shared config by the user.
//
// `legacy`, `regional` are the only case-insensitive valid strings for
// resolving the S3 regional Endpoint flag.
func GetS3UsEast1RegionalEndpoint(s string) (S3UsEast1RegionalEndpoint, error) {
switch {
case strings.EqualFold(s, "legacy"):
return LegacyS3UsEast1Endpoint, nil
case strings.EqualFold(s, "regional"):
return RegionalS3UsEast1Endpoint, nil
default:
return UnsetS3UsEast1Endpoint,
fmt.Errorf("unable to resolve the value of S3UsEast1RegionalEndpoint for %v", s)
}
} }
// Set combines all of the option functions together. // Set combines all of the option functions together.
@ -79,6 +182,12 @@ func ResolveUnknownServiceOption(o *Options) {
o.ResolveUnknownService = true o.ResolveUnknownService = true
} }
// STSRegionalEndpointOption enables the STS endpoint resolver behavior to resolve
// STS endpoint to their regional endpoint, instead of the global endpoint.
func STSRegionalEndpointOption(o *Options) {
o.STSRegionalEndpoint = RegionalSTSEndpoint
}
// A Resolver provides the interface for functionality to resolve endpoints. // A Resolver provides the interface for functionality to resolve endpoints.
// The build in Partition and DefaultResolver return value satisfy this interface. // The build in Partition and DefaultResolver return value satisfy this interface.
type Resolver interface { type Resolver interface {
@ -194,7 +303,7 @@ func (p Partition) ID() string { return p.id }
// require the provided service and region to be known by the partition. // require the provided service and region to be known by the partition.
// If the endpoint cannot be strictly resolved an error will be returned. This // If the endpoint cannot be strictly resolved an error will be returned. This
// mode is useful to ensure the endpoint resolved is valid. Without // mode is useful to ensure the endpoint resolved is valid. Without
// StrictMatching enabled the endpoint returned my look valid but may not work. // StrictMatching enabled the endpoint returned may look valid but may not work.
// StrictMatching requires the SDK to be updated if you want to take advantage // StrictMatching requires the SDK to be updated if you want to take advantage
// of new regions and services expansions. // of new regions and services expansions.
// //
@ -208,7 +317,7 @@ func (p Partition) EndpointFor(service, region string, opts ...func(*Options)) (
// Regions returns a map of Regions indexed by their ID. This is useful for // Regions returns a map of Regions indexed by their ID. This is useful for
// enumerating over the regions in a partition. // enumerating over the regions in a partition.
func (p Partition) Regions() map[string]Region { func (p Partition) Regions() map[string]Region {
rs := map[string]Region{} rs := make(map[string]Region, len(p.p.Regions))
for id, r := range p.p.Regions { for id, r := range p.p.Regions {
rs[id] = Region{ rs[id] = Region{
id: id, id: id,
@ -223,7 +332,7 @@ func (p Partition) Regions() map[string]Region {
// Services returns a map of Service indexed by their ID. This is useful for // Services returns a map of Service indexed by their ID. This is useful for
// enumerating over the services in a partition. // enumerating over the services in a partition.
func (p Partition) Services() map[string]Service { func (p Partition) Services() map[string]Service {
ss := map[string]Service{} ss := make(map[string]Service, len(p.p.Services))
for id := range p.p.Services { for id := range p.p.Services {
ss[id] = Service{ ss[id] = Service{
id: id, id: id,
@ -310,7 +419,7 @@ func (s Service) Regions() map[string]Region {
// A region is the AWS region the service exists in. Whereas a Endpoint is // A region is the AWS region the service exists in. Whereas a Endpoint is
// an URL that can be resolved to a instance of a service. // an URL that can be resolved to a instance of a service.
func (s Service) Endpoints() map[string]Endpoint { func (s Service) Endpoints() map[string]Endpoint {
es := map[string]Endpoint{} es := make(map[string]Endpoint, len(s.p.Services[s.id].Endpoints))
for id := range s.p.Services[s.id].Endpoints { for id := range s.p.Services[s.id].Endpoints {
es[id] = Endpoint{ es[id] = Endpoint{
id: id, id: id,
@ -350,6 +459,9 @@ type ResolvedEndpoint struct {
// The endpoint URL // The endpoint URL
URL string URL string
// The endpoint partition
PartitionID string
// The region that should be used for signing requests. // The region that should be used for signing requests.
SigningRegion string SigningRegion string

View File

@ -0,0 +1,24 @@
package endpoints
var legacyGlobalRegions = map[string]map[string]struct{}{
"sts": {
"ap-northeast-1": {},
"ap-south-1": {},
"ap-southeast-1": {},
"ap-southeast-2": {},
"ca-central-1": {},
"eu-central-1": {},
"eu-north-1": {},
"eu-west-1": {},
"eu-west-2": {},
"eu-west-3": {},
"sa-east-1": {},
"us-east-1": {},
"us-east-2": {},
"us-west-1": {},
"us-west-2": {},
},
"s3": {
"us-east-1": {},
},
}

View File

@ -75,24 +75,56 @@ func (p partition) canResolveEndpoint(service, region string, strictMatch bool)
return p.RegionRegex.MatchString(region) return p.RegionRegex.MatchString(region)
} }
func allowLegacyEmptyRegion(service string) bool {
legacy := map[string]struct{}{
"budgets": {},
"ce": {},
"chime": {},
"cloudfront": {},
"ec2metadata": {},
"iam": {},
"importexport": {},
"organizations": {},
"route53": {},
"sts": {},
"support": {},
"waf": {},
}
_, allowed := legacy[service]
return allowed
}
func (p partition) EndpointFor(service, region string, opts ...func(*Options)) (resolved ResolvedEndpoint, err error) { func (p partition) EndpointFor(service, region string, opts ...func(*Options)) (resolved ResolvedEndpoint, err error) {
var opt Options var opt Options
opt.Set(opts...) opt.Set(opts...)
s, hasService := p.Services[service] s, hasService := p.Services[service]
if !(hasService || opt.ResolveUnknownService) { if len(service) == 0 || !(hasService || opt.ResolveUnknownService) {
// Only return error if the resolver will not fallback to creating // Only return error if the resolver will not fallback to creating
// endpoint based on service endpoint ID passed in. // endpoint based on service endpoint ID passed in.
return resolved, NewUnknownServiceError(p.ID, service, serviceList(p.Services)) return resolved, NewUnknownServiceError(p.ID, service, serviceList(p.Services))
} }
if len(region) == 0 && allowLegacyEmptyRegion(service) && len(s.PartitionEndpoint) != 0 {
region = s.PartitionEndpoint
}
if (service == "sts" && opt.STSRegionalEndpoint != RegionalSTSEndpoint) ||
(service == "s3" && opt.S3UsEast1RegionalEndpoint != RegionalS3UsEast1Endpoint) {
if _, ok := legacyGlobalRegions[service][region]; ok {
region = "aws-global"
}
}
e, hasEndpoint := s.endpointForRegion(region) e, hasEndpoint := s.endpointForRegion(region)
if !hasEndpoint && opt.StrictMatching { if len(region) == 0 || (!hasEndpoint && opt.StrictMatching) {
return resolved, NewUnknownEndpointError(p.ID, service, region, endpointList(s.Endpoints)) return resolved, NewUnknownEndpointError(p.ID, service, region, endpointList(s.Endpoints))
} }
defs := []endpoint{p.Defaults, s.Defaults} defs := []endpoint{p.Defaults, s.Defaults}
return e.resolve(service, region, p.DNSSuffix, defs, opt), nil
return e.resolve(service, p.ID, region, p.DNSSuffix, defs, opt), nil
} }
func serviceList(ss services) []string { func serviceList(ss services) []string {
@ -201,7 +233,7 @@ func getByPriority(s []string, p []string, def string) string {
return s[0] return s[0]
} }
func (e endpoint) resolve(service, region, dnsSuffix string, defs []endpoint, opts Options) ResolvedEndpoint { func (e endpoint) resolve(service, partitionID, region, dnsSuffix string, defs []endpoint, opts Options) ResolvedEndpoint {
var merged endpoint var merged endpoint
for _, def := range defs { for _, def := range defs {
merged.mergeIn(def) merged.mergeIn(def)
@ -209,20 +241,6 @@ func (e endpoint) resolve(service, region, dnsSuffix string, defs []endpoint, op
merged.mergeIn(e) merged.mergeIn(e)
e = merged e = merged
hostname := e.Hostname
// Offset the hostname for dualstack if enabled
if opts.UseDualStack && e.HasDualStack == boxedTrue {
hostname = e.DualStackHostname
}
u := strings.Replace(hostname, "{service}", service, 1)
u = strings.Replace(u, "{region}", region, 1)
u = strings.Replace(u, "{dnsSuffix}", dnsSuffix, 1)
scheme := getEndpointScheme(e.Protocols, opts.DisableSSL)
u = fmt.Sprintf("%s://%s", scheme, u)
signingRegion := e.CredentialScope.Region signingRegion := e.CredentialScope.Region
if len(signingRegion) == 0 { if len(signingRegion) == 0 {
signingRegion = region signingRegion = region
@ -235,8 +253,23 @@ func (e endpoint) resolve(service, region, dnsSuffix string, defs []endpoint, op
signingNameDerived = true signingNameDerived = true
} }
hostname := e.Hostname
// Offset the hostname for dualstack if enabled
if opts.UseDualStack && e.HasDualStack == boxedTrue {
hostname = e.DualStackHostname
region = signingRegion
}
u := strings.Replace(hostname, "{service}", service, 1)
u = strings.Replace(u, "{region}", region, 1)
u = strings.Replace(u, "{dnsSuffix}", dnsSuffix, 1)
scheme := getEndpointScheme(e.Protocols, opts.DisableSSL)
u = fmt.Sprintf("%s://%s", scheme, u)
return ResolvedEndpoint{ return ResolvedEndpoint{
URL: u, URL: u,
PartitionID: partitionID,
SigningRegion: signingRegion, SigningRegion: signingRegion,
SigningName: signingName, SigningName: signingName,
SigningNameDerived: signingNameDerived, SigningNameDerived: signingNameDerived,

View File

@ -10,6 +10,7 @@ import (
type Handlers struct { type Handlers struct {
Validate HandlerList Validate HandlerList
Build HandlerList Build HandlerList
BuildStream HandlerList
Sign HandlerList Sign HandlerList
Send HandlerList Send HandlerList
ValidateResponse HandlerList ValidateResponse HandlerList
@ -28,6 +29,7 @@ func (h *Handlers) Copy() Handlers {
return Handlers{ return Handlers{
Validate: h.Validate.copy(), Validate: h.Validate.copy(),
Build: h.Build.copy(), Build: h.Build.copy(),
BuildStream: h.BuildStream.copy(),
Sign: h.Sign.copy(), Sign: h.Sign.copy(),
Send: h.Send.copy(), Send: h.Send.copy(),
ValidateResponse: h.ValidateResponse.copy(), ValidateResponse: h.ValidateResponse.copy(),
@ -46,6 +48,7 @@ func (h *Handlers) Copy() Handlers {
func (h *Handlers) Clear() { func (h *Handlers) Clear() {
h.Validate.Clear() h.Validate.Clear()
h.Build.Clear() h.Build.Clear()
h.BuildStream.Clear()
h.Send.Clear() h.Send.Clear()
h.Sign.Clear() h.Sign.Clear()
h.Unmarshal.Clear() h.Unmarshal.Clear()
@ -67,6 +70,9 @@ func (h *Handlers) IsEmpty() bool {
if h.Build.Len() != 0 { if h.Build.Len() != 0 {
return false return false
} }
if h.BuildStream.Len() != 0 {
return false
}
if h.Send.Len() != 0 { if h.Send.Len() != 0 {
return false return false
} }
@ -320,3 +326,18 @@ func MakeAddToUserAgentFreeFormHandler(s string) func(*Request) {
AddToUserAgent(r, s) AddToUserAgent(r, s)
} }
} }
// WithSetRequestHeaders updates the operation request's HTTP header to contain
// the header key value pairs provided. If the header key already exists in the
// request's HTTP header set, the existing value(s) will be replaced.
func WithSetRequestHeaders(h map[string]string) Option {
return withRequestHeader(h).SetRequestHeaders
}
type withRequestHeader map[string]string
func (h withRequestHeader) SetRequestHeaders(r *Request) {
for k, v := range h {
r.HTTPRequest.Header[k] = []string{v}
}
}

View File

@ -36,6 +36,10 @@ const (
// API request that was canceled. Requests given a aws.Context may // API request that was canceled. Requests given a aws.Context may
// return this error when canceled. // return this error when canceled.
CanceledErrorCode = "RequestCanceled" CanceledErrorCode = "RequestCanceled"
// ErrCodeRequestError is an error preventing the SDK from continuing to
// process the request.
ErrCodeRequestError = "RequestError"
) )
// A Request is the service request to be made. // A Request is the service request to be made.
@ -51,6 +55,7 @@ type Request struct {
HTTPRequest *http.Request HTTPRequest *http.Request
HTTPResponse *http.Response HTTPResponse *http.Response
Body io.ReadSeeker Body io.ReadSeeker
streamingBody io.ReadCloser
BodyStart int64 // offset from beginning of Body that the request body starts BodyStart int64 // offset from beginning of Body that the request body starts
Params interface{} Params interface{}
Error error Error error
@ -99,8 +104,12 @@ type Operation struct {
BeforePresignFn func(r *Request) error BeforePresignFn func(r *Request) error
} }
// New returns a new Request pointer for the service API // New returns a new Request pointer for the service API operation and
// operation and parameters. // parameters.
//
// A Retryer should be provided to direct how the request is retried. If
// Retryer is nil, a default no retry value will be used. You can use
// NoOpRetryer in the Client package to disable retry behavior directly.
// //
// Params is any value of input parameters to be the request payload. // Params is any value of input parameters to be the request payload.
// Data is pointer value to an object which the request's response // Data is pointer value to an object which the request's response
@ -108,6 +117,10 @@ type Operation struct {
func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers, func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request { retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request {
if retryer == nil {
retryer = noOpRetryer{}
}
method := operation.HTTPMethod method := operation.HTTPMethod
if method == "" { if method == "" {
method = "POST" method = "POST"
@ -122,8 +135,6 @@ func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
err = awserr.New("InvalidEndpointURL", "invalid endpoint uri", err) err = awserr.New("InvalidEndpointURL", "invalid endpoint uri", err)
} }
SanitizeHostForHeader(httpReq)
r := &Request{ r := &Request{
Config: cfg, Config: cfg,
ClientInfo: clientInfo, ClientInfo: clientInfo,
@ -287,6 +298,13 @@ func (r *Request) SetReaderBody(reader io.ReadSeeker) {
r.ResetBody() r.ResetBody()
} }
// SetStreamingBody set the reader to be used for the request that will stream
// bytes to the server. Request's Body must not be set to any reader.
func (r *Request) SetStreamingBody(reader io.ReadCloser) {
r.streamingBody = reader
r.SetReaderBody(aws.ReadSeekCloser(reader))
}
// Presign returns the request's signed URL. Error will be returned // Presign returns the request's signed URL. Error will be returned
// if the signing fails. The expire parameter is only used for presigned Amazon // if the signing fails. The expire parameter is only used for presigned Amazon
// S3 API requests. All other AWS services will use a fixed expiration // S3 API requests. All other AWS services will use a fixed expiration
@ -406,11 +424,17 @@ func (r *Request) Sign() error {
return r.Error return r.Error
} }
SanitizeHostForHeader(r.HTTPRequest)
r.Handlers.Sign.Run(r) r.Handlers.Sign.Run(r)
return r.Error return r.Error
} }
func (r *Request) getNextRequestBody() (body io.ReadCloser, err error) { func (r *Request) getNextRequestBody() (body io.ReadCloser, err error) {
if r.streamingBody != nil {
return r.streamingBody, nil
}
if r.safeBody != nil { if r.safeBody != nil {
r.safeBody.Close() r.safeBody.Close()
} }
@ -615,6 +639,10 @@ func getHost(r *http.Request) string {
return r.Host return r.Host
} }
if r.URL == nil {
return ""
}
return r.URL.Host return r.URL.Host
} }

View File

@ -17,11 +17,13 @@ import (
// does the pagination between API operations, and Paginator defines the // does the pagination between API operations, and Paginator defines the
// configuration that will be used per page request. // configuration that will be used per page request.
// //
// cont := true // for p.Next() {
// for p.Next() && cont {
// data := p.Page().(*s3.ListObjectsOutput) // data := p.Page().(*s3.ListObjectsOutput)
// // process the page's data // // process the page's data
// // ...
// // break out of loop to stop fetching additional pages
// } // }
//
// return p.Err() // return p.Err()
// //
// See service client API operation Pages methods for examples how the SDK will // See service client API operation Pages methods for examples how the SDK will

View File

@ -35,16 +35,47 @@ type Retryer interface {
} }
// WithRetryer sets a Retryer value to the given Config returning the Config // WithRetryer sets a Retryer value to the given Config returning the Config
// value for chaining. // value for chaining. The value must not be nil.
func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config { func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config {
if retryer == nil {
if cfg.Logger != nil {
cfg.Logger.Log("ERROR: Request.WithRetryer called with nil retryer. Replacing with retry disabled Retryer.")
}
retryer = noOpRetryer{}
}
cfg.Retryer = retryer cfg.Retryer = retryer
return cfg return cfg
}
// noOpRetryer is a internal no op retryer used when a request is created
// without a retryer.
//
// Provides a retryer that performs no retries.
// It should be used when we do not want retries to be performed.
type noOpRetryer struct{}
// MaxRetries returns the number of maximum returns the service will use to make
// an individual API; For NoOpRetryer the MaxRetries will always be zero.
func (d noOpRetryer) MaxRetries() int {
return 0
}
// ShouldRetry will always return false for NoOpRetryer, as it should never retry.
func (d noOpRetryer) ShouldRetry(_ *Request) bool {
return false
}
// RetryRules returns the delay duration before retrying this request again;
// since NoOpRetryer does not retry, RetryRules always returns 0.
func (d noOpRetryer) RetryRules(_ *Request) time.Duration {
return 0
} }
// retryableCodes is a collection of service response codes which are retry-able // retryableCodes is a collection of service response codes which are retry-able
// without any further action. // without any further action.
var retryableCodes = map[string]struct{}{ var retryableCodes = map[string]struct{}{
"RequestError": {}, ErrCodeRequestError: {},
"RequestTimeout": {}, "RequestTimeout": {},
ErrCodeResponseTimeout: {}, ErrCodeResponseTimeout: {},
"RequestTimeoutException": {}, // Glacier's flavor of RequestTimeout "RequestTimeoutException": {}, // Glacier's flavor of RequestTimeout
@ -52,6 +83,7 @@ var retryableCodes = map[string]struct{}{
var throttleCodes = map[string]struct{}{ var throttleCodes = map[string]struct{}{
"ProvisionedThroughputExceededException": {}, "ProvisionedThroughputExceededException": {},
"ThrottledException": {}, // SNS, XRay, ResourceGroupsTagging API
"Throttling": {}, "Throttling": {},
"ThrottlingException": {}, "ThrottlingException": {},
"RequestLimitExceeded": {}, "RequestLimitExceeded": {},
@ -60,6 +92,7 @@ var throttleCodes = map[string]struct{}{
"TooManyRequestsException": {}, // Lambda functions "TooManyRequestsException": {}, // Lambda functions
"PriorRequestNotComplete": {}, // Route53 "PriorRequestNotComplete": {}, // Route53
"TransactionInProgressException": {}, "TransactionInProgressException": {},
"EC2ThrottledException": {}, // EC2
} }
// credsExpiredCodes is a collection of error codes which signify the credentials // credsExpiredCodes is a collection of error codes which signify the credentials
@ -145,8 +178,8 @@ func shouldRetryError(origErr error) bool {
origErr := err.OrigErr() origErr := err.OrigErr()
var shouldRetry bool var shouldRetry bool
if origErr != nil { if origErr != nil {
shouldRetry := shouldRetryError(origErr) shouldRetry = shouldRetryError(origErr)
if err.Code() == "RequestError" && !shouldRetry { if err.Code() == ErrCodeRequestError && !shouldRetry {
return false return false
} }
} }

View File

@ -3,6 +3,7 @@ package session
import ( import (
"fmt" "fmt"
"os" "os"
"time"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/awserr"
@ -47,10 +48,10 @@ func resolveCredentials(cfg *aws.Config,
} }
// WebIdentityEmptyRoleARNErr will occur if 'AWS_WEB_IDENTITY_TOKEN_FILE' was set but // WebIdentityEmptyRoleARNErr will occur if 'AWS_WEB_IDENTITY_TOKEN_FILE' was set but
// 'AWS_IAM_ROLE_ARN' was not set. // 'AWS_ROLE_ARN' was not set.
var WebIdentityEmptyRoleARNErr = awserr.New(stscreds.ErrCodeWebIdentity, "role ARN is not set", nil) var WebIdentityEmptyRoleARNErr = awserr.New(stscreds.ErrCodeWebIdentity, "role ARN is not set", nil)
// WebIdentityEmptyTokenFilePathErr will occur if 'AWS_IAM_ROLE_ARN' was set but // WebIdentityEmptyTokenFilePathErr will occur if 'AWS_ROLE_ARN' was set but
// 'AWS_WEB_IDENTITY_TOKEN_FILE' was not set. // 'AWS_WEB_IDENTITY_TOKEN_FILE' was not set.
var WebIdentityEmptyTokenFilePathErr = awserr.New(stscreds.ErrCodeWebIdentity, "token file path is not set", nil) var WebIdentityEmptyTokenFilePathErr = awserr.New(stscreds.ErrCodeWebIdentity, "token file path is not set", nil)
@ -206,7 +207,14 @@ func credsFromAssumeRole(cfg aws.Config,
sharedCfg.RoleARN, sharedCfg.RoleARN,
func(opt *stscreds.AssumeRoleProvider) { func(opt *stscreds.AssumeRoleProvider) {
opt.RoleSessionName = sharedCfg.RoleSessionName opt.RoleSessionName = sharedCfg.RoleSessionName
opt.Duration = sessOpts.AssumeRoleDuration
if sessOpts.AssumeRoleDuration == 0 &&
sharedCfg.AssumeRoleDuration != nil &&
*sharedCfg.AssumeRoleDuration/time.Minute > 15 {
opt.Duration = *sharedCfg.AssumeRoleDuration
} else if sessOpts.AssumeRoleDuration != 0 {
opt.Duration = sessOpts.AssumeRoleDuration
}
// Assume role with external ID // Assume role with external ID
if len(sharedCfg.ExternalID) > 0 { if len(sharedCfg.ExternalID) > 0 {

View File

@ -1,12 +1,15 @@
package session package session
import ( import (
"fmt"
"os" "os"
"strconv" "strconv"
"strings"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/defaults" "github.com/aws/aws-sdk-go/aws/defaults"
"github.com/aws/aws-sdk-go/aws/endpoints"
) )
// EnvProviderName provides a name of the provider when config is loaded from environment. // EnvProviderName provides a name of the provider when config is loaded from environment.
@ -125,6 +128,26 @@ type envConfig struct {
// //
// AWS_ROLE_SESSION_NAME=session_name // AWS_ROLE_SESSION_NAME=session_name
RoleSessionName string RoleSessionName string
// Specifies the STS Regional Endpoint flag for the SDK to resolve the endpoint
// for a service.
//
// AWS_STS_REGIONAL_ENDPOINTS=regional
// This can take value as `regional` or `legacy`
STSRegionalEndpoint endpoints.STSRegionalEndpoint
// Specifies the S3 Regional Endpoint flag for the SDK to resolve the
// endpoint for a service.
//
// AWS_S3_US_EAST_1_REGIONAL_ENDPOINT=regional
// This can take value as `regional` or `legacy`
S3UsEast1RegionalEndpoint endpoints.S3UsEast1RegionalEndpoint
// Specifies if the S3 service should allow ARNs to direct the region
// the client's requests are sent to.
//
// AWS_S3_USE_ARN_REGION=true
S3UseARNRegion bool
} }
var ( var (
@ -179,6 +202,15 @@ var (
roleSessionNameEnvKey = []string{ roleSessionNameEnvKey = []string{
"AWS_ROLE_SESSION_NAME", "AWS_ROLE_SESSION_NAME",
} }
stsRegionalEndpointKey = []string{
"AWS_STS_REGIONAL_ENDPOINTS",
}
s3UsEast1RegionalEndpoint = []string{
"AWS_S3_US_EAST_1_REGIONAL_ENDPOINT",
}
s3UseARNRegionEnvKey = []string{
"AWS_S3_USE_ARN_REGION",
}
) )
// loadEnvConfig retrieves the SDK's environment configuration. // loadEnvConfig retrieves the SDK's environment configuration.
@ -187,7 +219,7 @@ var (
// If the environment variable `AWS_SDK_LOAD_CONFIG` is set to a truthy value // If the environment variable `AWS_SDK_LOAD_CONFIG` is set to a truthy value
// the shared SDK config will be loaded in addition to the SDK's specific // the shared SDK config will be loaded in addition to the SDK's specific
// configuration values. // configuration values.
func loadEnvConfig() envConfig { func loadEnvConfig() (envConfig, error) {
enableSharedConfig, _ := strconv.ParseBool(os.Getenv("AWS_SDK_LOAD_CONFIG")) enableSharedConfig, _ := strconv.ParseBool(os.Getenv("AWS_SDK_LOAD_CONFIG"))
return envConfigLoad(enableSharedConfig) return envConfigLoad(enableSharedConfig)
} }
@ -198,11 +230,11 @@ func loadEnvConfig() envConfig {
// Loads the shared configuration in addition to the SDK's specific configuration. // Loads the shared configuration in addition to the SDK's specific configuration.
// This will load the same values as `loadEnvConfig` if the `AWS_SDK_LOAD_CONFIG` // This will load the same values as `loadEnvConfig` if the `AWS_SDK_LOAD_CONFIG`
// environment variable is set. // environment variable is set.
func loadSharedEnvConfig() envConfig { func loadSharedEnvConfig() (envConfig, error) {
return envConfigLoad(true) return envConfigLoad(true)
} }
func envConfigLoad(enableSharedConfig bool) envConfig { func envConfigLoad(enableSharedConfig bool) (envConfig, error) {
cfg := envConfig{} cfg := envConfig{}
cfg.EnableSharedConfig = enableSharedConfig cfg.EnableSharedConfig = enableSharedConfig
@ -264,12 +296,48 @@ func envConfigLoad(enableSharedConfig bool) envConfig {
cfg.CustomCABundle = os.Getenv("AWS_CA_BUNDLE") cfg.CustomCABundle = os.Getenv("AWS_CA_BUNDLE")
return cfg var err error
// STS Regional Endpoint variable
for _, k := range stsRegionalEndpointKey {
if v := os.Getenv(k); len(v) != 0 {
cfg.STSRegionalEndpoint, err = endpoints.GetSTSRegionalEndpoint(v)
if err != nil {
return cfg, fmt.Errorf("failed to load, %v from env config, %v", k, err)
}
}
}
// S3 Regional Endpoint variable
for _, k := range s3UsEast1RegionalEndpoint {
if v := os.Getenv(k); len(v) != 0 {
cfg.S3UsEast1RegionalEndpoint, err = endpoints.GetS3UsEast1RegionalEndpoint(v)
if err != nil {
return cfg, fmt.Errorf("failed to load, %v from env config, %v", k, err)
}
}
}
var s3UseARNRegion string
setFromEnvVal(&s3UseARNRegion, s3UseARNRegionEnvKey)
if len(s3UseARNRegion) != 0 {
switch {
case strings.EqualFold(s3UseARNRegion, "false"):
cfg.S3UseARNRegion = false
case strings.EqualFold(s3UseARNRegion, "true"):
cfg.S3UseARNRegion = true
default:
return envConfig{}, fmt.Errorf(
"invalid value for environment variable, %s=%s, need true or false",
s3UseARNRegionEnvKey[0], s3UseARNRegion)
}
}
return cfg, nil
} }
func setFromEnvVal(dst *string, keys []string) { func setFromEnvVal(dst *string, keys []string) {
for _, k := range keys { for _, k := range keys {
if v := os.Getenv(k); len(v) > 0 { if v := os.Getenv(k); len(v) != 0 {
*dst = v *dst = v
break break
} }

View File

@ -73,7 +73,7 @@ type Session struct {
// func is called instead of waiting to receive an error until a request is made. // func is called instead of waiting to receive an error until a request is made.
func New(cfgs ...*aws.Config) *Session { func New(cfgs ...*aws.Config) *Session {
// load initial config from environment // load initial config from environment
envCfg := loadEnvConfig() envCfg, envErr := loadEnvConfig()
if envCfg.EnableSharedConfig { if envCfg.EnableSharedConfig {
var cfg aws.Config var cfg aws.Config
@ -93,17 +93,17 @@ func New(cfgs ...*aws.Config) *Session {
// Session creation failed, need to report the error and prevent // Session creation failed, need to report the error and prevent
// any requests from succeeding. // any requests from succeeding.
s = &Session{Config: defaults.Config()} s = &Session{Config: defaults.Config()}
s.Config.MergeIn(cfgs...) s.logDeprecatedNewSessionError(msg, err, cfgs)
s.Config.Logger.Log("ERROR:", msg, "Error:", err)
s.Handlers.Validate.PushBack(func(r *request.Request) {
r.Error = err
})
} }
return s return s
} }
s := deprecatedNewSession(cfgs...) s := deprecatedNewSession(cfgs...)
if envErr != nil {
msg := "failed to load env config"
s.logDeprecatedNewSessionError(msg, envErr, cfgs)
}
if csmCfg, err := loadCSMConfig(envCfg, []string{}); err != nil { if csmCfg, err := loadCSMConfig(envCfg, []string{}); err != nil {
if l := s.Config.Logger; l != nil { if l := s.Config.Logger; l != nil {
@ -112,11 +112,8 @@ func New(cfgs ...*aws.Config) *Session {
} else if csmCfg.Enabled { } else if csmCfg.Enabled {
err := enableCSM(&s.Handlers, csmCfg, s.Config.Logger) err := enableCSM(&s.Handlers, csmCfg, s.Config.Logger)
if err != nil { if err != nil {
err = fmt.Errorf("failed to enable CSM, %v", err) msg := "failed to enable CSM"
s.Config.Logger.Log("ERROR:", err.Error()) s.logDeprecatedNewSessionError(msg, err, cfgs)
s.Handlers.Validate.PushBack(func(r *request.Request) {
r.Error = err
})
} }
} }
@ -279,10 +276,17 @@ type Options struct {
// })) // }))
func NewSessionWithOptions(opts Options) (*Session, error) { func NewSessionWithOptions(opts Options) (*Session, error) {
var envCfg envConfig var envCfg envConfig
var err error
if opts.SharedConfigState == SharedConfigEnable { if opts.SharedConfigState == SharedConfigEnable {
envCfg = loadSharedEnvConfig() envCfg, err = loadSharedEnvConfig()
if err != nil {
return nil, fmt.Errorf("failed to load shared config, %v", err)
}
} else { } else {
envCfg = loadEnvConfig() envCfg, err = loadEnvConfig()
if err != nil {
return nil, fmt.Errorf("failed to load environment config, %v", err)
}
} }
if len(opts.Profile) != 0 { if len(opts.Profile) != 0 {
@ -550,6 +554,22 @@ func mergeConfigSrcs(cfg, userCfg *aws.Config,
} }
} }
// Regional Endpoint flag for STS endpoint resolving
mergeSTSRegionalEndpointConfig(cfg, []endpoints.STSRegionalEndpoint{
userCfg.STSRegionalEndpoint,
envCfg.STSRegionalEndpoint,
sharedCfg.STSRegionalEndpoint,
endpoints.LegacySTSEndpoint,
})
// Regional Endpoint flag for S3 endpoint resolving
mergeS3UsEast1RegionalEndpointConfig(cfg, []endpoints.S3UsEast1RegionalEndpoint{
userCfg.S3UsEast1RegionalEndpoint,
envCfg.S3UsEast1RegionalEndpoint,
sharedCfg.S3UsEast1RegionalEndpoint,
endpoints.LegacyS3UsEast1Endpoint,
})
// Configure credentials if not already set by the user when creating the // Configure credentials if not already set by the user when creating the
// Session. // Session.
if cfg.Credentials == credentials.AnonymousCredentials && userCfg.Credentials == nil { if cfg.Credentials == credentials.AnonymousCredentials && userCfg.Credentials == nil {
@ -560,9 +580,35 @@ func mergeConfigSrcs(cfg, userCfg *aws.Config,
cfg.Credentials = creds cfg.Credentials = creds
} }
cfg.S3UseARNRegion = userCfg.S3UseARNRegion
if cfg.S3UseARNRegion == nil {
cfg.S3UseARNRegion = &envCfg.S3UseARNRegion
}
if cfg.S3UseARNRegion == nil {
cfg.S3UseARNRegion = &sharedCfg.S3UseARNRegion
}
return nil return nil
} }
func mergeSTSRegionalEndpointConfig(cfg *aws.Config, values []endpoints.STSRegionalEndpoint) {
for _, v := range values {
if v != endpoints.UnsetSTSEndpoint {
cfg.STSRegionalEndpoint = v
break
}
}
}
func mergeS3UsEast1RegionalEndpointConfig(cfg *aws.Config, values []endpoints.S3UsEast1RegionalEndpoint) {
for _, v := range values {
if v != endpoints.UnsetS3UsEast1Endpoint {
cfg.S3UsEast1RegionalEndpoint = v
break
}
}
}
func initHandlers(s *Session) { func initHandlers(s *Session) {
// Add the Validate parameter handler if it is not disabled. // Add the Validate parameter handler if it is not disabled.
s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler) s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler)
@ -591,47 +637,67 @@ func (s *Session) Copy(cfgs ...*aws.Config) *Session {
// ClientConfig satisfies the client.ConfigProvider interface and is used to // ClientConfig satisfies the client.ConfigProvider interface and is used to
// configure the service client instances. Passing the Session to the service // configure the service client instances. Passing the Session to the service
// client's constructor (New) will use this method to configure the client. // client's constructor (New) will use this method to configure the client.
func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config { func (s *Session) ClientConfig(service string, cfgs ...*aws.Config) client.Config {
// Backwards compatibility, the error will be eaten if user calls ClientConfig
// directly. All SDK services will use ClientconfigWithError.
cfg, _ := s.clientConfigWithErr(serviceName, cfgs...)
return cfg
}
func (s *Session) clientConfigWithErr(serviceName string, cfgs ...*aws.Config) (client.Config, error) {
s = s.Copy(cfgs...) s = s.Copy(cfgs...)
var resolved endpoints.ResolvedEndpoint
var err error
region := aws.StringValue(s.Config.Region) region := aws.StringValue(s.Config.Region)
resolved, err := s.resolveEndpoint(service, region, s.Config)
if endpoint := aws.StringValue(s.Config.Endpoint); len(endpoint) != 0 { if err != nil {
resolved.URL = endpoints.AddScheme(endpoint, aws.BoolValue(s.Config.DisableSSL)) s.Handlers.Validate.PushBack(func(r *request.Request) {
resolved.SigningRegion = region if len(r.ClientInfo.Endpoint) != 0 {
} else { // Error occurred while resolving endpoint, but the request
resolved, err = s.Config.EndpointResolver.EndpointFor( // being invoked has had an endpoint specified after the client
serviceName, region, // was created.
func(opt *endpoints.Options) { return
opt.DisableSSL = aws.BoolValue(s.Config.DisableSSL) }
opt.UseDualStack = aws.BoolValue(s.Config.UseDualStack) r.Error = err
})
// Support the condition where the service is modeled but its
// endpoint metadata is not available.
opt.ResolveUnknownService = true
},
)
} }
return client.Config{ return client.Config{
Config: s.Config, Config: s.Config,
Handlers: s.Handlers, Handlers: s.Handlers,
PartitionID: resolved.PartitionID,
Endpoint: resolved.URL, Endpoint: resolved.URL,
SigningRegion: resolved.SigningRegion, SigningRegion: resolved.SigningRegion,
SigningNameDerived: resolved.SigningNameDerived, SigningNameDerived: resolved.SigningNameDerived,
SigningName: resolved.SigningName, SigningName: resolved.SigningName,
}, err }
}
func (s *Session) resolveEndpoint(service, region string, cfg *aws.Config) (endpoints.ResolvedEndpoint, error) {
if ep := aws.StringValue(cfg.Endpoint); len(ep) != 0 {
return endpoints.ResolvedEndpoint{
URL: endpoints.AddScheme(ep, aws.BoolValue(cfg.DisableSSL)),
SigningRegion: region,
}, nil
}
resolved, err := cfg.EndpointResolver.EndpointFor(service, region,
func(opt *endpoints.Options) {
opt.DisableSSL = aws.BoolValue(cfg.DisableSSL)
opt.UseDualStack = aws.BoolValue(cfg.UseDualStack)
// Support for STSRegionalEndpoint where the STSRegionalEndpoint is
// provided in envConfig or sharedConfig with envConfig getting
// precedence.
opt.STSRegionalEndpoint = cfg.STSRegionalEndpoint
// Support for S3UsEast1RegionalEndpoint where the S3UsEast1RegionalEndpoint is
// provided in envConfig or sharedConfig with envConfig getting
// precedence.
opt.S3UsEast1RegionalEndpoint = cfg.S3UsEast1RegionalEndpoint
// Support the condition where the service is modeled but its
// endpoint metadata is not available.
opt.ResolveUnknownService = true
},
)
if err != nil {
return endpoints.ResolvedEndpoint{}, err
}
return resolved, nil
} }
// ClientConfigNoResolveEndpoint is the same as ClientConfig with the exception // ClientConfigNoResolveEndpoint is the same as ClientConfig with the exception
@ -641,12 +707,9 @@ func (s *Session) ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) client.Conf
s = s.Copy(cfgs...) s = s.Copy(cfgs...)
var resolved endpoints.ResolvedEndpoint var resolved endpoints.ResolvedEndpoint
region := aws.StringValue(s.Config.Region)
if ep := aws.StringValue(s.Config.Endpoint); len(ep) > 0 { if ep := aws.StringValue(s.Config.Endpoint); len(ep) > 0 {
resolved.URL = endpoints.AddScheme(ep, aws.BoolValue(s.Config.DisableSSL)) resolved.URL = endpoints.AddScheme(ep, aws.BoolValue(s.Config.DisableSSL))
resolved.SigningRegion = region resolved.SigningRegion = aws.StringValue(s.Config.Region)
} }
return client.Config{ return client.Config{
@ -658,3 +721,14 @@ func (s *Session) ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) client.Conf
SigningName: resolved.SigningName, SigningName: resolved.SigningName,
} }
} }
// logDeprecatedNewSessionError function enables error handling for session
func (s *Session) logDeprecatedNewSessionError(msg string, err error, cfgs []*aws.Config) {
// Session creation failed, need to report the error and prevent
// any requests from succeeding.
s.Config.MergeIn(cfgs...)
s.Config.Logger.Log("ERROR:", msg, "Error:", err)
s.Handlers.Validate.PushBack(func(r *request.Request) {
r.Error = err
})
}

View File

@ -2,9 +2,11 @@ package session
import ( import (
"fmt" "fmt"
"time"
"github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/internal/ini" "github.com/aws/aws-sdk-go/internal/ini"
) )
@ -15,12 +17,13 @@ const (
sessionTokenKey = `aws_session_token` // optional sessionTokenKey = `aws_session_token` // optional
// Assume Role Credentials group // Assume Role Credentials group
roleArnKey = `role_arn` // group required roleArnKey = `role_arn` // group required
sourceProfileKey = `source_profile` // group required (or credential_source) sourceProfileKey = `source_profile` // group required (or credential_source)
credentialSourceKey = `credential_source` // group required (or source_profile) credentialSourceKey = `credential_source` // group required (or source_profile)
externalIDKey = `external_id` // optional externalIDKey = `external_id` // optional
mfaSerialKey = `mfa_serial` // optional mfaSerialKey = `mfa_serial` // optional
roleSessionNameKey = `role_session_name` // optional roleSessionNameKey = `role_session_name` // optional
roleDurationSecondsKey = "duration_seconds" // optional
// CSM options // CSM options
csmEnabledKey = `csm_enabled` csmEnabledKey = `csm_enabled`
@ -40,10 +43,19 @@ const (
// Web Identity Token File // Web Identity Token File
webIdentityTokenFileKey = `web_identity_token_file` // optional webIdentityTokenFileKey = `web_identity_token_file` // optional
// Additional config fields for regional or legacy endpoints
stsRegionalEndpointSharedKey = `sts_regional_endpoints`
// Additional config fields for regional or legacy endpoints
s3UsEast1RegionalSharedKey = `s3_us_east_1_regional_endpoint`
// DefaultSharedConfigProfile is the default profile to be used when // DefaultSharedConfigProfile is the default profile to be used when
// loading configuration from the config files if another profile name // loading configuration from the config files if another profile name
// is not provided. // is not provided.
DefaultSharedConfigProfile = `default` DefaultSharedConfigProfile = `default`
// S3 ARN Region Usage
s3UseARNRegionKey = "s3_use_arn_region"
) )
// sharedConfig represents the configuration fields of the SDK config files. // sharedConfig represents the configuration fields of the SDK config files.
@ -63,10 +75,11 @@ type sharedConfig struct {
CredentialProcess string CredentialProcess string
WebIdentityTokenFile string WebIdentityTokenFile string
RoleARN string RoleARN string
RoleSessionName string RoleSessionName string
ExternalID string ExternalID string
MFASerial string MFASerial string
AssumeRoleDuration *time.Duration
SourceProfileName string SourceProfileName string
SourceProfile *sharedConfig SourceProfile *sharedConfig
@ -88,6 +101,24 @@ type sharedConfig struct {
CSMHost string CSMHost string
CSMPort string CSMPort string
CSMClientID string CSMClientID string
// Specifies the Regional Endpoint flag for the SDK to resolve the endpoint for a service
//
// sts_regional_endpoints = regional
// This can take value as `LegacySTSEndpoint` or `RegionalSTSEndpoint`
STSRegionalEndpoint endpoints.STSRegionalEndpoint
// Specifies the Regional Endpoint flag for the SDK to resolve the endpoint for a service
//
// s3_us_east_1_regional_endpoint = regional
// This can take value as `LegacyS3UsEast1Endpoint` or `RegionalS3UsEast1Endpoint`
S3UsEast1RegionalEndpoint endpoints.S3UsEast1RegionalEndpoint
// Specifies if the S3 service should allow ARNs to direct the region
// the client's requests are sent to.
//
// s3_use_arn_region=true
S3UseARNRegion bool
} }
type sharedConfigFile struct { type sharedConfigFile struct {
@ -244,8 +275,30 @@ func (cfg *sharedConfig) setFromIniFile(profile string, file sharedConfigFile, e
updateString(&cfg.RoleSessionName, section, roleSessionNameKey) updateString(&cfg.RoleSessionName, section, roleSessionNameKey)
updateString(&cfg.SourceProfileName, section, sourceProfileKey) updateString(&cfg.SourceProfileName, section, sourceProfileKey)
updateString(&cfg.CredentialSource, section, credentialSourceKey) updateString(&cfg.CredentialSource, section, credentialSourceKey)
updateString(&cfg.Region, section, regionKey) updateString(&cfg.Region, section, regionKey)
if section.Has(roleDurationSecondsKey) {
d := time.Duration(section.Int(roleDurationSecondsKey)) * time.Second
cfg.AssumeRoleDuration = &d
}
if v := section.String(stsRegionalEndpointSharedKey); len(v) != 0 {
sre, err := endpoints.GetSTSRegionalEndpoint(v)
if err != nil {
return fmt.Errorf("failed to load %s from shared config, %s, %v",
stsRegionalEndpointSharedKey, file.Filename, err)
}
cfg.STSRegionalEndpoint = sre
}
if v := section.String(s3UsEast1RegionalSharedKey); len(v) != 0 {
sre, err := endpoints.GetS3UsEast1RegionalEndpoint(v)
if err != nil {
return fmt.Errorf("failed to load %s from shared config, %s, %v",
s3UsEast1RegionalSharedKey, file.Filename, err)
}
cfg.S3UsEast1RegionalEndpoint = sre
}
} }
updateString(&cfg.CredentialProcess, section, credentialProcessKey) updateString(&cfg.CredentialProcess, section, credentialProcessKey)
@ -271,6 +324,8 @@ func (cfg *sharedConfig) setFromIniFile(profile string, file sharedConfigFile, e
updateString(&cfg.CSMPort, section, csmPortKey) updateString(&cfg.CSMPort, section, csmPortKey)
updateString(&cfg.CSMClientID, section, csmClientIDKey) updateString(&cfg.CSMClientID, section, csmClientIDKey)
updateBool(&cfg.S3UseARNRegion, section, s3UseARNRegionKey)
return nil return nil
} }
@ -363,6 +418,15 @@ func updateString(dst *string, section ini.Section, key string) {
*dst = section.String(key) *dst = section.String(key)
} }
// updateBool will only update the dst with the value in the section key, key
// is present in the section.
func updateBool(dst *bool, section ini.Section, key string) {
if !section.Has(key) {
return
}
*dst = section.Bool(key)
}
// updateBoolPtr will only update the dst with the value in the section key, // updateBoolPtr will only update the dst with the value in the section key,
// key is present in the section. // key is present in the section.
func updateBoolPtr(dst **bool, section ini.Section, key string) { func updateBoolPtr(dst **bool, section ini.Section, key string) {

View File

@ -1,8 +1,7 @@
package v4 package v4
import ( import (
"net/http" "github.com/aws/aws-sdk-go/internal/strings"
"strings"
) )
// validator houses a set of rule needed for validation of a // validator houses a set of rule needed for validation of a
@ -61,7 +60,7 @@ type patterns []string
// been found // been found
func (p patterns) IsValid(value string) bool { func (p patterns) IsValid(value string) bool {
for _, pattern := range p { for _, pattern := range p {
if strings.HasPrefix(http.CanonicalHeaderKey(value), pattern) { if strings.HasPrefixFold(value, pattern) {
return true return true
} }
} }

View File

@ -0,0 +1,13 @@
// +build !go1.7
package v4
import (
"net/http"
"github.com/aws/aws-sdk-go/aws"
)
func requestContext(r *http.Request) aws.Context {
return aws.BackgroundContext()
}

View File

@ -0,0 +1,13 @@
// +build go1.7
package v4
import (
"net/http"
"github.com/aws/aws-sdk-go/aws"
)
func requestContext(r *http.Request) aws.Context {
return r.Context()
}

View File

@ -0,0 +1,63 @@
package v4
import (
"encoding/hex"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws/credentials"
)
type credentialValueProvider interface {
Get() (credentials.Value, error)
}
// StreamSigner implements signing of event stream encoded payloads
type StreamSigner struct {
region string
service string
credentials credentialValueProvider
prevSig []byte
}
// NewStreamSigner creates a SigV4 signer used to sign Event Stream encoded messages
func NewStreamSigner(region, service string, seedSignature []byte, credentials *credentials.Credentials) *StreamSigner {
return &StreamSigner{
region: region,
service: service,
credentials: credentials,
prevSig: seedSignature,
}
}
// GetSignature takes an event stream encoded headers and payload and returns a signature
func (s *StreamSigner) GetSignature(headers, payload []byte, date time.Time) ([]byte, error) {
credValue, err := s.credentials.Get()
if err != nil {
return nil, err
}
sigKey := deriveSigningKey(s.region, s.service, credValue.SecretAccessKey, date)
keyPath := buildSigningScope(s.region, s.service, date)
stringToSign := buildEventStreamStringToSign(headers, payload, s.prevSig, keyPath, date)
signature := hmacSHA256(sigKey, []byte(stringToSign))
s.prevSig = signature
return signature, nil
}
func buildEventStreamStringToSign(headers, payload, prevSig []byte, scope string, date time.Time) string {
return strings.Join([]string{
"AWS4-HMAC-SHA256-PAYLOAD",
formatTime(date),
scope,
hex.EncodeToString(prevSig),
hex.EncodeToString(hashSHA256(headers)),
hex.EncodeToString(hashSHA256(payload)),
}, "\n")
}

View File

@ -76,9 +76,14 @@ import (
) )
const ( const (
authorizationHeader = "Authorization"
authHeaderSignatureElem = "Signature="
signatureQueryKey = "X-Amz-Signature"
authHeaderPrefix = "AWS4-HMAC-SHA256" authHeaderPrefix = "AWS4-HMAC-SHA256"
timeFormat = "20060102T150405Z" timeFormat = "20060102T150405Z"
shortTimeFormat = "20060102" shortTimeFormat = "20060102"
awsV4Request = "aws4_request"
// emptyStringSHA256 is a SHA256 of an empty string // emptyStringSHA256 is a SHA256 of an empty string
emptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855` emptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`
@ -87,9 +92,9 @@ const (
var ignoredHeaders = rules{ var ignoredHeaders = rules{
blacklist{ blacklist{
mapRule{ mapRule{
"Authorization": struct{}{}, authorizationHeader: struct{}{},
"User-Agent": struct{}{}, "User-Agent": struct{}{},
"X-Amzn-Trace-Id": struct{}{}, "X-Amzn-Trace-Id": struct{}{},
}, },
}, },
} }
@ -229,11 +234,9 @@ type signingCtx struct {
DisableURIPathEscaping bool DisableURIPathEscaping bool
credValues credentials.Value credValues credentials.Value
isPresign bool isPresign bool
formattedTime string unsignedPayload bool
formattedShortTime string
unsignedPayload bool
bodyDigest string bodyDigest string
signedHeaders string signedHeaders string
@ -337,7 +340,7 @@ func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, regi
} }
var err error var err error
ctx.credValues, err = v4.Credentials.Get() ctx.credValues, err = v4.Credentials.GetWithContext(requestContext(r))
if err != nil { if err != nil {
return http.Header{}, err return http.Header{}, err
} }
@ -532,39 +535,56 @@ func (ctx *signingCtx) build(disableHeaderHoisting bool) error {
ctx.buildSignature() // depends on string to sign ctx.buildSignature() // depends on string to sign
if ctx.isPresign { if ctx.isPresign {
ctx.Request.URL.RawQuery += "&X-Amz-Signature=" + ctx.signature ctx.Request.URL.RawQuery += "&" + signatureQueryKey + "=" + ctx.signature
} else { } else {
parts := []string{ parts := []string{
authHeaderPrefix + " Credential=" + ctx.credValues.AccessKeyID + "/" + ctx.credentialString, authHeaderPrefix + " Credential=" + ctx.credValues.AccessKeyID + "/" + ctx.credentialString,
"SignedHeaders=" + ctx.signedHeaders, "SignedHeaders=" + ctx.signedHeaders,
"Signature=" + ctx.signature, authHeaderSignatureElem + ctx.signature,
} }
ctx.Request.Header.Set("Authorization", strings.Join(parts, ", ")) ctx.Request.Header.Set(authorizationHeader, strings.Join(parts, ", "))
} }
return nil return nil
} }
func (ctx *signingCtx) buildTime() { // GetSignedRequestSignature attempts to extract the signature of the request.
ctx.formattedTime = ctx.Time.UTC().Format(timeFormat) // Returning an error if the request is unsigned, or unable to extract the
ctx.formattedShortTime = ctx.Time.UTC().Format(shortTimeFormat) // signature.
func GetSignedRequestSignature(r *http.Request) ([]byte, error) {
if auth := r.Header.Get(authorizationHeader); len(auth) != 0 {
ps := strings.Split(auth, ", ")
for _, p := range ps {
if idx := strings.Index(p, authHeaderSignatureElem); idx >= 0 {
sig := p[len(authHeaderSignatureElem):]
if len(sig) == 0 {
return nil, fmt.Errorf("invalid request signature authorization header")
}
return hex.DecodeString(sig)
}
}
}
if sig := r.URL.Query().Get("X-Amz-Signature"); len(sig) != 0 {
return hex.DecodeString(sig)
}
return nil, fmt.Errorf("request not signed")
}
func (ctx *signingCtx) buildTime() {
if ctx.isPresign { if ctx.isPresign {
duration := int64(ctx.ExpireTime / time.Second) duration := int64(ctx.ExpireTime / time.Second)
ctx.Query.Set("X-Amz-Date", ctx.formattedTime) ctx.Query.Set("X-Amz-Date", formatTime(ctx.Time))
ctx.Query.Set("X-Amz-Expires", strconv.FormatInt(duration, 10)) ctx.Query.Set("X-Amz-Expires", strconv.FormatInt(duration, 10))
} else { } else {
ctx.Request.Header.Set("X-Amz-Date", ctx.formattedTime) ctx.Request.Header.Set("X-Amz-Date", formatTime(ctx.Time))
} }
} }
func (ctx *signingCtx) buildCredentialString() { func (ctx *signingCtx) buildCredentialString() {
ctx.credentialString = strings.Join([]string{ ctx.credentialString = buildSigningScope(ctx.Region, ctx.ServiceName, ctx.Time)
ctx.formattedShortTime,
ctx.Region,
ctx.ServiceName,
"aws4_request",
}, "/")
if ctx.isPresign { if ctx.isPresign {
ctx.Query.Set("X-Amz-Credential", ctx.credValues.AccessKeyID+"/"+ctx.credentialString) ctx.Query.Set("X-Amz-Credential", ctx.credValues.AccessKeyID+"/"+ctx.credentialString)
@ -588,8 +608,7 @@ func (ctx *signingCtx) buildCanonicalHeaders(r rule, header http.Header) {
var headers []string var headers []string
headers = append(headers, "host") headers = append(headers, "host")
for k, v := range header { for k, v := range header {
canonicalKey := http.CanonicalHeaderKey(k) if !r.IsValid(k) {
if !r.IsValid(canonicalKey) {
continue // ignored header continue // ignored header
} }
if ctx.SignedHeaderVals == nil { if ctx.SignedHeaderVals == nil {
@ -653,19 +672,15 @@ func (ctx *signingCtx) buildCanonicalString() {
func (ctx *signingCtx) buildStringToSign() { func (ctx *signingCtx) buildStringToSign() {
ctx.stringToSign = strings.Join([]string{ ctx.stringToSign = strings.Join([]string{
authHeaderPrefix, authHeaderPrefix,
ctx.formattedTime, formatTime(ctx.Time),
ctx.credentialString, ctx.credentialString,
hex.EncodeToString(makeSha256([]byte(ctx.canonicalString))), hex.EncodeToString(hashSHA256([]byte(ctx.canonicalString))),
}, "\n") }, "\n")
} }
func (ctx *signingCtx) buildSignature() { func (ctx *signingCtx) buildSignature() {
secret := ctx.credValues.SecretAccessKey creds := deriveSigningKey(ctx.Region, ctx.ServiceName, ctx.credValues.SecretAccessKey, ctx.Time)
date := makeHmac([]byte("AWS4"+secret), []byte(ctx.formattedShortTime)) signature := hmacSHA256(creds, []byte(ctx.stringToSign))
region := makeHmac(date, []byte(ctx.Region))
service := makeHmac(region, []byte(ctx.ServiceName))
credentials := makeHmac(service, []byte("aws4_request"))
signature := makeHmac(credentials, []byte(ctx.stringToSign))
ctx.signature = hex.EncodeToString(signature) ctx.signature = hex.EncodeToString(signature)
} }
@ -726,13 +741,13 @@ func (ctx *signingCtx) removePresign() {
ctx.Query.Del("X-Amz-SignedHeaders") ctx.Query.Del("X-Amz-SignedHeaders")
} }
func makeHmac(key []byte, data []byte) []byte { func hmacSHA256(key []byte, data []byte) []byte {
hash := hmac.New(sha256.New, key) hash := hmac.New(sha256.New, key)
hash.Write(data) hash.Write(data)
return hash.Sum(nil) return hash.Sum(nil)
} }
func makeSha256(data []byte) []byte { func hashSHA256(data []byte) []byte {
hash := sha256.New() hash := sha256.New()
hash.Write(data) hash.Write(data)
return hash.Sum(nil) return hash.Sum(nil)
@ -804,3 +819,28 @@ func stripExcessSpaces(vals []string) {
vals[i] = string(buf[:m]) vals[i] = string(buf[:m])
} }
} }
func buildSigningScope(region, service string, dt time.Time) string {
return strings.Join([]string{
formatShortTime(dt),
region,
service,
awsV4Request,
}, "/")
}
func deriveSigningKey(region, service, secretKey string, dt time.Time) []byte {
kDate := hmacSHA256([]byte("AWS4"+secretKey), []byte(formatShortTime(dt)))
kRegion := hmacSHA256(kDate, []byte(region))
kService := hmacSHA256(kRegion, []byte(service))
signingKey := hmacSHA256(kService, []byte(awsV4Request))
return signingKey
}
func formatShortTime(dt time.Time) string {
return dt.UTC().Format(shortTimeFormat)
}
func formatTime(dt time.Time) string {
return dt.UTC().Format(timeFormat)
}

View File

@ -2,6 +2,7 @@ package aws
import ( import (
"io" "io"
"strings"
"sync" "sync"
"github.com/aws/aws-sdk-go/internal/sdkio" "github.com/aws/aws-sdk-go/internal/sdkio"
@ -205,3 +206,36 @@ func (b *WriteAtBuffer) Bytes() []byte {
defer b.m.Unlock() defer b.m.Unlock()
return b.buf return b.buf
} }
// MultiCloser is a utility to close multiple io.Closers within a single
// statement.
type MultiCloser []io.Closer
// Close closes all of the io.Closers making up the MultiClosers. Any
// errors that occur while closing will be returned in the order they
// occur.
func (m MultiCloser) Close() error {
var errs errors
for _, c := range m {
err := c.Close()
if err != nil {
errs = append(errs, err)
}
}
if len(errs) != 0 {
return errs
}
return nil
}
type errors []error
func (es errors) Error() string {
var parts []string
for _, e := range es {
parts = append(parts, e.Error())
}
return strings.Join(parts, "\n")
}

View File

@ -5,4 +5,4 @@ package aws
const SDKName = "aws-sdk-go" const SDKName = "aws-sdk-go"
// SDKVersion is the version of this SDK // SDKVersion is the version of this SDK
const SDKVersion = "1.25.3" const SDKVersion = "1.30.12"

View File

@ -0,0 +1,40 @@
// +build !go1.7
package context
import "time"
// An emptyCtx is a copy of the Go 1.7 context.emptyCtx type. This is copied to
// provide a 1.6 and 1.5 safe version of context that is compatible with Go
// 1.7's Context.
//
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
// struct{}, since vars of this type must have distinct addresses.
type emptyCtx int
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
return
}
func (*emptyCtx) Done() <-chan struct{} {
return nil
}
func (*emptyCtx) Err() error {
return nil
}
func (*emptyCtx) Value(key interface{}) interface{} {
return nil
}
func (e *emptyCtx) String() string {
switch e {
case BackgroundCtx:
return "aws.BackgroundContext"
}
return "unknown empty Context"
}
// BackgroundCtx is the common base context.
var BackgroundCtx = new(emptyCtx)

View File

@ -162,7 +162,7 @@ loop:
if len(tokens) == 0 { if len(tokens) == 0 {
break loop break loop
} }
// if should skip is true, we skip the tokens until should skip is set to false.
step = SkipTokenState step = SkipTokenState
} }
@ -218,7 +218,7 @@ loop:
// S -> equal_expr' expr_stmt' // S -> equal_expr' expr_stmt'
switch k.Kind { switch k.Kind {
case ASTKindEqualExpr: case ASTKindEqualExpr:
// assiging a value to some key // assigning a value to some key
k.AppendChild(newExpression(tok)) k.AppendChild(newExpression(tok))
stack.Push(newExprStatement(k)) stack.Push(newExprStatement(k))
case ASTKindExpr: case ASTKindExpr:
@ -250,6 +250,13 @@ loop:
if !runeCompare(tok.Raw(), openBrace) { if !runeCompare(tok.Raw(), openBrace) {
return nil, NewParseError("expected '['") return nil, NewParseError("expected '['")
} }
// If OpenScopeState is not at the start, we must mark the previous ast as complete
//
// for example: if previous ast was a skip statement;
// we should mark it as complete before we create a new statement
if k.Kind != ASTKindStart {
stack.MarkComplete(k)
}
stmt := newStatement() stmt := newStatement()
stack.Push(stmt) stack.Push(stmt)

View File

@ -22,24 +22,24 @@ func newSkipper() skipper {
} }
func (s *skipper) ShouldSkip(tok Token) bool { func (s *skipper) ShouldSkip(tok Token) bool {
// should skip state will be modified only if previous token was new line (NL);
// and the current token is not WhiteSpace (WS).
if s.shouldSkip && if s.shouldSkip &&
s.prevTok.Type() == TokenNL && s.prevTok.Type() == TokenNL &&
tok.Type() != TokenWS { tok.Type() != TokenWS {
s.Continue() s.Continue()
return false return false
} }
s.prevTok = tok s.prevTok = tok
return s.shouldSkip return s.shouldSkip
} }
func (s *skipper) Skip() { func (s *skipper) Skip() {
s.shouldSkip = true s.shouldSkip = true
s.prevTok = emptyToken
} }
func (s *skipper) Continue() { func (s *skipper) Continue() {
s.shouldSkip = false s.shouldSkip = false
// empty token is assigned as we return to default state, when should skip is false
s.prevTok = emptyToken s.prevTok = emptyToken
} }

View File

@ -0,0 +1,11 @@
package strings
import (
"strings"
)
// HasPrefixFold tests whether the string s begins with prefix, interpreted as UTF-8 strings,
// under Unicode case-folding.
func HasPrefixFold(s, prefix string) bool {
return len(s) >= len(prefix) && strings.EqualFold(s[0:len(prefix)], prefix)
}

View File

@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,120 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package singleflight provides a duplicate function call suppression
// mechanism.
package singleflight
import "sync"
// call is an in-flight or completed singleflight.Do call
type call struct {
wg sync.WaitGroup
// These fields are written once before the WaitGroup is done
// and are only read after the WaitGroup is done.
val interface{}
err error
// forgotten indicates whether Forget was called with this call's key
// while the call was still in flight.
forgotten bool
// These fields are read and written with the singleflight
// mutex held before the WaitGroup is done, and are read but
// not written after the WaitGroup is done.
dups int
chans []chan<- Result
}
// Group represents a class of work and forms a namespace in
// which units of work can be executed with duplicate suppression.
type Group struct {
mu sync.Mutex // protects m
m map[string]*call // lazily initialized
}
// Result holds the results of Do, so they can be passed
// on a channel.
type Result struct {
Val interface{}
Err error
Shared bool
}
// Do executes and returns the results of the given function, making
// sure that only one execution is in-flight for a given key at a
// time. If a duplicate comes in, the duplicate caller waits for the
// original to complete and receives the same results.
// The return value shared indicates whether v was given to multiple callers.
func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
g.mu.Lock()
if g.m == nil {
g.m = make(map[string]*call)
}
if c, ok := g.m[key]; ok {
c.dups++
g.mu.Unlock()
c.wg.Wait()
return c.val, c.err, true
}
c := new(call)
c.wg.Add(1)
g.m[key] = c
g.mu.Unlock()
g.doCall(c, key, fn)
return c.val, c.err, c.dups > 0
}
// DoChan is like Do but returns a channel that will receive the
// results when they are ready.
func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result {
ch := make(chan Result, 1)
g.mu.Lock()
if g.m == nil {
g.m = make(map[string]*call)
}
if c, ok := g.m[key]; ok {
c.dups++
c.chans = append(c.chans, ch)
g.mu.Unlock()
return ch
}
c := &call{chans: []chan<- Result{ch}}
c.wg.Add(1)
g.m[key] = c
g.mu.Unlock()
go g.doCall(c, key, fn)
return ch
}
// doCall handles the single call for a key.
func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) {
c.val, c.err = fn()
c.wg.Done()
g.mu.Lock()
if !c.forgotten {
delete(g.m, key)
}
for _, ch := range c.chans {
ch <- Result{c.val, c.err, c.dups > 0}
}
g.mu.Unlock()
}
// Forget tells the singleflight to forget about a key. Future calls
// to Do for this key will call the function rather than waiting for
// an earlier call to complete.
func (g *Group) Forget(key string) {
g.mu.Lock()
if c, ok := g.m[key]; ok {
c.forgotten = true
}
delete(g.m, key)
g.mu.Unlock()
}

View File

@ -101,7 +101,7 @@ func (hs *decodedHeaders) UnmarshalJSON(b []byte) error {
} }
headers.Set(h.Name, value) headers.Set(h.Name, value)
} }
(*hs) = decodedHeaders(headers) *hs = decodedHeaders(headers)
return nil return nil
} }

View File

@ -21,10 +21,24 @@ type Decoder struct {
// NewDecoder initializes and returns a Decoder for decoding event // NewDecoder initializes and returns a Decoder for decoding event
// stream messages from the reader provided. // stream messages from the reader provided.
func NewDecoder(r io.Reader) *Decoder { func NewDecoder(r io.Reader, opts ...func(*Decoder)) *Decoder {
return &Decoder{ d := &Decoder{
r: r, r: r,
} }
for _, opt := range opts {
opt(d)
}
return d
}
// DecodeWithLogger adds a logger to be used by the decoder when decoding
// stream events.
func DecodeWithLogger(logger aws.Logger) func(*Decoder) {
return func(d *Decoder) {
d.logger = logger
}
} }
// Decode attempts to decode a single message from the event stream reader. // Decode attempts to decode a single message from the event stream reader.
@ -40,6 +54,15 @@ func (d *Decoder) Decode(payloadBuf []byte) (m Message, err error) {
}() }()
} }
m, err = Decode(reader, payloadBuf)
return m, err
}
// 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 reader.
func Decode(reader io.Reader, payloadBuf []byte) (m Message, err error) {
crc := crc32.New(crc32IEEETable) crc := crc32.New(crc32IEEETable)
hashReader := io.TeeReader(reader, crc) hashReader := io.TeeReader(reader, crc)
@ -72,12 +95,6 @@ func (d *Decoder) Decode(payloadBuf []byte) (m Message, err error) {
return m, nil 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) { func logMessageDecode(logger aws.Logger, msgBuf *bytes.Buffer, msg Message, decodeErr error) {
w := bytes.NewBuffer(nil) w := bytes.NewBuffer(nil)
defer func() { logger.Log(w.String()) }() defer func() { logger.Log(w.String()) }()

View File

@ -3,61 +3,107 @@ package eventstream
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"hash" "hash"
"hash/crc32" "hash/crc32"
"io" "io"
"github.com/aws/aws-sdk-go/aws"
) )
// Encoder provides EventStream message encoding. // Encoder provides EventStream message encoding.
type Encoder struct { type Encoder struct {
w io.Writer w io.Writer
logger aws.Logger
headersBuf *bytes.Buffer headersBuf *bytes.Buffer
} }
// NewEncoder initializes and returns an Encoder to encode Event Stream // NewEncoder initializes and returns an Encoder to encode Event Stream
// messages to an io.Writer. // messages to an io.Writer.
func NewEncoder(w io.Writer) *Encoder { func NewEncoder(w io.Writer, opts ...func(*Encoder)) *Encoder {
return &Encoder{ e := &Encoder{
w: w, w: w,
headersBuf: bytes.NewBuffer(nil), headersBuf: bytes.NewBuffer(nil),
} }
for _, opt := range opts {
opt(e)
}
return e
}
// EncodeWithLogger adds a logger to be used by the encode when decoding
// stream events.
func EncodeWithLogger(logger aws.Logger) func(*Encoder) {
return func(d *Encoder) {
d.logger = logger
}
} }
// Encode encodes a single EventStream message to the io.Writer the Encoder // Encode encodes a single EventStream message to the io.Writer the Encoder
// was created with. An error is returned if writing the message fails. // was created with. An error is returned if writing the message fails.
func (e *Encoder) Encode(msg Message) error { func (e *Encoder) Encode(msg Message) (err error) {
e.headersBuf.Reset() e.headersBuf.Reset()
err := encodeHeaders(e.headersBuf, msg.Headers) writer := e.w
if err != nil { if e.logger != nil {
encodeMsgBuf := bytes.NewBuffer(nil)
writer = io.MultiWriter(writer, encodeMsgBuf)
defer func() {
logMessageEncode(e.logger, encodeMsgBuf, msg, err)
}()
}
if err = EncodeHeaders(e.headersBuf, msg.Headers); err != nil {
return err return err
} }
crc := crc32.New(crc32IEEETable) crc := crc32.New(crc32IEEETable)
hashWriter := io.MultiWriter(e.w, crc) hashWriter := io.MultiWriter(writer, crc)
headersLen := uint32(e.headersBuf.Len()) headersLen := uint32(e.headersBuf.Len())
payloadLen := uint32(len(msg.Payload)) payloadLen := uint32(len(msg.Payload))
if err := encodePrelude(hashWriter, crc, headersLen, payloadLen); err != nil { if err = encodePrelude(hashWriter, crc, headersLen, payloadLen); err != nil {
return err return err
} }
if headersLen > 0 { if headersLen > 0 {
if _, err := io.Copy(hashWriter, e.headersBuf); err != nil { if _, err = io.Copy(hashWriter, e.headersBuf); err != nil {
return err return err
} }
} }
if payloadLen > 0 { if payloadLen > 0 {
if _, err := hashWriter.Write(msg.Payload); err != nil { if _, err = hashWriter.Write(msg.Payload); err != nil {
return err return err
} }
} }
msgCRC := crc.Sum32() msgCRC := crc.Sum32()
return binary.Write(e.w, binary.BigEndian, msgCRC) return binary.Write(writer, binary.BigEndian, msgCRC)
}
func logMessageEncode(logger aws.Logger, msgBuf *bytes.Buffer, msg Message, encodeErr error) {
w := bytes.NewBuffer(nil)
defer func() { logger.Log(w.String()) }()
fmt.Fprintf(w, "Message to encode:\n")
encoder := json.NewEncoder(w)
if err := encoder.Encode(msg); err != nil {
fmt.Fprintf(w, "Failed to get encoded message, %v\n", err)
}
if encodeErr != nil {
fmt.Fprintf(w, "Encode error: %v\n", encodeErr)
return
}
fmt.Fprintf(w, "Raw message:\n%s\n", hex.Dump(msgBuf.Bytes()))
} }
func encodePrelude(w io.Writer, crc hash.Hash32, headersLen, payloadLen uint32) error { func encodePrelude(w io.Writer, crc hash.Hash32, headersLen, payloadLen uint32) error {
@ -86,7 +132,9 @@ func encodePrelude(w io.Writer, crc hash.Hash32, headersLen, payloadLen uint32)
return nil return nil
} }
func encodeHeaders(w io.Writer, headers Headers) error { // EncodeHeaders writes the header values to the writer encoded in the event
// stream format. Returns an error if a header fails to encode.
func EncodeHeaders(w io.Writer, headers Headers) error {
for _, h := range headers { for _, h := range headers {
hn := headerName{ hn := headerName{
Len: uint8(len(h.Name)), Len: uint8(len(h.Name)),

View File

@ -1,6 +1,9 @@
package eventstreamapi package eventstreamapi
import "fmt" import (
"fmt"
"sync"
)
type messageError struct { type messageError struct {
code string code string
@ -22,3 +25,53 @@ func (e messageError) Error() string {
func (e messageError) OrigErr() error { func (e messageError) OrigErr() error {
return nil return nil
} }
// OnceError wraps the behavior of recording an error
// once and signal on a channel when this has occurred.
// Signaling is done by closing of the channel.
//
// Type is safe for concurrent usage.
type OnceError struct {
mu sync.RWMutex
err error
ch chan struct{}
}
// NewOnceError return a new OnceError
func NewOnceError() *OnceError {
return &OnceError{
ch: make(chan struct{}, 1),
}
}
// Err acquires a read-lock and returns an
// error if one has been set.
func (e *OnceError) Err() error {
e.mu.RLock()
err := e.err
e.mu.RUnlock()
return err
}
// SetError acquires a write-lock and will set
// the underlying error value if one has not been set.
func (e *OnceError) SetError(err error) {
if err == nil {
return
}
e.mu.Lock()
if e.err == nil {
e.err = err
close(e.ch)
}
e.mu.Unlock()
}
// ErrorSet returns a channel that will be used to signal
// that an error has been set. This channel will be closed
// when the error value has been set for OnceError.
func (e *OnceError) ErrorSet() <-chan struct{} {
return e.ch
}

View File

@ -2,9 +2,7 @@ package eventstreamapi
import ( import (
"fmt" "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"
"github.com/aws/aws-sdk-go/private/protocol/eventstream" "github.com/aws/aws-sdk-go/private/protocol/eventstream"
) )
@ -15,27 +13,8 @@ type Unmarshaler interface {
UnmarshalEvent(protocol.PayloadUnmarshaler, eventstream.Message) error 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. // EventReader provides reading from the EventStream of an reader.
type EventReader struct { type EventReader struct {
reader io.ReadCloser
decoder *eventstream.Decoder decoder *eventstream.Decoder
unmarshalerForEventType func(string) (Unmarshaler, error) unmarshalerForEventType func(string) (Unmarshaler, error)
@ -47,27 +26,18 @@ type EventReader struct {
// NewEventReader returns a EventReader built from the reader and unmarshaler // NewEventReader returns a EventReader built from the reader and unmarshaler
// provided. Use ReadStream method to start reading from the EventStream. // provided. Use ReadStream method to start reading from the EventStream.
func NewEventReader( func NewEventReader(
reader io.ReadCloser, decoder *eventstream.Decoder,
payloadUnmarshaler protocol.PayloadUnmarshaler, payloadUnmarshaler protocol.PayloadUnmarshaler,
unmarshalerForEventType func(string) (Unmarshaler, error), unmarshalerForEventType func(string) (Unmarshaler, error),
) *EventReader { ) *EventReader {
return &EventReader{ return &EventReader{
reader: reader, decoder: decoder,
decoder: eventstream.NewDecoder(reader),
payloadUnmarshaler: payloadUnmarshaler, payloadUnmarshaler: payloadUnmarshaler,
unmarshalerForEventType: unmarshalerForEventType, unmarshalerForEventType: unmarshalerForEventType,
payloadBuf: make([]byte, 10*1024), 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 // ReadEvent attempts to read a message from the EventStream and return the
// unmarshaled event value that the message is for. // unmarshaled event value that the message is for.
// //
@ -95,8 +65,7 @@ func (r *EventReader) ReadEvent() (event interface{}, err error) {
case EventMessageType: case EventMessageType:
return r.unmarshalEventMessage(msg) return r.unmarshalEventMessage(msg)
case ExceptionMessageType: case ExceptionMessageType:
err = r.unmarshalEventException(msg) return nil, r.unmarshalEventException(msg)
return nil, err
case ErrorMessageType: case ErrorMessageType:
return nil, r.unmarshalErrorMessage(msg) return nil, r.unmarshalErrorMessage(msg)
default: default:
@ -174,11 +143,6 @@ func (r *EventReader) unmarshalErrorMessage(msg eventstream.Message) (err error)
return msgErr 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 // 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. // is not set or the value is not a string an error will be returned.
func GetHeaderString(msg eventstream.Message, headerName string) (string, error) { func GetHeaderString(msg eventstream.Message, headerName string) (string, error) {

View File

@ -0,0 +1,23 @@
package eventstreamapi
// EventStream headers with specific meaning to async API functionality.
const (
ChunkSignatureHeader = `:chunk-signature` // chunk signature for message
DateHeader = `:date` // Date header for signature
// Message header and values
MessageTypeHeader = `:message-type` // Identifies type of message.
EventMessageType = `event`
ErrorMessageType = `error`
ExceptionMessageType = `exception`
// Message Events
EventTypeHeader = `:event-type` // Identifies message event type e.g. "Stats".
// Message Error
ErrorCodeHeader = `:error-code`
ErrorMessageHeader = `:error-message`
// Message Exception
ExceptionTypeHeader = `:exception-type`
)

View File

@ -0,0 +1,123 @@
package eventstreamapi
import (
"bytes"
"strings"
"time"
"github.com/aws/aws-sdk-go/private/protocol/eventstream"
)
var timeNow = time.Now
// StreamSigner defines an interface for the implementation of signing of event stream payloads
type StreamSigner interface {
GetSignature(headers, payload []byte, date time.Time) ([]byte, error)
}
// SignEncoder envelopes event stream messages
// into an event stream message payload with included
// signature headers using the provided signer and encoder.
type SignEncoder struct {
signer StreamSigner
encoder Encoder
bufEncoder *BufferEncoder
closeErr error
closed bool
}
// NewSignEncoder returns a new SignEncoder using the provided stream signer and
// event stream encoder.
func NewSignEncoder(signer StreamSigner, encoder Encoder) *SignEncoder {
// TODO: Need to pass down logging
return &SignEncoder{
signer: signer,
encoder: encoder,
bufEncoder: NewBufferEncoder(),
}
}
// Close encodes a final event stream signing envelope with an empty event stream
// payload. This final end-frame is used to mark the conclusion of the stream.
func (s *SignEncoder) Close() error {
if s.closed {
return s.closeErr
}
if err := s.encode([]byte{}); err != nil {
if strings.Contains(err.Error(), "on closed pipe") {
return nil
}
s.closeErr = err
s.closed = true
return s.closeErr
}
return nil
}
// Encode takes the provided message and add envelopes the message
// with the required signature.
func (s *SignEncoder) Encode(msg eventstream.Message) error {
payload, err := s.bufEncoder.Encode(msg)
if err != nil {
return err
}
return s.encode(payload)
}
func (s SignEncoder) encode(payload []byte) error {
date := timeNow()
var msg eventstream.Message
msg.Headers.Set(DateHeader, eventstream.TimestampValue(date))
msg.Payload = payload
var headers bytes.Buffer
if err := eventstream.EncodeHeaders(&headers, msg.Headers); err != nil {
return err
}
sig, err := s.signer.GetSignature(headers.Bytes(), msg.Payload, date)
if err != nil {
return err
}
msg.Headers.Set(ChunkSignatureHeader, eventstream.BytesValue(sig))
return s.encoder.Encode(msg)
}
// BufferEncoder is a utility that provides a buffered
// event stream encoder
type BufferEncoder struct {
encoder Encoder
buffer *bytes.Buffer
}
// NewBufferEncoder returns a new BufferEncoder initialized
// with a 1024 byte buffer.
func NewBufferEncoder() *BufferEncoder {
buf := bytes.NewBuffer(make([]byte, 1024))
return &BufferEncoder{
encoder: eventstream.NewEncoder(buf),
buffer: buf,
}
}
// Encode returns the encoded message as a byte slice.
// The returned byte slice will be modified on the next encode call
// and should not be held onto.
func (e *BufferEncoder) Encode(msg eventstream.Message) ([]byte, error) {
e.buffer.Reset()
if err := e.encoder.Encode(msg); err != nil {
return nil, err
}
return e.buffer.Bytes(), nil
}

View File

@ -0,0 +1,129 @@
package eventstreamapi
import (
"fmt"
"io"
"sync"
"github.com/aws/aws-sdk-go/aws"
)
// StreamWriter provides concurrent safe writing to an event stream.
type StreamWriter struct {
eventWriter *EventWriter
stream chan eventWriteAsyncReport
done chan struct{}
closeOnce sync.Once
err *OnceError
streamCloser io.Closer
}
// NewStreamWriter returns a StreamWriter for the event writer, and stream
// closer provided.
func NewStreamWriter(eventWriter *EventWriter, streamCloser io.Closer) *StreamWriter {
w := &StreamWriter{
eventWriter: eventWriter,
streamCloser: streamCloser,
stream: make(chan eventWriteAsyncReport),
done: make(chan struct{}),
err: NewOnceError(),
}
go w.writeStream()
return w
}
// Close terminates the writers ability to write new events to the stream. Any
// future call to Send will fail with an error.
func (w *StreamWriter) Close() error {
w.closeOnce.Do(w.safeClose)
return w.Err()
}
func (w *StreamWriter) safeClose() {
close(w.done)
}
// ErrorSet returns a channel which will be closed
// if an error occurs.
func (w *StreamWriter) ErrorSet() <-chan struct{} {
return w.err.ErrorSet()
}
// Err returns any error that occurred while attempting to write an event to the
// stream.
func (w *StreamWriter) Err() error {
return w.err.Err()
}
// Send writes a single event to the stream returning an error if the write
// failed.
//
// Send may be called concurrently. Events will be written to the stream
// safely.
func (w *StreamWriter) Send(ctx aws.Context, event Marshaler) error {
if err := w.Err(); err != nil {
return err
}
resultCh := make(chan error)
wrapped := eventWriteAsyncReport{
Event: event,
Result: resultCh,
}
select {
case w.stream <- wrapped:
case <-ctx.Done():
return ctx.Err()
case <-w.done:
return fmt.Errorf("stream closed, unable to send event")
}
select {
case err := <-resultCh:
return err
case <-ctx.Done():
return ctx.Err()
case <-w.done:
return fmt.Errorf("stream closed, unable to send event")
}
}
func (w *StreamWriter) writeStream() {
defer w.Close()
for {
select {
case wrapper := <-w.stream:
err := w.eventWriter.WriteEvent(wrapper.Event)
wrapper.ReportResult(w.done, err)
if err != nil {
w.err.SetError(err)
return
}
case <-w.done:
if err := w.streamCloser.Close(); err != nil {
w.err.SetError(err)
}
return
}
}
}
type eventWriteAsyncReport struct {
Event Marshaler
Result chan<- error
}
func (e eventWriteAsyncReport) ReportResult(cancel <-chan struct{}, err error) bool {
select {
case e.Result <- err:
return true
case <-cancel:
return false
}
}

View File

@ -0,0 +1,109 @@
package eventstreamapi
import (
"github.com/aws/aws-sdk-go/private/protocol"
"github.com/aws/aws-sdk-go/private/protocol/eventstream"
)
// Marshaler provides a marshaling interface for event types to event stream
// messages.
type Marshaler interface {
MarshalEvent(protocol.PayloadMarshaler) (eventstream.Message, error)
}
// Encoder is an stream encoder that will encode an event stream message for
// the transport.
type Encoder interface {
Encode(eventstream.Message) error
}
// EventWriter provides a wrapper around the underlying event stream encoder
// for an io.WriteCloser.
type EventWriter struct {
encoder Encoder
payloadMarshaler protocol.PayloadMarshaler
eventTypeFor func(Marshaler) (string, error)
}
// NewEventWriter returns a new event stream writer, that will write to the
// writer provided. Use the WriteEvent method to write an event to the stream.
func NewEventWriter(encoder Encoder, pm protocol.PayloadMarshaler, eventTypeFor func(Marshaler) (string, error),
) *EventWriter {
return &EventWriter{
encoder: encoder,
payloadMarshaler: pm,
eventTypeFor: eventTypeFor,
}
}
// WriteEvent writes an event to the stream. Returns an error if the event
// fails to marshal into a message, or writing to the underlying writer fails.
func (w *EventWriter) WriteEvent(event Marshaler) error {
msg, err := w.marshal(event)
if err != nil {
return err
}
return w.encoder.Encode(msg)
}
func (w *EventWriter) marshal(event Marshaler) (eventstream.Message, error) {
eventType, err := w.eventTypeFor(event)
if err != nil {
return eventstream.Message{}, err
}
msg, err := event.MarshalEvent(w.payloadMarshaler)
if err != nil {
return eventstream.Message{}, err
}
msg.Headers.Set(EventTypeHeader, eventstream.StringValue(eventType))
return msg, nil
}
//type EventEncoder struct {
// encoder Encoder
// ppayloadMarshaler protocol.PayloadMarshaler
// eventTypeFor func(Marshaler) (string, error)
//}
//
//func (e EventEncoder) Encode(event Marshaler) error {
// msg, err := e.marshal(event)
// if err != nil {
// return err
// }
//
// return w.encoder.Encode(msg)
//}
//
//func (e EventEncoder) marshal(event Marshaler) (eventstream.Message, error) {
// eventType, err := w.eventTypeFor(event)
// if err != nil {
// return eventstream.Message{}, err
// }
//
// msg, err := event.MarshalEvent(w.payloadMarshaler)
// if err != nil {
// return eventstream.Message{}, err
// }
//
// msg.Headers.Set(EventTypeHeader, eventstream.StringValue(eventType))
// return msg, nil
//}
//
//func (w *EventWriter) marshal(event Marshaler) (eventstream.Message, error) {
// eventType, err := w.eventTypeFor(event)
// if err != nil {
// return eventstream.Message{}, err
// }
//
// msg, err := event.MarshalEvent(w.payloadMarshaler)
// if err != nil {
// return eventstream.Message{}, err
// }
//
// msg.Headers.Set(EventTypeHeader, eventstream.StringValue(eventType))
// return msg, nil
//}
//

View File

@ -461,6 +461,11 @@ func (v *TimestampValue) decode(r io.Reader) error {
return nil return nil
} }
// MarshalJSON implements the json.Marshaler interface
func (v TimestampValue) MarshalJSON() ([]byte, error) {
return []byte(v.String()), nil
}
func timeFromEpochMilli(t int64) time.Time { func timeFromEpochMilli(t int64) time.Time {
secs := t / 1e3 secs := t / 1e3
msec := t % 1e3 msec := t % 1e3

View File

@ -27,7 +27,7 @@ func (m *Message) rawMessage() (rawMessage, error) {
if len(m.Headers) > 0 { if len(m.Headers) > 0 {
var headers bytes.Buffer var headers bytes.Buffer
if err := encodeHeaders(&headers, m.Headers); err != nil { if err := EncodeHeaders(&headers, m.Headers); err != nil {
return rawMessage{}, err return rawMessage{}, err
} }
raw.Headers = headers.Bytes() raw.Headers = headers.Bytes()

View File

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"io" "io"
"reflect" "reflect"
"strings"
"time" "time"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
@ -45,10 +46,31 @@ func UnmarshalJSON(v interface{}, stream io.Reader) error {
return err return err
} }
return unmarshalAny(reflect.ValueOf(v), out, "") return unmarshaler{}.unmarshalAny(reflect.ValueOf(v), out, "")
} }
func unmarshalAny(value reflect.Value, data interface{}, tag reflect.StructTag) error { // UnmarshalJSONCaseInsensitive reads a stream and unmarshals the result into the
// object v. Ignores casing for structure members.
func UnmarshalJSONCaseInsensitive(v interface{}, stream io.Reader) error {
var out interface{}
err := json.NewDecoder(stream).Decode(&out)
if err == io.EOF {
return nil
} else if err != nil {
return err
}
return unmarshaler{
caseInsensitive: true,
}.unmarshalAny(reflect.ValueOf(v), out, "")
}
type unmarshaler struct {
caseInsensitive bool
}
func (u unmarshaler) unmarshalAny(value reflect.Value, data interface{}, tag reflect.StructTag) error {
vtype := value.Type() vtype := value.Type()
if vtype.Kind() == reflect.Ptr { if vtype.Kind() == reflect.Ptr {
vtype = vtype.Elem() // check kind of actual element type vtype = vtype.Elem() // check kind of actual element type
@ -80,17 +102,17 @@ func unmarshalAny(value reflect.Value, data interface{}, tag reflect.StructTag)
if field, ok := vtype.FieldByName("_"); ok { if field, ok := vtype.FieldByName("_"); ok {
tag = field.Tag tag = field.Tag
} }
return unmarshalStruct(value, data, tag) return u.unmarshalStruct(value, data, tag)
case "list": case "list":
return unmarshalList(value, data, tag) return u.unmarshalList(value, data, tag)
case "map": case "map":
return unmarshalMap(value, data, tag) return u.unmarshalMap(value, data, tag)
default: default:
return unmarshalScalar(value, data, tag) return u.unmarshalScalar(value, data, tag)
} }
} }
func unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTag) error { func (u unmarshaler) unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTag) error {
if data == nil { if data == nil {
return nil return nil
} }
@ -114,7 +136,7 @@ func unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTa
// unwrap any payloads // unwrap any payloads
if payload := tag.Get("payload"); payload != "" { if payload := tag.Get("payload"); payload != "" {
field, _ := t.FieldByName(payload) field, _ := t.FieldByName(payload)
return unmarshalAny(value.FieldByName(payload), data, field.Tag) return u.unmarshalAny(value.FieldByName(payload), data, field.Tag)
} }
for i := 0; i < t.NumField(); i++ { for i := 0; i < t.NumField(); i++ {
@ -128,9 +150,19 @@ func unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTa
if locName := field.Tag.Get("locationName"); locName != "" { if locName := field.Tag.Get("locationName"); locName != "" {
name = locName name = locName
} }
if u.caseInsensitive {
if _, ok := mapData[name]; !ok {
// Fallback to uncased name search if the exact name didn't match.
for kn, v := range mapData {
if strings.EqualFold(kn, name) {
mapData[name] = v
}
}
}
}
member := value.FieldByIndex(field.Index) member := value.FieldByIndex(field.Index)
err := unmarshalAny(member, mapData[name], field.Tag) err := u.unmarshalAny(member, mapData[name], field.Tag)
if err != nil { if err != nil {
return err return err
} }
@ -138,7 +170,7 @@ func unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTa
return nil return nil
} }
func unmarshalList(value reflect.Value, data interface{}, tag reflect.StructTag) error { func (u unmarshaler) unmarshalList(value reflect.Value, data interface{}, tag reflect.StructTag) error {
if data == nil { if data == nil {
return nil return nil
} }
@ -153,7 +185,7 @@ func unmarshalList(value reflect.Value, data interface{}, tag reflect.StructTag)
} }
for i, c := range listData { for i, c := range listData {
err := unmarshalAny(value.Index(i), c, "") err := u.unmarshalAny(value.Index(i), c, "")
if err != nil { if err != nil {
return err return err
} }
@ -162,7 +194,7 @@ func unmarshalList(value reflect.Value, data interface{}, tag reflect.StructTag)
return nil return nil
} }
func unmarshalMap(value reflect.Value, data interface{}, tag reflect.StructTag) error { func (u unmarshaler) unmarshalMap(value reflect.Value, data interface{}, tag reflect.StructTag) error {
if data == nil { if data == nil {
return nil return nil
} }
@ -179,14 +211,14 @@ func unmarshalMap(value reflect.Value, data interface{}, tag reflect.StructTag)
kvalue := reflect.ValueOf(k) kvalue := reflect.ValueOf(k)
vvalue := reflect.New(value.Type().Elem()).Elem() vvalue := reflect.New(value.Type().Elem()).Elem()
unmarshalAny(vvalue, v, "") u.unmarshalAny(vvalue, v, "")
value.SetMapIndex(kvalue, vvalue) value.SetMapIndex(kvalue, vvalue)
} }
return nil return nil
} }
func unmarshalScalar(value reflect.Value, data interface{}, tag reflect.StructTag) error { func (u unmarshaler) unmarshalScalar(value reflect.Value, data interface{}, tag reflect.StructTag) error {
switch d := data.(type) { switch d := data.(type) {
case nil: case nil:

View File

@ -2,12 +2,10 @@
// requests and responses. // requests and responses.
package jsonrpc package jsonrpc
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/json.json build_test.go //go:generate go run -tags codegen ../../../private/model/cli/gen-protocol-tests ../../../models/protocol_tests/input/json.json build_test.go
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/json.json unmarshal_test.go //go:generate go run -tags codegen ../../../private/model/cli/gen-protocol-tests ../../../models/protocol_tests/output/json.json unmarshal_test.go
import ( import (
"strings"
"github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/private/protocol/json/jsonutil" "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil"
@ -16,17 +14,26 @@ import (
var emptyJSON = []byte("{}") var emptyJSON = []byte("{}")
// BuildHandler is a named request handler for building jsonrpc protocol requests // BuildHandler is a named request handler for building jsonrpc protocol
var BuildHandler = request.NamedHandler{Name: "awssdk.jsonrpc.Build", Fn: Build} // requests
var BuildHandler = request.NamedHandler{
Name: "awssdk.jsonrpc.Build",
Fn: Build,
}
// UnmarshalHandler is a named request handler for unmarshaling jsonrpc protocol requests // UnmarshalHandler is a named request handler for unmarshaling jsonrpc
var UnmarshalHandler = request.NamedHandler{Name: "awssdk.jsonrpc.Unmarshal", Fn: Unmarshal} // protocol requests
var UnmarshalHandler = request.NamedHandler{
Name: "awssdk.jsonrpc.Unmarshal",
Fn: Unmarshal,
}
// UnmarshalMetaHandler is a named request handler for unmarshaling jsonrpc protocol request metadata // UnmarshalMetaHandler is a named request handler for unmarshaling jsonrpc
var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.jsonrpc.UnmarshalMeta", Fn: UnmarshalMeta} // protocol request metadata
var UnmarshalMetaHandler = request.NamedHandler{
// UnmarshalErrorHandler is a named request handler for unmarshaling jsonrpc protocol request errors Name: "awssdk.jsonrpc.UnmarshalMeta",
var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.jsonrpc.UnmarshalError", Fn: UnmarshalError} Fn: UnmarshalMeta,
}
// Build builds a JSON payload for a JSON RPC request. // Build builds a JSON payload for a JSON RPC request.
func Build(req *request.Request) { func Build(req *request.Request) {
@ -79,32 +86,3 @@ func Unmarshal(req *request.Request) {
func UnmarshalMeta(req *request.Request) { func UnmarshalMeta(req *request.Request) {
rest.UnmarshalMeta(req) rest.UnmarshalMeta(req)
} }
// UnmarshalError unmarshals an error response for a JSON RPC service.
func UnmarshalError(req *request.Request) {
defer req.HTTPResponse.Body.Close()
var jsonErr jsonErrorResponse
err := jsonutil.UnmarshalJSONError(&jsonErr, req.HTTPResponse.Body)
if err != nil {
req.Error = awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization,
"failed to unmarshal error message", err),
req.HTTPResponse.StatusCode,
req.RequestID,
)
return
}
codes := strings.SplitN(jsonErr.Code, "#", 2)
req.Error = awserr.NewRequestFailure(
awserr.New(codes[len(codes)-1], jsonErr.Message, nil),
req.HTTPResponse.StatusCode,
req.RequestID,
)
}
type jsonErrorResponse struct {
Code string `json:"__type"`
Message string `json:"message"`
}

View File

@ -0,0 +1,107 @@
package jsonrpc
import (
"bytes"
"io"
"io/ioutil"
"net/http"
"strings"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/private/protocol"
"github.com/aws/aws-sdk-go/private/protocol/json/jsonutil"
)
// UnmarshalTypedError provides unmarshaling errors API response errors
// for both typed and untyped errors.
type UnmarshalTypedError struct {
exceptions map[string]func(protocol.ResponseMetadata) error
}
// NewUnmarshalTypedError returns an UnmarshalTypedError initialized for the
// set of exception names to the error unmarshalers
func NewUnmarshalTypedError(exceptions map[string]func(protocol.ResponseMetadata) error) *UnmarshalTypedError {
return &UnmarshalTypedError{
exceptions: exceptions,
}
}
// UnmarshalError attempts to unmarshal the HTTP response error as a known
// error type. If unable to unmarshal the error type, the generic SDK error
// type will be used.
func (u *UnmarshalTypedError) UnmarshalError(
resp *http.Response,
respMeta protocol.ResponseMetadata,
) (error, error) {
var buf bytes.Buffer
var jsonErr jsonErrorResponse
teeReader := io.TeeReader(resp.Body, &buf)
err := jsonutil.UnmarshalJSONError(&jsonErr, teeReader)
if err != nil {
return nil, err
}
body := ioutil.NopCloser(&buf)
// Code may be separated by hash(#), with the last element being the code
// used by the SDK.
codeParts := strings.SplitN(jsonErr.Code, "#", 2)
code := codeParts[len(codeParts)-1]
msg := jsonErr.Message
if fn, ok := u.exceptions[code]; ok {
// If exception code is know, use associated constructor to get a value
// for the exception that the JSON body can be unmarshaled into.
v := fn(respMeta)
err := jsonutil.UnmarshalJSONCaseInsensitive(v, body)
if err != nil {
return nil, err
}
return v, nil
}
// fallback to unmodeled generic exceptions
return awserr.NewRequestFailure(
awserr.New(code, msg, nil),
respMeta.StatusCode,
respMeta.RequestID,
), nil
}
// UnmarshalErrorHandler is a named request handler for unmarshaling jsonrpc
// protocol request errors
var UnmarshalErrorHandler = request.NamedHandler{
Name: "awssdk.jsonrpc.UnmarshalError",
Fn: UnmarshalError,
}
// UnmarshalError unmarshals an error response for a JSON RPC service.
func UnmarshalError(req *request.Request) {
defer req.HTTPResponse.Body.Close()
var jsonErr jsonErrorResponse
err := jsonutil.UnmarshalJSONError(&jsonErr, req.HTTPResponse.Body)
if err != nil {
req.Error = awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization,
"failed to unmarshal error message", err),
req.HTTPResponse.StatusCode,
req.RequestID,
)
return
}
codes := strings.SplitN(jsonErr.Code, "#", 2)
req.Error = awserr.NewRequestFailure(
awserr.New(codes[len(codes)-1], jsonErr.Message, nil),
req.HTTPResponse.StatusCode,
req.RequestID,
)
}
type jsonErrorResponse struct {
Code string `json:"__type"`
Message string `json:"message"`
}

View File

@ -64,7 +64,7 @@ func (h HandlerPayloadMarshal) MarshalPayload(w io.Writer, v interface{}) error
metadata.ClientInfo{}, metadata.ClientInfo{},
request.Handlers{}, request.Handlers{},
nil, nil,
&request.Operation{HTTPMethod: "GET"}, &request.Operation{HTTPMethod: "PUT"},
v, v,
nil, nil,
) )

View File

@ -0,0 +1,49 @@
package protocol
import (
"fmt"
"strings"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
)
// RequireHTTPMinProtocol request handler is used to enforce that
// the target endpoint supports the given major and minor HTTP protocol version.
type RequireHTTPMinProtocol struct {
Major, Minor int
}
// Handler will mark the request.Request with an error if the
// target endpoint did not connect with the required HTTP protocol
// major and minor version.
func (p RequireHTTPMinProtocol) Handler(r *request.Request) {
if r.Error != nil || r.HTTPResponse == nil {
return
}
if !strings.HasPrefix(r.HTTPResponse.Proto, "HTTP") {
r.Error = newMinHTTPProtoError(p.Major, p.Minor, r)
}
if r.HTTPResponse.ProtoMajor < p.Major || r.HTTPResponse.ProtoMinor < p.Minor {
r.Error = newMinHTTPProtoError(p.Major, p.Minor, r)
}
}
// ErrCodeMinimumHTTPProtocolError error code is returned when the target endpoint
// did not match the required HTTP major and minor protocol version.
const ErrCodeMinimumHTTPProtocolError = "MinimumHTTPProtocolError"
func newMinHTTPProtoError(major, minor int, r *request.Request) error {
return awserr.NewRequestFailure(
awserr.New("MinimumHTTPProtocolError",
fmt.Sprintf(
"operation requires minimum HTTP protocol of HTTP/%d.%d, but was %s",
major, minor, r.HTTPResponse.Proto,
),
nil,
),
r.HTTPResponse.StatusCode, r.RequestID,
)
}

View File

@ -1,7 +1,7 @@
// Package query provides serialization of AWS query requests, and responses. // Package query provides serialization of AWS query requests, and responses.
package query package query
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/query.json build_test.go //go:generate go run -tags codegen ../../../private/model/cli/gen-protocol-tests ../../../models/protocol_tests/input/query.json build_test.go
import ( import (
"net/url" "net/url"

View File

@ -1,6 +1,6 @@
package query package query
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/query.json unmarshal_test.go //go:generate go run -tags codegen ../../../private/model/cli/gen-protocol-tests ../../../models/protocol_tests/output/query.json unmarshal_test.go
import ( import (
"encoding/xml" "encoding/xml"

View File

@ -15,6 +15,7 @@ import (
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/request"
awsStrings "github.com/aws/aws-sdk-go/internal/strings"
"github.com/aws/aws-sdk-go/private/protocol" "github.com/aws/aws-sdk-go/private/protocol"
) )
@ -28,7 +29,9 @@ var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.rest.UnmarshalMeta
func Unmarshal(r *request.Request) { func Unmarshal(r *request.Request) {
if r.DataFilled() { if r.DataFilled() {
v := reflect.Indirect(reflect.ValueOf(r.Data)) v := reflect.Indirect(reflect.ValueOf(r.Data))
unmarshalBody(r, v) if err := unmarshalBody(r, v); err != nil {
r.Error = err
}
} }
} }
@ -40,12 +43,21 @@ func UnmarshalMeta(r *request.Request) {
r.RequestID = r.HTTPResponse.Header.Get("X-Amz-Request-Id") r.RequestID = r.HTTPResponse.Header.Get("X-Amz-Request-Id")
} }
if r.DataFilled() { if r.DataFilled() {
v := reflect.Indirect(reflect.ValueOf(r.Data)) if err := UnmarshalResponse(r.HTTPResponse, r.Data, aws.BoolValue(r.Config.LowerCaseHeaderMaps)); err != nil {
unmarshalLocationElements(r, v) r.Error = err
}
} }
} }
func unmarshalBody(r *request.Request, v reflect.Value) { // UnmarshalResponse attempts to unmarshal the REST response headers to
// the data type passed in. The type must be a pointer. An error is returned
// with any error unmarshaling the response into the target datatype.
func UnmarshalResponse(resp *http.Response, data interface{}, lowerCaseHeaderMaps bool) error {
v := reflect.Indirect(reflect.ValueOf(data))
return unmarshalLocationElements(resp, v, lowerCaseHeaderMaps)
}
func unmarshalBody(r *request.Request, v reflect.Value) error {
if field, ok := v.Type().FieldByName("_"); ok { if field, ok := v.Type().FieldByName("_"); ok {
if payloadName := field.Tag.Get("payload"); payloadName != "" { if payloadName := field.Tag.Get("payload"); payloadName != "" {
pfield, _ := v.Type().FieldByName(payloadName) pfield, _ := v.Type().FieldByName(payloadName)
@ -57,35 +69,38 @@ func unmarshalBody(r *request.Request, v reflect.Value) {
defer r.HTTPResponse.Body.Close() defer r.HTTPResponse.Body.Close()
b, err := ioutil.ReadAll(r.HTTPResponse.Body) b, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil { if err != nil {
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err) return awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
} else {
payload.Set(reflect.ValueOf(b))
} }
payload.Set(reflect.ValueOf(b))
case *string: case *string:
defer r.HTTPResponse.Body.Close() defer r.HTTPResponse.Body.Close()
b, err := ioutil.ReadAll(r.HTTPResponse.Body) b, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil { if err != nil {
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err) return awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
} else {
str := string(b)
payload.Set(reflect.ValueOf(&str))
} }
str := string(b)
payload.Set(reflect.ValueOf(&str))
default: default:
switch payload.Type().String() { switch payload.Type().String() {
case "io.ReadCloser": case "io.ReadCloser":
payload.Set(reflect.ValueOf(r.HTTPResponse.Body)) payload.Set(reflect.ValueOf(r.HTTPResponse.Body))
case "io.ReadSeeker": case "io.ReadSeeker":
b, err := ioutil.ReadAll(r.HTTPResponse.Body) b, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil { if err != nil {
r.Error = awserr.New(request.ErrCodeSerialization, return awserr.New(request.ErrCodeSerialization,
"failed to read response body", err) "failed to read response body", err)
return
} }
payload.Set(reflect.ValueOf(ioutil.NopCloser(bytes.NewReader(b)))) payload.Set(reflect.ValueOf(ioutil.NopCloser(bytes.NewReader(b))))
default: default:
io.Copy(ioutil.Discard, r.HTTPResponse.Body) io.Copy(ioutil.Discard, r.HTTPResponse.Body)
defer r.HTTPResponse.Body.Close() r.HTTPResponse.Body.Close()
r.Error = awserr.New(request.ErrCodeSerialization, return awserr.New(request.ErrCodeSerialization,
"failed to decode REST response", "failed to decode REST response",
fmt.Errorf("unknown payload type %s", payload.Type())) fmt.Errorf("unknown payload type %s", payload.Type()))
} }
@ -94,9 +109,11 @@ func unmarshalBody(r *request.Request, v reflect.Value) {
} }
} }
} }
return nil
} }
func unmarshalLocationElements(r *request.Request, v reflect.Value) { func unmarshalLocationElements(resp *http.Response, v reflect.Value, lowerCaseHeaderMaps bool) error {
for i := 0; i < v.NumField(); i++ { for i := 0; i < v.NumField(); i++ {
m, field := v.Field(i), v.Type().Field(i) m, field := v.Field(i), v.Type().Field(i)
if n := field.Name; n[0:1] == strings.ToLower(n[0:1]) { if n := field.Name; n[0:1] == strings.ToLower(n[0:1]) {
@ -111,26 +128,25 @@ func unmarshalLocationElements(r *request.Request, v reflect.Value) {
switch field.Tag.Get("location") { switch field.Tag.Get("location") {
case "statusCode": case "statusCode":
unmarshalStatusCode(m, r.HTTPResponse.StatusCode) unmarshalStatusCode(m, resp.StatusCode)
case "header": case "header":
err := unmarshalHeader(m, r.HTTPResponse.Header.Get(name), field.Tag) err := unmarshalHeader(m, resp.Header.Get(name), field.Tag)
if err != nil { if err != nil {
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err) return awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
break
} }
case "headers": case "headers":
prefix := field.Tag.Get("locationName") prefix := field.Tag.Get("locationName")
err := unmarshalHeaderMap(m, r.HTTPResponse.Header, prefix) err := unmarshalHeaderMap(m, resp.Header, prefix, lowerCaseHeaderMaps)
if err != nil { if err != nil {
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err) awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
break
} }
} }
} }
if r.Error != nil {
return
}
} }
return nil
} }
func unmarshalStatusCode(v reflect.Value, statusCode int) { func unmarshalStatusCode(v reflect.Value, statusCode int) {
@ -145,7 +161,7 @@ func unmarshalStatusCode(v reflect.Value, statusCode int) {
} }
} }
func unmarshalHeaderMap(r reflect.Value, headers http.Header, prefix string) error { func unmarshalHeaderMap(r reflect.Value, headers http.Header, prefix string, normalize bool) error {
if len(headers) == 0 { if len(headers) == 0 {
return nil return nil
} }
@ -153,8 +169,12 @@ func unmarshalHeaderMap(r reflect.Value, headers http.Header, prefix string) err
case map[string]*string: // we only support string map value types case map[string]*string: // we only support string map value types
out := map[string]*string{} out := map[string]*string{}
for k, v := range headers { for k, v := range headers {
k = http.CanonicalHeaderKey(k) if awsStrings.HasPrefixFold(k, prefix) {
if strings.HasPrefix(strings.ToLower(k), strings.ToLower(prefix)) { if normalize == true {
k = strings.ToLower(k)
} else {
k = http.CanonicalHeaderKey(k)
}
out[k[len(prefix):]] = &v[0] out[k[len(prefix):]] = &v[0]
} }
} }

View File

@ -2,8 +2,8 @@
// requests and responses. // requests and responses.
package restxml package restxml
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/rest-xml.json build_test.go //go:generate go run -tags codegen ../../../private/model/cli/gen-protocol-tests ../../../models/protocol_tests/input/rest-xml.json build_test.go
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/rest-xml.json unmarshal_test.go //go:generate go run -tags codegen ../../../private/model/cli/gen-protocol-tests ../../../models/protocol_tests/output/rest-xml.json unmarshal_test.go
import ( import (
"bytes" "bytes"

View File

@ -19,3 +19,9 @@ func UnmarshalDiscardBody(r *request.Request) {
io.Copy(ioutil.Discard, r.HTTPResponse.Body) io.Copy(ioutil.Discard, r.HTTPResponse.Body)
r.HTTPResponse.Body.Close() r.HTTPResponse.Body.Close()
} }
// ResponseMetadata provides the SDK response metadata attributes.
type ResponseMetadata struct {
StatusCode int
RequestID string
}

View File

@ -0,0 +1,65 @@
package protocol
import (
"net/http"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
)
// UnmarshalErrorHandler provides unmarshaling errors API response errors for
// both typed and untyped errors.
type UnmarshalErrorHandler struct {
unmarshaler ErrorUnmarshaler
}
// ErrorUnmarshaler is an abstract interface for concrete implementations to
// unmarshal protocol specific response errors.
type ErrorUnmarshaler interface {
UnmarshalError(*http.Response, ResponseMetadata) (error, error)
}
// NewUnmarshalErrorHandler returns an UnmarshalErrorHandler
// initialized for the set of exception names to the error unmarshalers
func NewUnmarshalErrorHandler(unmarshaler ErrorUnmarshaler) *UnmarshalErrorHandler {
return &UnmarshalErrorHandler{
unmarshaler: unmarshaler,
}
}
// UnmarshalErrorHandlerName is the name of the named handler.
const UnmarshalErrorHandlerName = "awssdk.protocol.UnmarshalError"
// NamedHandler returns a NamedHandler for the unmarshaler using the set of
// errors the unmarshaler was initialized for.
func (u *UnmarshalErrorHandler) NamedHandler() request.NamedHandler {
return request.NamedHandler{
Name: UnmarshalErrorHandlerName,
Fn: u.UnmarshalError,
}
}
// UnmarshalError will attempt to unmarshal the API response's error message
// into either a generic SDK error type, or a typed error corresponding to the
// errors exception name.
func (u *UnmarshalErrorHandler) UnmarshalError(r *request.Request) {
defer r.HTTPResponse.Body.Close()
respMeta := ResponseMetadata{
StatusCode: r.HTTPResponse.StatusCode,
RequestID: r.RequestID,
}
v, err := u.unmarshaler.UnmarshalError(r.HTTPResponse, respMeta)
if err != nil {
r.Error = awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization,
"failed to unmarshal response error", err),
respMeta.StatusCode,
respMeta.RequestID,
)
return
}
r.Error = v
}

View File

@ -8,6 +8,7 @@ import (
"reflect" "reflect"
"sort" "sort"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/aws/aws-sdk-go/private/protocol" "github.com/aws/aws-sdk-go/private/protocol"
@ -60,6 +61,14 @@ func (b *xmlBuilder) buildValue(value reflect.Value, current *XMLNode, tag refle
return nil return nil
} }
xml := tag.Get("xml")
if len(xml) != 0 {
name := strings.SplitAfterN(xml, ",", 2)[0]
if name == "-" {
return nil
}
}
t := tag.Get("type") t := tag.Get("type")
if t == "" { if t == "" {
switch value.Kind() { switch value.Kind() {

View File

@ -64,6 +64,14 @@ func UnmarshalXML(v interface{}, d *xml.Decoder, wrapper string) error {
// parse deserializes any value from the XMLNode. The type tag is used to infer the type, or reflect // parse deserializes any value from the XMLNode. The type tag is used to infer the type, or reflect
// will be used to determine the type from r. // will be used to determine the type from r.
func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
xml := tag.Get("xml")
if len(xml) != 0 {
name := strings.SplitAfterN(xml, ",", 2)[0]
if name == "-" {
return nil
}
}
rtype := r.Type() rtype := r.Type()
if rtype.Kind() == reflect.Ptr { if rtype.Kind() == reflect.Ptr {
rtype = rtype.Elem() // check kind of actual element type rtype = rtype.Elem() // check kind of actual element type

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,10 @@
package dynamodb package dynamodb
import (
"github.com/aws/aws-sdk-go/private/protocol"
)
const ( const (
// ErrCodeBackupInUseException for service response error code // ErrCodeBackupInUseException for service response error code
@ -184,8 +188,6 @@ const (
// index (LSI) becomes too large, or a similar validation error occurs because // index (LSI) becomes too large, or a similar validation error occurs because
// of changes made by the transaction. // of changes made by the transaction.
// //
// * The aggregate size of the items in the transaction exceeds 4 MBs.
//
// * There is a user error, such as an invalid data format. // * There is a user error, such as an invalid data format.
// //
// DynamoDB cancels a TransactGetItems request under the following circumstances: // DynamoDB cancels a TransactGetItems request under the following circumstances:
@ -200,8 +202,6 @@ const (
// * There is insufficient provisioned capacity for the transaction to be // * There is insufficient provisioned capacity for the transaction to be
// completed. // completed.
// //
// * The aggregate size of the items in the transaction exceeds 4 MBs.
//
// * There is a user error, such as an invalid data format. // * There is a user error, such as an invalid data format.
// //
// If using Java, DynamoDB lists the cancellation reasons on the CancellationReasons // If using Java, DynamoDB lists the cancellation reasons on the CancellationReasons
@ -268,3 +268,31 @@ const (
// The transaction with the given request token is already in progress. // The transaction with the given request token is already in progress.
ErrCodeTransactionInProgressException = "TransactionInProgressException" ErrCodeTransactionInProgressException = "TransactionInProgressException"
) )
var exceptionFromCode = map[string]func(protocol.ResponseMetadata) error{
"BackupInUseException": newErrorBackupInUseException,
"BackupNotFoundException": newErrorBackupNotFoundException,
"ConditionalCheckFailedException": newErrorConditionalCheckFailedException,
"ContinuousBackupsUnavailableException": newErrorContinuousBackupsUnavailableException,
"GlobalTableAlreadyExistsException": newErrorGlobalTableAlreadyExistsException,
"GlobalTableNotFoundException": newErrorGlobalTableNotFoundException,
"IdempotentParameterMismatchException": newErrorIdempotentParameterMismatchException,
"IndexNotFoundException": newErrorIndexNotFoundException,
"InternalServerError": newErrorInternalServerError,
"InvalidRestoreTimeException": newErrorInvalidRestoreTimeException,
"ItemCollectionSizeLimitExceededException": newErrorItemCollectionSizeLimitExceededException,
"LimitExceededException": newErrorLimitExceededException,
"PointInTimeRecoveryUnavailableException": newErrorPointInTimeRecoveryUnavailableException,
"ProvisionedThroughputExceededException": newErrorProvisionedThroughputExceededException,
"ReplicaAlreadyExistsException": newErrorReplicaAlreadyExistsException,
"ReplicaNotFoundException": newErrorReplicaNotFoundException,
"RequestLimitExceeded": newErrorRequestLimitExceeded,
"ResourceInUseException": newErrorResourceInUseException,
"ResourceNotFoundException": newErrorResourceNotFoundException,
"TableAlreadyExistsException": newErrorTableAlreadyExistsException,
"TableInUseException": newErrorTableInUseException,
"TableNotFoundException": newErrorTableNotFoundException,
"TransactionCanceledException": newErrorTransactionCanceledException,
"TransactionConflictException": newErrorTransactionConflictException,
"TransactionInProgressException": newErrorTransactionInProgressException,
}

View File

@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go/aws/crr" "github.com/aws/aws-sdk-go/aws/crr"
"github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/aws/signer/v4" "github.com/aws/aws-sdk-go/aws/signer/v4"
"github.com/aws/aws-sdk-go/private/protocol"
"github.com/aws/aws-sdk-go/private/protocol/jsonrpc" "github.com/aws/aws-sdk-go/private/protocol/jsonrpc"
) )
@ -33,7 +34,7 @@ var initRequest func(*request.Request)
const ( const (
ServiceName = "dynamodb" // Name of service. ServiceName = "dynamodb" // Name of service.
EndpointsID = ServiceName // ID to lookup a service endpoint with. EndpointsID = ServiceName // ID to lookup a service endpoint with.
ServiceID = "DynamoDB" // ServiceID is a unique identifer of a specific service. ServiceID = "DynamoDB" // ServiceID is a unique identifier of a specific service.
) )
// New creates a new instance of the DynamoDB client with a session. // New creates a new instance of the DynamoDB client with a session.
@ -41,6 +42,8 @@ const (
// aws.Config parameter to add your extra config. // aws.Config parameter to add your extra config.
// //
// Example: // Example:
// mySession := session.Must(session.NewSession())
//
// // Create a DynamoDB client from just a session. // // Create a DynamoDB client from just a session.
// svc := dynamodb.New(mySession) // svc := dynamodb.New(mySession)
// //
@ -48,11 +51,11 @@ const (
// svc := dynamodb.New(mySession, aws.NewConfig().WithRegion("us-west-2")) // svc := dynamodb.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
func New(p client.ConfigProvider, cfgs ...*aws.Config) *DynamoDB { func New(p client.ConfigProvider, cfgs ...*aws.Config) *DynamoDB {
c := p.ClientConfig(EndpointsID, cfgs...) c := p.ClientConfig(EndpointsID, cfgs...)
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) return newClient(*c.Config, c.Handlers, c.PartitionID, c.Endpoint, c.SigningRegion, c.SigningName)
} }
// newClient creates, initializes and returns a new service client instance. // newClient creates, initializes and returns a new service client instance.
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *DynamoDB { func newClient(cfg aws.Config, handlers request.Handlers, partitionID, endpoint, signingRegion, signingName string) *DynamoDB {
svc := &DynamoDB{ svc := &DynamoDB{
Client: client.New( Client: client.New(
cfg, cfg,
@ -61,6 +64,7 @@ func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
ServiceID: ServiceID, ServiceID: ServiceID,
SigningName: signingName, SigningName: signingName,
SigningRegion: signingRegion, SigningRegion: signingRegion,
PartitionID: partitionID,
Endpoint: endpoint, Endpoint: endpoint,
APIVersion: "2012-08-10", APIVersion: "2012-08-10",
JSONVersion: "1.0", JSONVersion: "1.0",
@ -76,7 +80,9 @@ func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler)
svc.Handlers.Unmarshal.PushBackNamed(jsonrpc.UnmarshalHandler) svc.Handlers.Unmarshal.PushBackNamed(jsonrpc.UnmarshalHandler)
svc.Handlers.UnmarshalMeta.PushBackNamed(jsonrpc.UnmarshalMetaHandler) svc.Handlers.UnmarshalMeta.PushBackNamed(jsonrpc.UnmarshalMetaHandler)
svc.Handlers.UnmarshalError.PushBackNamed(jsonrpc.UnmarshalErrorHandler) svc.Handlers.UnmarshalError.PushBackNamed(
protocol.NewUnmarshalErrorHandler(jsonrpc.NewUnmarshalTypedError(exceptionFromCode)).NamedHandler(),
)
// Run custom client initialization if present // Run custom client initialization if present
if initClient != nil { if initClient != nil {

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@ var initRequest func(*request.Request)
const ( const (
ServiceName = "iam" // Name of service. ServiceName = "iam" // Name of service.
EndpointsID = ServiceName // ID to lookup a service endpoint with. EndpointsID = ServiceName // ID to lookup a service endpoint with.
ServiceID = "IAM" // ServiceID is a unique identifer of a specific service. ServiceID = "IAM" // ServiceID is a unique identifier of a specific service.
) )
// New creates a new instance of the IAM client with a session. // New creates a new instance of the IAM client with a session.
@ -39,6 +39,8 @@ const (
// aws.Config parameter to add your extra config. // aws.Config parameter to add your extra config.
// //
// Example: // Example:
// mySession := session.Must(session.NewSession())
//
// // Create a IAM client from just a session. // // Create a IAM client from just a session.
// svc := iam.New(mySession) // svc := iam.New(mySession)
// //
@ -46,11 +48,11 @@ const (
// svc := iam.New(mySession, aws.NewConfig().WithRegion("us-west-2")) // svc := iam.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
func New(p client.ConfigProvider, cfgs ...*aws.Config) *IAM { func New(p client.ConfigProvider, cfgs ...*aws.Config) *IAM {
c := p.ClientConfig(EndpointsID, cfgs...) c := p.ClientConfig(EndpointsID, cfgs...)
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) return newClient(*c.Config, c.Handlers, c.PartitionID, c.Endpoint, c.SigningRegion, c.SigningName)
} }
// newClient creates, initializes and returns a new service client instance. // newClient creates, initializes and returns a new service client instance.
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *IAM { func newClient(cfg aws.Config, handlers request.Handlers, partitionID, endpoint, signingRegion, signingName string) *IAM {
svc := &IAM{ svc := &IAM{
Client: client.New( Client: client.New(
cfg, cfg,
@ -59,6 +61,7 @@ func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
ServiceID: ServiceID, ServiceID: ServiceID,
SigningName: signingName, SigningName: signingName,
SigningRegion: signingRegion, SigningRegion: signingRegion,
PartitionID: partitionID,
Endpoint: endpoint, Endpoint: endpoint,
APIVersion: "2010-05-08", APIVersion: "2010-05-08",
}, },

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@ import (
"github.com/aws/aws-sdk-go/aws/client" "github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/internal/s3err" "github.com/aws/aws-sdk-go/internal/s3err"
"github.com/aws/aws-sdk-go/service/s3/internal/arn"
) )
func init() { func init() {
@ -13,7 +14,7 @@ func init() {
func defaultInitClientFn(c *client.Client) { func defaultInitClientFn(c *client.Client) {
// Support building custom endpoints based on config // Support building custom endpoints based on config
c.Handlers.Build.PushFront(updateEndpointForS3Config) c.Handlers.Build.PushFront(endpointHandler)
// Require SSL when using SSE keys // Require SSL when using SSE keys
c.Handlers.Validate.PushBack(validateSSERequiresSSL) c.Handlers.Validate.PushBack(validateSSERequiresSSL)
@ -27,7 +28,7 @@ func defaultInitClientFn(c *client.Client) {
} }
func defaultInitRequestFn(r *request.Request) { func defaultInitRequestFn(r *request.Request) {
// Add reuest handlers for specific platforms. // Add request handlers for specific platforms.
// e.g. 100-continue support for PUT requests using Go 1.6 // e.g. 100-continue support for PUT requests using Go 1.6
platformRequestHandlers(r) platformRequestHandlers(r)
@ -73,3 +74,8 @@ type sseCustomerKeyGetter interface {
type copySourceSSECustomerKeyGetter interface { type copySourceSSECustomerKeyGetter interface {
getCopySourceSSECustomerKey() string getCopySourceSSECustomerKey() string
} }
type endpointARNGetter interface {
getEndpointARN() (arn.Resource, error)
hasEndpointARN() bool
}

233
vendor/github.com/aws/aws-sdk-go/service/s3/endpoint.go generated vendored Normal file
View File

@ -0,0 +1,233 @@
package s3
import (
"net/url"
"strings"
"github.com/aws/aws-sdk-go/aws"
awsarn "github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/private/protocol"
"github.com/aws/aws-sdk-go/service/s3/internal/arn"
)
// Used by shapes with members decorated as endpoint ARN.
func parseEndpointARN(v string) (arn.Resource, error) {
return arn.ParseResource(v, accessPointResourceParser)
}
func accessPointResourceParser(a awsarn.ARN) (arn.Resource, error) {
resParts := arn.SplitResource(a.Resource)
switch resParts[0] {
case "accesspoint":
return arn.ParseAccessPointResource(a, resParts[1:])
default:
return nil, arn.InvalidARNError{ARN: a, Reason: "unknown resource type"}
}
}
func endpointHandler(req *request.Request) {
endpoint, ok := req.Params.(endpointARNGetter)
if !ok || !endpoint.hasEndpointARN() {
updateBucketEndpointFromParams(req)
return
}
resource, err := endpoint.getEndpointARN()
if err != nil {
req.Error = newInvalidARNError(nil, err)
return
}
resReq := resourceRequest{
Resource: resource,
Request: req,
}
if resReq.IsCrossPartition() {
req.Error = newClientPartitionMismatchError(resource,
req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
return
}
if !resReq.AllowCrossRegion() && resReq.IsCrossRegion() {
req.Error = newClientRegionMismatchError(resource,
req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
return
}
if resReq.HasCustomEndpoint() {
req.Error = newInvalidARNWithCustomEndpointError(resource, nil)
return
}
switch tv := resource.(type) {
case arn.AccessPointARN:
err = updateRequestAccessPointEndpoint(req, tv)
if err != nil {
req.Error = err
}
default:
req.Error = newInvalidARNError(resource, nil)
}
}
type resourceRequest struct {
Resource arn.Resource
Request *request.Request
}
func (r resourceRequest) ARN() awsarn.ARN {
return r.Resource.GetARN()
}
func (r resourceRequest) AllowCrossRegion() bool {
return aws.BoolValue(r.Request.Config.S3UseARNRegion)
}
func (r resourceRequest) UseFIPS() bool {
return isFIPS(aws.StringValue(r.Request.Config.Region))
}
func (r resourceRequest) IsCrossPartition() bool {
return r.Request.ClientInfo.PartitionID != r.Resource.GetARN().Partition
}
func (r resourceRequest) IsCrossRegion() bool {
return isCrossRegion(r.Request, r.Resource.GetARN().Region)
}
func (r resourceRequest) HasCustomEndpoint() bool {
return len(aws.StringValue(r.Request.Config.Endpoint)) > 0
}
func isFIPS(clientRegion string) bool {
return strings.HasPrefix(clientRegion, "fips-") || strings.HasSuffix(clientRegion, "-fips")
}
func isCrossRegion(req *request.Request, otherRegion string) bool {
return req.ClientInfo.SigningRegion != otherRegion
}
func updateBucketEndpointFromParams(r *request.Request) {
bucket, ok := bucketNameFromReqParams(r.Params)
if !ok {
// Ignore operation requests if the bucket name was not provided
// if this is an input validation error the validation handler
// will report it.
return
}
updateEndpointForS3Config(r, bucket)
}
func updateRequestAccessPointEndpoint(req *request.Request, accessPoint arn.AccessPointARN) error {
// Accelerate not supported
if aws.BoolValue(req.Config.S3UseAccelerate) {
return newClientConfiguredForAccelerateError(accessPoint,
req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
}
// Ignore the disable host prefix for access points since custom endpoints
// are not supported.
req.Config.DisableEndpointHostPrefix = aws.Bool(false)
if err := accessPointEndpointBuilder(accessPoint).Build(req); err != nil {
return err
}
removeBucketFromPath(req.HTTPRequest.URL)
return nil
}
func removeBucketFromPath(u *url.URL) {
u.Path = strings.Replace(u.Path, "/{Bucket}", "", -1)
if u.Path == "" {
u.Path = "/"
}
}
type accessPointEndpointBuilder arn.AccessPointARN
const (
accessPointPrefixLabel = "accesspoint"
accountIDPrefixLabel = "accountID"
accesPointPrefixTemplate = "{" + accessPointPrefixLabel + "}-{" + accountIDPrefixLabel + "}."
)
func (a accessPointEndpointBuilder) Build(req *request.Request) error {
resolveRegion := arn.AccessPointARN(a).Region
cfgRegion := aws.StringValue(req.Config.Region)
if isFIPS(cfgRegion) {
if aws.BoolValue(req.Config.S3UseARNRegion) && isCrossRegion(req, resolveRegion) {
// FIPS with cross region is not supported, the SDK must fail
// because there is no well defined method for SDK to construct a
// correct FIPS endpoint.
return newClientConfiguredForCrossRegionFIPSError(arn.AccessPointARN(a),
req.ClientInfo.PartitionID, cfgRegion, nil)
}
resolveRegion = cfgRegion
}
endpoint, err := resolveRegionalEndpoint(req, resolveRegion)
if err != nil {
return newFailedToResolveEndpointError(arn.AccessPointARN(a),
req.ClientInfo.PartitionID, cfgRegion, err)
}
if err = updateRequestEndpoint(req, endpoint.URL); err != nil {
return err
}
const serviceEndpointLabel = "s3-accesspoint"
// dualstack provided by endpoint resolver
cfgHost := req.HTTPRequest.URL.Host
if strings.HasPrefix(cfgHost, "s3") {
req.HTTPRequest.URL.Host = serviceEndpointLabel + cfgHost[2:]
}
protocol.HostPrefixBuilder{
Prefix: accesPointPrefixTemplate,
LabelsFn: a.hostPrefixLabelValues,
}.Build(req)
req.ClientInfo.SigningName = endpoint.SigningName
req.ClientInfo.SigningRegion = endpoint.SigningRegion
err = protocol.ValidateEndpointHost(req.Operation.Name, req.HTTPRequest.URL.Host)
if err != nil {
return newInvalidARNError(arn.AccessPointARN(a), err)
}
return nil
}
func (a accessPointEndpointBuilder) hostPrefixLabelValues() map[string]string {
return map[string]string{
accessPointPrefixLabel: arn.AccessPointARN(a).AccessPointName,
accountIDPrefixLabel: arn.AccessPointARN(a).AccountID,
}
}
func resolveRegionalEndpoint(r *request.Request, region string) (endpoints.ResolvedEndpoint, error) {
return r.Config.EndpointResolver.EndpointFor(EndpointsID, region, func(opts *endpoints.Options) {
opts.DisableSSL = aws.BoolValue(r.Config.DisableSSL)
opts.UseDualStack = aws.BoolValue(r.Config.UseDualStack)
opts.S3UsEast1RegionalEndpoint = endpoints.RegionalS3UsEast1Endpoint
})
}
func updateRequestEndpoint(r *request.Request, endpoint string) (err error) {
endpoint = endpoints.AddScheme(endpoint, aws.BoolValue(r.Config.DisableSSL))
r.HTTPRequest.URL, err = url.Parse(endpoint + r.Operation.HTTPPath)
if err != nil {
return awserr.New(request.ErrCodeSerialization,
"failed to parse endpoint URL", err)
}
return nil
}

View File

@ -0,0 +1,151 @@
package s3
import (
"fmt"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/s3/internal/arn"
)
const (
invalidARNErrorErrCode = "InvalidARNError"
configurationErrorErrCode = "ConfigurationError"
)
type invalidARNError struct {
message string
resource arn.Resource
origErr error
}
func (e invalidARNError) Error() string {
var extra string
if e.resource != nil {
extra = "ARN: " + e.resource.String()
}
return awserr.SprintError(e.Code(), e.Message(), extra, e.origErr)
}
func (e invalidARNError) Code() string {
return invalidARNErrorErrCode
}
func (e invalidARNError) Message() string {
return e.message
}
func (e invalidARNError) OrigErr() error {
return e.origErr
}
func newInvalidARNError(resource arn.Resource, err error) invalidARNError {
return invalidARNError{
message: "invalid ARN",
origErr: err,
resource: resource,
}
}
func newInvalidARNWithCustomEndpointError(resource arn.Resource, err error) invalidARNError {
return invalidARNError{
message: "resource ARN not supported with custom client endpoints",
origErr: err,
resource: resource,
}
}
// ARN not supported for the target partition
func newInvalidARNWithUnsupportedPartitionError(resource arn.Resource, err error) invalidARNError {
return invalidARNError{
message: "resource ARN not supported for the target ARN partition",
origErr: err,
resource: resource,
}
}
type configurationError struct {
message string
resource arn.Resource
clientPartitionID string
clientRegion string
origErr error
}
func (e configurationError) Error() string {
extra := fmt.Sprintf("ARN: %s, client partition: %s, client region: %s",
e.resource, e.clientPartitionID, e.clientRegion)
return awserr.SprintError(e.Code(), e.Message(), extra, e.origErr)
}
func (e configurationError) Code() string {
return configurationErrorErrCode
}
func (e configurationError) Message() string {
return e.message
}
func (e configurationError) OrigErr() error {
return e.origErr
}
func newClientPartitionMismatchError(resource arn.Resource, clientPartitionID, clientRegion string, err error) configurationError {
return configurationError{
message: "client partition does not match provided ARN partition",
origErr: err,
resource: resource,
clientPartitionID: clientPartitionID,
clientRegion: clientRegion,
}
}
func newClientRegionMismatchError(resource arn.Resource, clientPartitionID, clientRegion string, err error) configurationError {
return configurationError{
message: "client region does not match provided ARN region",
origErr: err,
resource: resource,
clientPartitionID: clientPartitionID,
clientRegion: clientRegion,
}
}
func newFailedToResolveEndpointError(resource arn.Resource, clientPartitionID, clientRegion string, err error) configurationError {
return configurationError{
message: "endpoint resolver failed to find an endpoint for the provided ARN region",
origErr: err,
resource: resource,
clientPartitionID: clientPartitionID,
clientRegion: clientRegion,
}
}
func newClientConfiguredForFIPSError(resource arn.Resource, clientPartitionID, clientRegion string, err error) configurationError {
return configurationError{
message: "client configured for fips but cross-region resource ARN provided",
origErr: err,
resource: resource,
clientPartitionID: clientPartitionID,
clientRegion: clientRegion,
}
}
func newClientConfiguredForAccelerateError(resource arn.Resource, clientPartitionID, clientRegion string, err error) configurationError {
return configurationError{
message: "client configured for S3 Accelerate but is supported with resource ARN",
origErr: err,
resource: resource,
clientPartitionID: clientPartitionID,
clientRegion: clientRegion,
}
}
func newClientConfiguredForCrossRegionFIPSError(resource arn.Resource, clientPartitionID, clientRegion string, err error) configurationError {
return configurationError{
message: "client configured for FIPS with cross-region enabled but is supported with cross-region resource ARN",
origErr: err,
resource: resource,
clientPartitionID: clientPartitionID,
clientRegion: clientRegion,
}
}

View File

@ -13,6 +13,12 @@ const (
// ErrCodeBucketAlreadyOwnedByYou for service response error code // ErrCodeBucketAlreadyOwnedByYou for service response error code
// "BucketAlreadyOwnedByYou". // "BucketAlreadyOwnedByYou".
//
// The bucket you tried to create already exists, and you own it. Amazon S3
// returns this error in all AWS Regions except in the North Virginia Region.
// For legacy compatibility, if you re-create an existing bucket that you already
// own in the North Virginia Region, Amazon S3 returns 200 OK and resets the
// bucket access control lists (ACLs).
ErrCodeBucketAlreadyOwnedByYou = "BucketAlreadyOwnedByYou" ErrCodeBucketAlreadyOwnedByYou = "BucketAlreadyOwnedByYou"
// ErrCodeNoSuchBucket for service response error code // ErrCodeNoSuchBucket for service response error code
@ -36,13 +42,13 @@ const (
// ErrCodeObjectAlreadyInActiveTierError for service response error code // ErrCodeObjectAlreadyInActiveTierError for service response error code
// "ObjectAlreadyInActiveTierError". // "ObjectAlreadyInActiveTierError".
// //
// This operation is not allowed against this storage tier // This operation is not allowed against this storage tier.
ErrCodeObjectAlreadyInActiveTierError = "ObjectAlreadyInActiveTierError" ErrCodeObjectAlreadyInActiveTierError = "ObjectAlreadyInActiveTierError"
// ErrCodeObjectNotInActiveTierError for service response error code // ErrCodeObjectNotInActiveTierError for service response error code
// "ObjectNotInActiveTierError". // "ObjectNotInActiveTierError".
// //
// The source object of the COPY operation is not in the active tier and is // The source object of the COPY operation is not in the active tier and is
// only stored in Amazon Glacier. // only stored in Amazon S3 Glacier.
ErrCodeObjectNotInActiveTierError = "ObjectNotInActiveTierError" ErrCodeObjectNotInActiveTierError = "ObjectNotInActiveTierError"
) )

View File

@ -30,10 +30,10 @@ var accelerateOpBlacklist = operationBlacklist{
opListBuckets, opCreateBucket, opDeleteBucket, opListBuckets, opCreateBucket, opDeleteBucket,
} }
// Request handler to automatically add the bucket name to the endpoint domain // Automatically add the bucket name to the endpoint domain
// if possible. This style of bucket is valid for all bucket names which are // if possible. This style of bucket is valid for all bucket names which are
// DNS compatible and do not contain "." // DNS compatible and do not contain "."
func updateEndpointForS3Config(r *request.Request) { func updateEndpointForS3Config(r *request.Request, bucketName string) {
forceHostStyle := aws.BoolValue(r.Config.S3ForcePathStyle) forceHostStyle := aws.BoolValue(r.Config.S3ForcePathStyle)
accelerate := aws.BoolValue(r.Config.S3UseAccelerate) accelerate := aws.BoolValue(r.Config.S3UseAccelerate)
@ -43,45 +43,29 @@ func updateEndpointForS3Config(r *request.Request) {
r.Config.Logger.Log("ERROR: aws.Config.S3UseAccelerate is not compatible with aws.Config.S3ForcePathStyle, ignoring S3ForcePathStyle.") r.Config.Logger.Log("ERROR: aws.Config.S3UseAccelerate is not compatible with aws.Config.S3ForcePathStyle, ignoring S3ForcePathStyle.")
} }
} }
updateEndpointForAccelerate(r) updateEndpointForAccelerate(r, bucketName)
} else if !forceHostStyle && r.Operation.Name != opGetBucketLocation { } else if !forceHostStyle && r.Operation.Name != opGetBucketLocation {
updateEndpointForHostStyle(r) updateEndpointForHostStyle(r, bucketName)
} }
} }
func updateEndpointForHostStyle(r *request.Request) { func updateEndpointForHostStyle(r *request.Request, bucketName string) {
bucket, ok := bucketNameFromReqParams(r.Params) if !hostCompatibleBucketName(r.HTTPRequest.URL, bucketName) {
if !ok {
// Ignore operation requests if the bucketname was not provided
// if this is an input validation error the validation handler
// will report it.
return
}
if !hostCompatibleBucketName(r.HTTPRequest.URL, bucket) {
// bucket name must be valid to put into the host // bucket name must be valid to put into the host
return return
} }
moveBucketToHost(r.HTTPRequest.URL, bucket) moveBucketToHost(r.HTTPRequest.URL, bucketName)
} }
var ( var (
accelElem = []byte("s3-accelerate.dualstack.") accelElem = []byte("s3-accelerate.dualstack.")
) )
func updateEndpointForAccelerate(r *request.Request) { func updateEndpointForAccelerate(r *request.Request, bucketName string) {
bucket, ok := bucketNameFromReqParams(r.Params) if !hostCompatibleBucketName(r.HTTPRequest.URL, bucketName) {
if !ok {
// Ignore operation requests if the bucketname was not provided
// if this is an input validation error the validation handler
// will report it.
return
}
if !hostCompatibleBucketName(r.HTTPRequest.URL, bucket) {
r.Error = awserr.New("InvalidParameterException", r.Error = awserr.New("InvalidParameterException",
fmt.Sprintf("bucket name %s is not compatible with S3 Accelerate", bucket), fmt.Sprintf("bucket name %s is not compatible with S3 Accelerate", bucketName),
nil) nil)
return return
} }
@ -106,7 +90,7 @@ func updateEndpointForAccelerate(r *request.Request) {
r.HTTPRequest.URL.Host = strings.Join(parts, ".") r.HTTPRequest.URL.Host = strings.Join(parts, ".")
moveBucketToHost(r.HTTPRequest.URL, bucket) moveBucketToHost(r.HTTPRequest.URL, bucketName)
} }
// Attempts to retrieve the bucket name from the request input parameters. // Attempts to retrieve the bucket name from the request input parameters.
@ -148,8 +132,5 @@ func dnsCompatibleBucketName(bucket string) bool {
// moveBucketToHost moves the bucket name from the URI path to URL host. // moveBucketToHost moves the bucket name from the URI path to URL host.
func moveBucketToHost(u *url.URL, bucket string) { func moveBucketToHost(u *url.URL, bucket string) {
u.Host = bucket + "." + u.Host u.Host = bucket + "." + u.Host
u.Path = strings.Replace(u.Path, "/{Bucket}", "", -1) removeBucketFromPath(u)
if u.Path == "" {
u.Path = "/"
}
} }

View File

@ -0,0 +1,45 @@
package arn
import (
"strings"
"github.com/aws/aws-sdk-go/aws/arn"
)
// AccessPointARN provides representation
type AccessPointARN struct {
arn.ARN
AccessPointName string
}
// GetARN returns the base ARN for the Access Point resource
func (a AccessPointARN) GetARN() arn.ARN {
return a.ARN
}
// ParseAccessPointResource attempts to parse the ARN's resource as an
// AccessPoint resource.
func ParseAccessPointResource(a arn.ARN, resParts []string) (AccessPointARN, error) {
if len(a.Region) == 0 {
return AccessPointARN{}, InvalidARNError{a, "region not set"}
}
if len(a.AccountID) == 0 {
return AccessPointARN{}, InvalidARNError{a, "account-id not set"}
}
if len(resParts) == 0 {
return AccessPointARN{}, InvalidARNError{a, "resource-id not set"}
}
if len(resParts) > 1 {
return AccessPointARN{}, InvalidARNError{a, "sub resource not supported"}
}
resID := resParts[0]
if len(strings.TrimSpace(resID)) == 0 {
return AccessPointARN{}, InvalidARNError{a, "resource-id not set"}
}
return AccessPointARN{
ARN: a,
AccessPointName: resID,
}, nil
}

View File

@ -0,0 +1,71 @@
package arn
import (
"strings"
"github.com/aws/aws-sdk-go/aws/arn"
)
// Resource provides the interfaces abstracting ARNs of specific resource
// types.
type Resource interface {
GetARN() arn.ARN
String() string
}
// ResourceParser provides the function for parsing an ARN's resource
// component into a typed resource.
type ResourceParser func(arn.ARN) (Resource, error)
// ParseResource parses an AWS ARN into a typed resource for the S3 API.
func ParseResource(s string, resParser ResourceParser) (resARN Resource, err error) {
a, err := arn.Parse(s)
if err != nil {
return nil, err
}
if len(a.Partition) == 0 {
return nil, InvalidARNError{a, "partition not set"}
}
if a.Service != "s3" {
return nil, InvalidARNError{a, "service is not S3"}
}
if len(a.Resource) == 0 {
return nil, InvalidARNError{a, "resource not set"}
}
return resParser(a)
}
// SplitResource splits the resource components by the ARN resource delimiters.
func SplitResource(v string) []string {
var parts []string
var offset int
for offset <= len(v) {
idx := strings.IndexAny(v[offset:], "/:")
if idx < 0 {
parts = append(parts, v[offset:])
break
}
parts = append(parts, v[offset:idx+offset])
offset += idx + 1
}
return parts
}
// IsARN returns whether the given string is an ARN
func IsARN(s string) bool {
return arn.IsARN(s)
}
// InvalidARNError provides the error for an invalid ARN error.
type InvalidARNError struct {
ARN arn.ARN
Reason string
}
func (e InvalidARNError) Error() string {
return "invalid Amazon S3 ARN, " + e.Reason + ", " + e.ARN.String()
}

View File

@ -31,7 +31,7 @@ var initRequest func(*request.Request)
const ( const (
ServiceName = "s3" // Name of service. ServiceName = "s3" // Name of service.
EndpointsID = ServiceName // ID to lookup a service endpoint with. EndpointsID = ServiceName // ID to lookup a service endpoint with.
ServiceID = "S3" // ServiceID is a unique identifer of a specific service. ServiceID = "S3" // ServiceID is a unique identifier of a specific service.
) )
// New creates a new instance of the S3 client with a session. // New creates a new instance of the S3 client with a session.
@ -39,6 +39,8 @@ const (
// aws.Config parameter to add your extra config. // aws.Config parameter to add your extra config.
// //
// Example: // Example:
// mySession := session.Must(session.NewSession())
//
// // Create a S3 client from just a session. // // Create a S3 client from just a session.
// svc := s3.New(mySession) // svc := s3.New(mySession)
// //
@ -46,11 +48,11 @@ const (
// svc := s3.New(mySession, aws.NewConfig().WithRegion("us-west-2")) // svc := s3.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
func New(p client.ConfigProvider, cfgs ...*aws.Config) *S3 { func New(p client.ConfigProvider, cfgs ...*aws.Config) *S3 {
c := p.ClientConfig(EndpointsID, cfgs...) c := p.ClientConfig(EndpointsID, cfgs...)
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) return newClient(*c.Config, c.Handlers, c.PartitionID, c.Endpoint, c.SigningRegion, c.SigningName)
} }
// newClient creates, initializes and returns a new service client instance. // newClient creates, initializes and returns a new service client instance.
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *S3 { func newClient(cfg aws.Config, handlers request.Handlers, partitionID, endpoint, signingRegion, signingName string) *S3 {
svc := &S3{ svc := &S3{
Client: client.New( Client: client.New(
cfg, cfg,
@ -59,6 +61,7 @@ func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
ServiceID: ServiceID, ServiceID: ServiceID,
SigningName: signingName, SigningName: signingName,
SigningRegion: signingRegion, SigningRegion: signingRegion,
PartitionID: partitionID,
Endpoint: endpoint, Endpoint: endpoint,
APIVersion: "2006-03-01", APIVersion: "2006-03-01",
}, },
@ -75,6 +78,7 @@ func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
svc.Handlers.UnmarshalMeta.PushBackNamed(restxml.UnmarshalMetaHandler) svc.Handlers.UnmarshalMeta.PushBackNamed(restxml.UnmarshalMetaHandler)
svc.Handlers.UnmarshalError.PushBackNamed(restxml.UnmarshalErrorHandler) svc.Handlers.UnmarshalError.PushBackNamed(restxml.UnmarshalErrorHandler)
svc.Handlers.BuildStream.PushBackNamed(restxml.BuildHandler)
svc.Handlers.UnmarshalStream.PushBackNamed(restxml.UnmarshalHandler) svc.Handlers.UnmarshalStream.PushBackNamed(restxml.UnmarshalHandler)
// Run custom client initialization if present // Run custom client initialization if present

View File

@ -78,6 +78,8 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o
// IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html) // IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html)
// in the IAM User Guide. // in the IAM User Guide.
// //
// Session Duration
//
// By default, the temporary security credentials created by AssumeRole last // By default, the temporary security credentials created by AssumeRole last
// for one hour. However, you can use the optional DurationSeconds parameter // 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 // to specify the duration of your session. You can provide a value from 900
@ -91,6 +93,8 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o
// URL. For more information, see Using IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html) // URL. For more information, see Using IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html)
// in the IAM User Guide. // in the IAM User Guide.
// //
// Permissions
//
// The temporary security credentials created by AssumeRole can be used to make // 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 // API calls to any AWS service with the following exception: You cannot call
// the AWS STS GetFederationToken or GetSessionToken API operations. // the AWS STS GetFederationToken or GetSessionToken API operations.
@ -99,7 +103,7 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o
// to this operation. You can pass a single JSON policy document to use as an // to this operation. You can pass a single JSON policy document to use as an
// inline session policy. You can also specify up to 10 managed policies to // inline session policy. You can also specify up to 10 managed policies to
// use as managed session policies. The plain text that you use for both inline // use as managed session policies. The plain text that you use for both inline
// and managed session policies shouldn't exceed 2048 characters. Passing policies // and managed session policies can't exceed 2,048 characters. Passing policies
// to this operation returns new temporary credentials. The resulting session's // to this operation returns new temporary credentials. The resulting session's
// permissions are the intersection of the role's identity-based policy and // permissions are the intersection of the role's identity-based policy and
// the session policies. You can use the role's temporary credentials in subsequent // the session policies. You can use the role's temporary credentials in subsequent
@ -131,6 +135,24 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o
// see IAM Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html) // see IAM Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html)
// in the IAM User Guide. // in the IAM User Guide.
// //
// Tags
//
// (Optional) You can pass tag key-value pairs to your session. These tags are
// called session tags. For more information about session tags, see Passing
// Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
// in the IAM User Guide.
//
// An administrator must grant you the permissions necessary to pass session
// tags. The administrator can also create granular permissions to allow you
// to pass only specific session tags. For more information, see Tutorial: Using
// Tags for Attribute-Based Access Control (https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)
// in the IAM User Guide.
//
// You can set the session tags as transitive. Transitive tags persist during
// role chaining. For more information, see Chaining Roles with Session Tags
// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining)
// in the IAM User Guide.
//
// Using MFA with AssumeRole // Using MFA with AssumeRole
// //
// (Optional) You can include multi-factor authentication (MFA) information // (Optional) You can include multi-factor authentication (MFA) information
@ -165,9 +187,18 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o
// message describes the specific error. // message describes the specific error.
// //
// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge" // * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge"
// The request was rejected because the policy document was too large. The error // The request was rejected because the total packed size of the session policies
// message describes how big the policy document is, in packed form, as a percentage // and session tags combined was too large. An AWS conversion compresses the
// of what the API allows. // session policy document, session policy ARNs, and session tags into a packed
// binary format that has a separate limit. The error message indicates by percentage
// how close the policies and tags are to the upper size limit. For more information,
// see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
// in the IAM User Guide.
//
// You could receive this error even though you meet other defined session policy
// and session tag limits. For more information, see IAM and STS Entity Character
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
// in the IAM User Guide.
// //
// * ErrCodeRegionDisabledException "RegionDisabledException" // * ErrCodeRegionDisabledException "RegionDisabledException"
// STS is not activated in the requested region for the account that is being // STS is not activated in the requested region for the account that is being
@ -256,6 +287,8 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re
// an access key ID, a secret access key, and a security token. Applications // 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. // can use these temporary security credentials to sign calls to AWS services.
// //
// Session Duration
//
// By default, the temporary security credentials created by AssumeRoleWithSAML // By default, the temporary security credentials created by AssumeRoleWithSAML
// last for one hour. However, you can use the optional DurationSeconds parameter // 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 // to specify the duration of your session. Your role session lasts for the
@ -271,6 +304,8 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re
// URL. For more information, see Using IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html) // URL. For more information, see Using IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html)
// in the IAM User Guide. // in the IAM User Guide.
// //
// Permissions
//
// The temporary security credentials created by AssumeRoleWithSAML can be used // The temporary security credentials created by AssumeRoleWithSAML can be used
// to make API calls to any AWS service with the following exception: you cannot // to make API calls to any AWS service with the following exception: you cannot
// call the STS GetFederationToken or GetSessionToken API operations. // call the STS GetFederationToken or GetSessionToken API operations.
@ -279,7 +314,7 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re
// to this operation. You can pass a single JSON policy document to use as an // to this operation. You can pass a single JSON policy document to use as an
// inline session policy. You can also specify up to 10 managed policies to // inline session policy. You can also specify up to 10 managed policies to
// use as managed session policies. The plain text that you use for both inline // use as managed session policies. The plain text that you use for both inline
// and managed session policies shouldn't exceed 2048 characters. Passing policies // and managed session policies can't exceed 2,048 characters. Passing policies
// to this operation returns new temporary credentials. The resulting session's // to this operation returns new temporary credentials. The resulting session's
// permissions are the intersection of the role's identity-based policy and // permissions are the intersection of the role's identity-based policy and
// the session policies. You can use the role's temporary credentials in subsequent // the session policies. You can use the role's temporary credentials in subsequent
@ -289,12 +324,6 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re
// information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
// in the IAM User Guide. // in the IAM User Guide.
// //
// Before your application can call AssumeRoleWithSAML, you must configure your
// SAML identity provider (IdP) to issue the claims required by AWS. Additionally,
// you must use AWS Identity and Access Management (IAM) to create a SAML provider
// entity in your AWS account that represents your identity provider. You must
// also create an IAM role that specifies this SAML provider in its trust policy.
//
// Calling AssumeRoleWithSAML does not require the use of AWS security credentials. // Calling AssumeRoleWithSAML does not require the use of AWS security credentials.
// The identity of the caller is validated by using keys in the metadata document // The identity of the caller is validated by using keys in the metadata document
// that is uploaded for the SAML provider entity for your identity provider. // that is uploaded for the SAML provider entity for your identity provider.
@ -302,8 +331,50 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re
// Calling AssumeRoleWithSAML can result in an entry in your AWS CloudTrail // Calling AssumeRoleWithSAML can result in an entry in your AWS CloudTrail
// logs. The entry includes the value in the NameID element of the SAML assertion. // logs. The entry includes the value in the NameID element of the SAML assertion.
// We recommend that you use a NameIDType that is not associated with any personally // We recommend that you use a NameIDType that is not associated with any personally
// identifiable information (PII). For example, you could instead use the Persistent // identifiable information (PII). For example, you could instead use the persistent
// Identifier (urn:oasis:names:tc:SAML:2.0:nameid-format:persistent). // identifier (urn:oasis:names:tc:SAML:2.0:nameid-format:persistent).
//
// Tags
//
// (Optional) You can configure your IdP to pass attributes into your SAML assertion
// as session tags. Each session tag consists of a key name and an associated
// value. For more information about session tags, see Passing Session Tags
// in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
// in the IAM User Guide.
//
// You can pass up to 50 session tags. The plain text session tag keys cant
// exceed 128 characters and the values cant exceed 256 characters. For these
// and additional limits, see IAM and STS Character Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length)
// in the IAM User Guide.
//
// An AWS conversion compresses the passed session policies and session tags
// into a packed binary format that has a separate limit. Your request can fail
// for this limit even if your plain text meets the other requirements. The
// PackedPolicySize response element indicates by percentage how close the policies
// and tags for your request are to the upper size limit.
//
// You can pass a session tag with the same key as a tag that is attached to
// the role. When you do, session tags override the role's tags with the same
// key.
//
// An administrator must grant you the permissions necessary to pass session
// tags. The administrator can also create granular permissions to allow you
// to pass only specific session tags. For more information, see Tutorial: Using
// Tags for Attribute-Based Access Control (https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)
// in the IAM User Guide.
//
// You can set the session tags as transitive. Transitive tags persist during
// role chaining. For more information, see Chaining Roles with Session Tags
// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining)
// in the IAM User Guide.
//
// SAML Configuration
//
// Before your application can call AssumeRoleWithSAML, you must configure your
// SAML identity provider (IdP) to issue the claims required by AWS. Additionally,
// you must use AWS Identity and Access Management (IAM) to create a SAML provider
// entity in your AWS account that represents your identity provider. You must
// also create an IAM role that specifies this SAML provider in its trust policy.
// //
// For more information, see the following resources: // For more information, see the following resources:
// //
@ -332,9 +403,18 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re
// message describes the specific error. // message describes the specific error.
// //
// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge" // * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge"
// The request was rejected because the policy document was too large. The error // The request was rejected because the total packed size of the session policies
// message describes how big the policy document is, in packed form, as a percentage // and session tags combined was too large. An AWS conversion compresses the
// of what the API allows. // session policy document, session policy ARNs, and session tags into a packed
// binary format that has a separate limit. The error message indicates by percentage
// how close the policies and tags are to the upper size limit. For more information,
// see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
// in the IAM User Guide.
//
// You could receive this error even though you meet other defined session policy
// and session tag limits. For more information, see IAM and STS Entity Character
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
// in the IAM User Guide.
// //
// * ErrCodeIDPRejectedClaimException "IDPRejectedClaim" // * ErrCodeIDPRejectedClaimException "IDPRejectedClaim"
// The identity provider (IdP) reported that authentication failed. This might // The identity provider (IdP) reported that authentication failed. This might
@ -456,6 +536,8 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI
// key ID, a secret access key, and a security token. Applications can use these // key ID, a secret access key, and a security token. Applications can use these
// temporary security credentials to sign calls to AWS service API operations. // temporary security credentials to sign calls to AWS service API operations.
// //
// Session Duration
//
// By default, the temporary security credentials created by AssumeRoleWithWebIdentity // By default, the temporary security credentials created by AssumeRoleWithWebIdentity
// last for one hour. However, you can use the optional DurationSeconds parameter // 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 // to specify the duration of your session. You can provide a value from 900
@ -469,6 +551,8 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI
// URL. For more information, see Using IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html) // URL. For more information, see Using IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html)
// in the IAM User Guide. // in the IAM User Guide.
// //
// Permissions
//
// The temporary security credentials created by AssumeRoleWithWebIdentity can // The temporary security credentials created by AssumeRoleWithWebIdentity can
// be used to make API calls to any AWS service with the following exception: // be used to make API calls to any AWS service with the following exception:
// you cannot call the STS GetFederationToken or GetSessionToken API operations. // you cannot call the STS GetFederationToken or GetSessionToken API operations.
@ -477,7 +561,7 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI
// to this operation. You can pass a single JSON policy document to use as an // to this operation. You can pass a single JSON policy document to use as an
// inline session policy. You can also specify up to 10 managed policies to // inline session policy. You can also specify up to 10 managed policies to
// use as managed session policies. The plain text that you use for both inline // use as managed session policies. The plain text that you use for both inline
// and managed session policies shouldn't exceed 2048 characters. Passing policies // and managed session policies can't exceed 2,048 characters. Passing policies
// to this operation returns new temporary credentials. The resulting session's // to this operation returns new temporary credentials. The resulting session's
// permissions are the intersection of the role's identity-based policy and // permissions are the intersection of the role's identity-based policy and
// the session policies. You can use the role's temporary credentials in subsequent // the session policies. You can use the role's temporary credentials in subsequent
@ -487,6 +571,42 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI
// information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
// in the IAM User Guide. // in the IAM User Guide.
// //
// Tags
//
// (Optional) You can configure your IdP to pass attributes into your web identity
// token as session tags. Each session tag consists of a key name and an associated
// value. For more information about session tags, see Passing Session Tags
// in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
// in the IAM User Guide.
//
// You can pass up to 50 session tags. The plain text session tag keys cant
// exceed 128 characters and the values cant exceed 256 characters. For these
// and additional limits, see IAM and STS Character Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length)
// in the IAM User Guide.
//
// An AWS conversion compresses the passed session policies and session tags
// into a packed binary format that has a separate limit. Your request can fail
// for this limit even if your plain text meets the other requirements. The
// PackedPolicySize response element indicates by percentage how close the policies
// and tags for your request are to the upper size limit.
//
// You can pass a session tag with the same key as a tag that is attached to
// the role. When you do, the session tag overrides the role tag with the same
// key.
//
// An administrator must grant you the permissions necessary to pass session
// tags. The administrator can also create granular permissions to allow you
// to pass only specific session tags. For more information, see Tutorial: Using
// Tags for Attribute-Based Access Control (https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)
// in the IAM User Guide.
//
// You can set the session tags as transitive. Transitive tags persist during
// role chaining. For more information, see Chaining Roles with Session Tags
// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining)
// in the IAM User Guide.
//
// Identities
//
// Before your application can call AssumeRoleWithWebIdentity, you must have // Before your application can call AssumeRoleWithWebIdentity, you must have
// an identity token from a supported identity provider and create a role that // an identity token from a supported identity provider and create a role that
// the application can assume. The role that your application assumes must trust // the application can assume. The role that your application assumes must trust
@ -514,8 +634,8 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI
// * AWS SDK for iOS Developer Guide (http://aws.amazon.com/sdkforios/) and // * AWS SDK for iOS Developer Guide (http://aws.amazon.com/sdkforios/) and
// AWS SDK for Android Developer Guide (http://aws.amazon.com/sdkforandroid/). // AWS SDK for Android Developer Guide (http://aws.amazon.com/sdkforandroid/).
// These toolkits contain sample apps that show how to invoke the identity // These toolkits contain sample apps that show how to invoke the identity
// providers, and then how to use the information from these providers to // providers. The toolkits then show how to use the information from these
// get and use temporary security credentials. // providers to get and use temporary security credentials.
// //
// * Web Identity Federation with Mobile Applications (http://aws.amazon.com/articles/web-identity-federation-with-mobile-applications). // * 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 // This article discusses web identity federation and shows an example of
@ -535,9 +655,18 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI
// message describes the specific error. // message describes the specific error.
// //
// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge" // * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge"
// The request was rejected because the policy document was too large. The error // The request was rejected because the total packed size of the session policies
// message describes how big the policy document is, in packed form, as a percentage // and session tags combined was too large. An AWS conversion compresses the
// of what the API allows. // session policy document, session policy ARNs, and session tags into a packed
// binary format that has a separate limit. The error message indicates by percentage
// how close the policies and tags are to the upper size limit. For more information,
// see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
// in the IAM User Guide.
//
// You could receive this error even though you meet other defined session policy
// and session tag limits. For more information, see IAM and STS Entity Character
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
// in the IAM User Guide.
// //
// * ErrCodeIDPRejectedClaimException "IDPRejectedClaim" // * ErrCodeIDPRejectedClaimException "IDPRejectedClaim"
// The identity provider (IdP) reported that authentication failed. This might // The identity provider (IdP) reported that authentication failed. This might
@ -547,11 +676,11 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI
// can also mean that the claim has expired or has been explicitly revoked. // can also mean that the claim has expired or has been explicitly revoked.
// //
// * ErrCodeIDPCommunicationErrorException "IDPCommunicationError" // * ErrCodeIDPCommunicationErrorException "IDPCommunicationError"
// The request could not be fulfilled because the non-AWS identity provider // The request could not be fulfilled because the identity provider (IDP) that
// (IDP) that was asked to verify the incoming identity token could not be reached. // was asked to verify the incoming identity token could not be reached. This
// This is often a transient error caused by network conditions. Retry the request // is often a transient error caused by network conditions. Retry the request
// a limited number of times so that you don't exceed the request rate. If the // a limited number of times so that you don't exceed the request rate. If the
// error persists, the non-AWS identity provider might be down or not responding. // error persists, the identity provider might be down or not responding.
// //
// * ErrCodeInvalidIdentityTokenException "InvalidIdentityToken" // * ErrCodeInvalidIdentityTokenException "InvalidIdentityToken"
// The web identity token that was passed could not be validated by AWS. Get // The web identity token that was passed could not be validated by AWS. Get
@ -763,7 +892,8 @@ func (c *STS) GetAccessKeyInfoRequest(input *GetAccessKeyInfoInput) (req *reques
// pull a credentials report (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_getting-report.html) // pull a credentials report (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_getting-report.html)
// to learn which IAM user owns the keys. To learn who requested the temporary // to learn which IAM user owns the keys. To learn who requested the temporary
// credentials for an ASIA access key, view the STS events in your CloudTrail // credentials for an ASIA access key, view the STS events in your CloudTrail
// logs (https://docs.aws.amazon.com/IAM/latest/UserGuide/cloudtrail-integration.html). // logs (https://docs.aws.amazon.com/IAM/latest/UserGuide/cloudtrail-integration.html)
// in the IAM User Guide.
// //
// This operation does not indicate the state of the access key. The key might // This operation does not indicate the state of the access key. The key might
// be active, inactive, or deleted. Active keys might not have permissions to // be active, inactive, or deleted. Active keys might not have permissions to
@ -850,7 +980,8 @@ func (c *STS) GetCallerIdentityRequest(input *GetCallerIdentityInput) (req *requ
// sts:GetCallerIdentity action, you can still perform this operation. Permissions // sts:GetCallerIdentity action, you can still perform this operation. Permissions
// are not required because the same information is returned when an IAM user // are not required because the same information is returned when an IAM user
// or role is denied access. To view an example response, see I Am Not Authorized // or role is denied access. To view an example response, see I Am Not Authorized
// to Perform: iam:DeleteVirtualMFADevice (https://docs.aws.amazon.com/IAM/latest/UserGuide/troubleshoot_general.html#troubleshoot_general_access-denied-delete-mfa). // to Perform: iam:DeleteVirtualMFADevice (https://docs.aws.amazon.com/IAM/latest/UserGuide/troubleshoot_general.html#troubleshoot_general_access-denied-delete-mfa)
// in the IAM User Guide.
// //
// Returns awserr.Error for service API and SDK errors. Use runtime type assertions // Returns awserr.Error for service API and SDK errors. Use runtime type assertions
// with awserr.Error's Code and Message methods to get detailed information about // with awserr.Error's Code and Message methods to get detailed information about
@ -942,7 +1073,8 @@ func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *re
// or an OpenID Connect-compatible identity provider. In this case, we recommend // or an OpenID Connect-compatible identity provider. In this case, we recommend
// that you use Amazon Cognito (http://aws.amazon.com/cognito/) or AssumeRoleWithWebIdentity. // that you use Amazon Cognito (http://aws.amazon.com/cognito/) or AssumeRoleWithWebIdentity.
// For more information, see Federation Through a Web-based Identity Provider // For more information, see Federation Through a Web-based Identity Provider
// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity). // (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity)
// in the IAM User Guide.
// //
// You can also call GetFederationToken using the security credentials of an // You can also call GetFederationToken using the security credentials of an
// AWS account root user, but we do not recommend it. Instead, we recommend // AWS account root user, but we do not recommend it. Instead, we recommend
@ -952,41 +1084,67 @@ func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *re
// Practices (https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) // Practices (https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html)
// in the IAM User Guide. // in the IAM User Guide.
// //
// Session duration
//
// The temporary credentials are valid for the specified duration, from 900 // The temporary credentials are valid for the specified duration, from 900
// seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours). The default // seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours). The default
// is 43,200 seconds (12 hours). Temporary credentials that are obtained by // session duration is 43,200 seconds (12 hours). Temporary credentials that
// using AWS account root user credentials have a maximum duration of 3,600 // are obtained by using AWS account root user credentials have a maximum duration
// seconds (1 hour). // of 3,600 seconds (1 hour).
//
// The temporary security credentials created by GetFederationToken can be used
// to make API calls to any AWS service with the following exceptions:
//
// * You cannot use these credentials to call any IAM API operations.
//
// * You cannot call any STS API operations except GetCallerIdentity.
// //
// Permissions // Permissions
// //
// You can use the temporary credentials created by GetFederationToken in any
// AWS service except the following:
//
// * You cannot call any IAM operations using the AWS CLI or the AWS API.
//
// * You cannot call any STS operations except GetCallerIdentity.
//
// You must pass an inline or managed session policy (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // You must pass an inline or managed session policy (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
// to this operation. You can pass a single JSON policy document to use as an // to this operation. You can pass a single JSON policy document to use as an
// inline session policy. You can also specify up to 10 managed policies to // inline session policy. You can also specify up to 10 managed policies to
// use as managed session policies. The plain text that you use for both inline // use as managed session policies. The plain text that you use for both inline
// and managed session policies shouldn't exceed 2048 characters. // and managed session policies can't exceed 2,048 characters.
// //
// Though the session policy parameters are optional, if you do not pass a policy, // Though the session policy parameters are optional, if you do not pass a policy,
// then the resulting federated user session has no permissions. The only exception // then the resulting federated user session has no permissions. When you pass
// is when the credentials are used to access a resource that has a resource-based // session policies, the session permissions are the intersection of the IAM
// policy that specifically references the federated user session in the Principal // user policies and the session policies that you pass. This gives you a way
// element of the policy. When you pass session policies, the session permissions // to further restrict the permissions for a federated user. You cannot use
// are the intersection of the IAM user policies and the session policies that // session policies to grant more permissions than those that are defined in
// you pass. This gives you a way to further restrict the permissions for a // the permissions policy of the IAM user. For more information, see Session
// federated user. You cannot use session policies to grant more permissions // Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
// than those that are defined in the permissions policy of the IAM user. For
// more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
// in the IAM User Guide. For information about using GetFederationToken to // in the IAM User Guide. For information about using GetFederationToken to
// create temporary security credentials, see GetFederationToken—Federation // create temporary security credentials, see GetFederationToken—Federation
// Through a Custom Identity Broker (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_getfederationtoken). // Through a Custom Identity Broker (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_getfederationtoken).
// //
// You can use the credentials to access a resource that has a resource-based
// policy. If that policy specifically references the federated user session
// in the Principal element of the policy, the session has the permissions allowed
// by the policy. These permissions are granted in addition to the permissions
// granted by the session policies.
//
// Tags
//
// (Optional) You can pass tag key-value pairs to your session. These are called
// session tags. For more information about session tags, see Passing Session
// Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
// in the IAM User Guide.
//
// An administrator must grant you the permissions necessary to pass session
// tags. The administrator can also create granular permissions to allow you
// to pass only specific session tags. For more information, see Tutorial: Using
// Tags for Attribute-Based Access Control (https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)
// in the IAM User Guide.
//
// Tag keyvalue pairs are not case sensitive, but case is preserved. This
// means that you cannot have separate Department and department tag keys. Assume
// that the user that you are federating has the Department=Marketing tag and
// you pass the department=engineering session tag. Department and department
// are not saved as separate tags, and the session tag passed in the request
// takes precedence over the user tag.
//
// Returns awserr.Error for service API and SDK errors. Use runtime type assertions // Returns awserr.Error for service API and SDK errors. Use runtime type assertions
// with awserr.Error's Code and Message methods to get detailed information about // with awserr.Error's Code and Message methods to get detailed information about
// the error. // the error.
@ -1000,9 +1158,18 @@ func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *re
// message describes the specific error. // message describes the specific error.
// //
// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge" // * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge"
// The request was rejected because the policy document was too large. The error // The request was rejected because the total packed size of the session policies
// message describes how big the policy document is, in packed form, as a percentage // and session tags combined was too large. An AWS conversion compresses the
// of what the API allows. // session policy document, session policy ARNs, and session tags into a packed
// binary format that has a separate limit. The error message indicates by percentage
// how close the policies and tags are to the upper size limit. For more information,
// see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
// in the IAM User Guide.
//
// You could receive this error even though you meet other defined session policy
// and session tag limits. For more information, see IAM and STS Entity Character
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
// in the IAM User Guide.
// //
// * ErrCodeRegionDisabledException "RegionDisabledException" // * ErrCodeRegionDisabledException "RegionDisabledException"
// STS is not activated in the requested region for the account that is being // STS is not activated in the requested region for the account that is being
@ -1091,6 +1258,8 @@ func (c *STS) GetSessionTokenRequest(input *GetSessionTokenInput) (req *request.
// and Comparing the AWS STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) // and Comparing the AWS STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison)
// in the IAM User Guide. // in the IAM User Guide.
// //
// Session Duration
//
// The GetSessionToken operation must be called by using the long-term AWS security // The GetSessionToken operation must be called by using the long-term AWS security
// credentials of the AWS account root user or an IAM user. Credentials that // credentials of the AWS account root user or an IAM user. Credentials that
// are created by IAM users are valid for the duration that you specify. This // are created by IAM users are valid for the duration that you specify. This
@ -1099,6 +1268,8 @@ func (c *STS) GetSessionTokenRequest(input *GetSessionTokenInput) (req *request.
// based on account credentials can range from 900 seconds (15 minutes) up to // based on account credentials can range from 900 seconds (15 minutes) up to
// 3,600 seconds (1 hour), with a default of 1 hour. // 3,600 seconds (1 hour), with a default of 1 hour.
// //
// Permissions
//
// The temporary security credentials created by GetSessionToken can be used // The temporary security credentials created by GetSessionToken can be used
// to make API calls to any AWS service with the following exceptions: // to make API calls to any AWS service with the following exceptions:
// //
@ -1213,16 +1384,16 @@ type AssumeRoleInput struct {
// in the IAM User Guide. // in the IAM User Guide.
// //
// The plain text that you use for both inline and managed session policies // The plain text that you use for both inline and managed session policies
// shouldn't exceed 2048 characters. The JSON policy characters can be any ASCII // can't exceed 2,048 characters. The JSON policy characters can be any ASCII
// character from the space character to the end of the valid character list // character from the space character to the end of the valid character list
// (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A), // (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A),
// and carriage return (\u000D) characters. // and carriage return (\u000D) characters.
// //
// The characters in this parameter count towards the 2048 character session // An AWS conversion compresses the passed session policies and session tags
// policy guideline. However, an AWS conversion compresses the session policies // into a packed binary format that has a separate limit. Your request can fail
// into a packed binary format that has a separate limit. This is the enforced // for this limit even if your plain text meets the other requirements. The
// limit. The PackedPolicySize response element indicates by percentage how // PackedPolicySize response element indicates by percentage how close the policies
// close the policy is to the upper size limit. // and tags for your request are to the upper size limit.
Policy *string `min:"1" type:"string"` Policy *string `min:"1" type:"string"`
// The Amazon Resource Names (ARNs) of the IAM managed policies that you want // The Amazon Resource Names (ARNs) of the IAM managed policies that you want
@ -1231,15 +1402,15 @@ type AssumeRoleInput struct {
// //
// This parameter is optional. You can provide up to 10 managed policy ARNs. // This parameter is optional. You can provide up to 10 managed policy ARNs.
// However, the plain text that you use for both inline and managed session // However, the plain text that you use for both inline and managed session
// policies shouldn't exceed 2048 characters. For more information about ARNs, // policies can't exceed 2,048 characters. For more information about ARNs,
// see Amazon Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) // see Amazon Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)
// in the AWS General Reference. // in the AWS General Reference.
// //
// The characters in this parameter count towards the 2048 character session // An AWS conversion compresses the passed session policies and session tags
// policy guideline. However, an AWS conversion compresses the session policies // into a packed binary format that has a separate limit. Your request can fail
// into a packed binary format that has a separate limit. This is the enforced // for this limit even if your plain text meets the other requirements. The
// limit. The PackedPolicySize response element indicates by percentage how // PackedPolicySize response element indicates by percentage how close the policies
// close the policy is to the upper size limit. // and tags for your request are to the upper size limit.
// //
// Passing policies to this operation returns new temporary credentials. The // Passing policies to this operation returns new temporary credentials. The
// resulting session's permissions are the intersection of the role's identity-based // resulting session's permissions are the intersection of the role's identity-based
@ -1284,6 +1455,41 @@ type AssumeRoleInput struct {
// also include underscores or any of the following characters: =,.@- // also include underscores or any of the following characters: =,.@-
SerialNumber *string `min:"9" type:"string"` SerialNumber *string `min:"9" type:"string"`
// A list of session tags that you want to pass. Each session tag consists of
// a key name and an associated value. For more information about session tags,
// see Tagging AWS STS Sessions (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
// in the IAM User Guide.
//
// This parameter is optional. You can pass up to 50 session tags. The plain
// text session tag keys cant exceed 128 characters, and the values cant
// exceed 256 characters. For these and additional limits, see IAM and STS Character
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length)
// in the IAM User Guide.
//
// An AWS conversion compresses the passed session policies and session tags
// into a packed binary format that has a separate limit. Your request can fail
// for this limit even if your plain text meets the other requirements. The
// PackedPolicySize response element indicates by percentage how close the policies
// and tags for your request are to the upper size limit.
//
// You can pass a session tag with the same key as a tag that is already attached
// to the role. When you do, session tags override a role tag with the same
// key.
//
// Tag keyvalue pairs are not case sensitive, but case is preserved. This
// means that you cannot have separate Department and department tag keys. Assume
// that the role has the Department=Marketing tag and you pass the department=engineering
// session tag. Department and department are not saved as separate tags, and
// the session tag passed in the request takes precedence over the role tag.
//
// Additionally, if you used temporary credentials to perform this operation,
// the new session inherits any transitive session tags from the calling session.
// If you pass a session tag with the same key as an inherited tag, the operation
// fails. To view the inherited tags for a session, see the AWS CloudTrail logs.
// For more information, see Viewing Session Tags in CloudTrail (https://docs.aws.amazon.com/IAM/latest/UserGuide/session-tags.html#id_session-tags_ctlogs)
// in the IAM User Guide.
Tags []*Tag `type:"list"`
// The value provided by the MFA device, if the trust policy of the role being // The value provided by the MFA device, if the trust policy of the role being
// assumed requires MFA (that is, if the policy includes a condition that tests // assumed requires MFA (that is, if the policy includes a condition that tests
// for MFA). If the role being assumed requires MFA and if the TokenCode value // for MFA). If the role being assumed requires MFA and if the TokenCode value
@ -1292,6 +1498,19 @@ type AssumeRoleInput struct {
// The format for this parameter, as described by its regex pattern, is a sequence // The format for this parameter, as described by its regex pattern, is a sequence
// of six numeric digits. // of six numeric digits.
TokenCode *string `min:"6" type:"string"` TokenCode *string `min:"6" type:"string"`
// A list of keys for session tags that you want to set as transitive. If you
// set a tag key as transitive, the corresponding key and value passes to subsequent
// sessions in a role chain. For more information, see Chaining Roles with Session
// Tags (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining)
// in the IAM User Guide.
//
// This parameter is optional. When you set session tags as transitive, the
// session policy and session tags packed binary limit is not affected.
//
// If you choose not to specify a transitive tag key, then no tags are passed
// from this session to any subsequent sessions.
TransitiveTagKeys []*string `type:"list"`
} }
// String returns the string representation // String returns the string representation
@ -1344,6 +1563,16 @@ func (s *AssumeRoleInput) Validate() error {
} }
} }
} }
if s.Tags != nil {
for i, v := range s.Tags {
if v == nil {
continue
}
if err := v.Validate(); err != nil {
invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Tags", i), err.(request.ErrInvalidParams))
}
}
}
if invalidParams.Len() > 0 { if invalidParams.Len() > 0 {
return invalidParams return invalidParams
@ -1393,12 +1622,24 @@ func (s *AssumeRoleInput) SetSerialNumber(v string) *AssumeRoleInput {
return s return s
} }
// SetTags sets the Tags field's value.
func (s *AssumeRoleInput) SetTags(v []*Tag) *AssumeRoleInput {
s.Tags = v
return s
}
// SetTokenCode sets the TokenCode field's value. // SetTokenCode sets the TokenCode field's value.
func (s *AssumeRoleInput) SetTokenCode(v string) *AssumeRoleInput { func (s *AssumeRoleInput) SetTokenCode(v string) *AssumeRoleInput {
s.TokenCode = &v s.TokenCode = &v
return s return s
} }
// SetTransitiveTagKeys sets the TransitiveTagKeys field's value.
func (s *AssumeRoleInput) SetTransitiveTagKeys(v []*string) *AssumeRoleInput {
s.TransitiveTagKeys = v
return s
}
// Contains the response to a successful AssumeRole request, including temporary // Contains the response to a successful AssumeRole request, including temporary
// AWS credentials that can be used to make AWS requests. // AWS credentials that can be used to make AWS requests.
type AssumeRoleOutput struct { type AssumeRoleOutput struct {
@ -1418,9 +1659,10 @@ type AssumeRoleOutput struct {
// We strongly recommend that you make no assumptions about the maximum size. // We strongly recommend that you make no assumptions about the maximum size.
Credentials *Credentials `type:"structure"` Credentials *Credentials `type:"structure"`
// A percentage value that indicates the size of the policy in packed form. // A percentage value that indicates the packed size of the session policies
// The service rejects any policy with a packed size greater than 100 percent, // and session tags combined passed in the request. The request fails if the
// which means the policy exceeded the allowed space. // packed size is greater than 100 percent, which means the policies and tags
// exceeded the allowed space.
PackedPolicySize *int64 `type:"integer"` PackedPolicySize *int64 `type:"integer"`
} }
@ -1491,16 +1733,16 @@ type AssumeRoleWithSAMLInput struct {
// in the IAM User Guide. // in the IAM User Guide.
// //
// The plain text that you use for both inline and managed session policies // The plain text that you use for both inline and managed session policies
// shouldn't exceed 2048 characters. The JSON policy characters can be any ASCII // can't exceed 2,048 characters. The JSON policy characters can be any ASCII
// character from the space character to the end of the valid character list // character from the space character to the end of the valid character list
// (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A), // (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A),
// and carriage return (\u000D) characters. // and carriage return (\u000D) characters.
// //
// The characters in this parameter count towards the 2048 character session // An AWS conversion compresses the passed session policies and session tags
// policy guideline. However, an AWS conversion compresses the session policies // into a packed binary format that has a separate limit. Your request can fail
// into a packed binary format that has a separate limit. This is the enforced // for this limit even if your plain text meets the other requirements. The
// limit. The PackedPolicySize response element indicates by percentage how // PackedPolicySize response element indicates by percentage how close the policies
// close the policy is to the upper size limit. // and tags for your request are to the upper size limit.
Policy *string `min:"1" type:"string"` Policy *string `min:"1" type:"string"`
// The Amazon Resource Names (ARNs) of the IAM managed policies that you want // The Amazon Resource Names (ARNs) of the IAM managed policies that you want
@ -1509,15 +1751,15 @@ type AssumeRoleWithSAMLInput struct {
// //
// This parameter is optional. You can provide up to 10 managed policy ARNs. // This parameter is optional. You can provide up to 10 managed policy ARNs.
// However, the plain text that you use for both inline and managed session // However, the plain text that you use for both inline and managed session
// policies shouldn't exceed 2048 characters. For more information about ARNs, // policies can't exceed 2,048 characters. For more information about ARNs,
// see Amazon Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) // see Amazon Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)
// in the AWS General Reference. // in the AWS General Reference.
// //
// The characters in this parameter count towards the 2048 character session // An AWS conversion compresses the passed session policies and session tags
// policy guideline. However, an AWS conversion compresses the session policies // into a packed binary format that has a separate limit. Your request can fail
// into a packed binary format that has a separate limit. This is the enforced // for this limit even if your plain text meets the other requirements. The
// limit. The PackedPolicySize response element indicates by percentage how // PackedPolicySize response element indicates by percentage how close the policies
// close the policy is to the upper size limit. // and tags for your request are to the upper size limit.
// //
// Passing policies to this operation returns new temporary credentials. The // Passing policies to this operation returns new temporary credentials. The
// resulting session's permissions are the intersection of the role's identity-based // resulting session's permissions are the intersection of the role's identity-based
@ -1673,9 +1915,10 @@ type AssumeRoleWithSAMLOutput struct {
// ) ) // ) )
NameQualifier *string `type:"string"` NameQualifier *string `type:"string"`
// A percentage value that indicates the size of the policy in packed form. // A percentage value that indicates the packed size of the session policies
// The service rejects any policy with a packed size greater than 100 percent, // and session tags combined passed in the request. The request fails if the
// which means the policy exceeded the allowed space. // packed size is greater than 100 percent, which means the policies and tags
// exceeded the allowed space.
PackedPolicySize *int64 `type:"integer"` PackedPolicySize *int64 `type:"integer"`
// The value of the NameID element in the Subject element of the SAML assertion. // The value of the NameID element in the Subject element of the SAML assertion.
@ -1786,16 +2029,16 @@ type AssumeRoleWithWebIdentityInput struct {
// in the IAM User Guide. // in the IAM User Guide.
// //
// The plain text that you use for both inline and managed session policies // The plain text that you use for both inline and managed session policies
// shouldn't exceed 2048 characters. The JSON policy characters can be any ASCII // can't exceed 2,048 characters. The JSON policy characters can be any ASCII
// character from the space character to the end of the valid character list // character from the space character to the end of the valid character list
// (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A), // (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A),
// and carriage return (\u000D) characters. // and carriage return (\u000D) characters.
// //
// The characters in this parameter count towards the 2048 character session // An AWS conversion compresses the passed session policies and session tags
// policy guideline. However, an AWS conversion compresses the session policies // into a packed binary format that has a separate limit. Your request can fail
// into a packed binary format that has a separate limit. This is the enforced // for this limit even if your plain text meets the other requirements. The
// limit. The PackedPolicySize response element indicates by percentage how // PackedPolicySize response element indicates by percentage how close the policies
// close the policy is to the upper size limit. // and tags for your request are to the upper size limit.
Policy *string `min:"1" type:"string"` Policy *string `min:"1" type:"string"`
// The Amazon Resource Names (ARNs) of the IAM managed policies that you want // The Amazon Resource Names (ARNs) of the IAM managed policies that you want
@ -1804,15 +2047,15 @@ type AssumeRoleWithWebIdentityInput struct {
// //
// This parameter is optional. You can provide up to 10 managed policy ARNs. // This parameter is optional. You can provide up to 10 managed policy ARNs.
// However, the plain text that you use for both inline and managed session // However, the plain text that you use for both inline and managed session
// policies shouldn't exceed 2048 characters. For more information about ARNs, // policies can't exceed 2,048 characters. For more information about ARNs,
// see Amazon Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) // see Amazon Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)
// in the AWS General Reference. // in the AWS General Reference.
// //
// The characters in this parameter count towards the 2048 character session // An AWS conversion compresses the passed session policies and session tags
// policy guideline. However, an AWS conversion compresses the session policies // into a packed binary format that has a separate limit. Your request can fail
// into a packed binary format that has a separate limit. This is the enforced // for this limit even if your plain text meets the other requirements. The
// limit. The PackedPolicySize response element indicates by percentage how // PackedPolicySize response element indicates by percentage how close the policies
// close the policy is to the upper size limit. // and tags for your request are to the upper size limit.
// //
// Passing policies to this operation returns new temporary credentials. The // Passing policies to this operation returns new temporary credentials. The
// resulting session's permissions are the intersection of the role's identity-based // resulting session's permissions are the intersection of the role's identity-based
@ -1983,9 +2226,10 @@ type AssumeRoleWithWebIdentityOutput struct {
// We strongly recommend that you make no assumptions about the maximum size. // We strongly recommend that you make no assumptions about the maximum size.
Credentials *Credentials `type:"structure"` Credentials *Credentials `type:"structure"`
// A percentage value that indicates the size of the policy in packed form. // A percentage value that indicates the packed size of the session policies
// The service rejects any policy with a packed size greater than 100 percent, // and session tags combined passed in the request. The request fails if the
// which means the policy exceeded the allowed space. // packed size is greater than 100 percent, which means the policies and tags
// exceeded the allowed space.
PackedPolicySize *int64 `type:"integer"` PackedPolicySize *int64 `type:"integer"`
// The issuing authority of the web identity token presented. For OpenID Connect // The issuing authority of the web identity token presented. For OpenID Connect
@ -2057,7 +2301,7 @@ type AssumedRoleUser struct {
// The ARN of the temporary security credentials that are returned from the // The ARN of the temporary security credentials that are returned from the
// AssumeRole action. For more information about ARNs and how to use them in // AssumeRole action. For more information about ARNs and how to use them in
// policies, see IAM Identifiers (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html) // policies, see IAM Identifiers (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html)
// in Using IAM. // in the IAM User Guide.
// //
// Arn is a required field // Arn is a required field
Arn *string `min:"20" type:"string" required:"true"` Arn *string `min:"20" type:"string" required:"true"`
@ -2225,7 +2469,7 @@ type FederatedUser struct {
// The ARN that specifies the federated user that is associated with the credentials. // The ARN that specifies the federated user that is associated with the credentials.
// For more information about ARNs and how to use them in policies, see IAM // For more information about ARNs and how to use them in policies, see IAM
// Identifiers (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html) // Identifiers (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html)
// in Using IAM. // in the IAM User Guide.
// //
// Arn is a required field // Arn is a required field
Arn *string `min:"20" type:"string" required:"true"` Arn *string `min:"20" type:"string" required:"true"`
@ -2265,7 +2509,7 @@ type GetAccessKeyInfoInput struct {
// The identifier of an access key. // The identifier of an access key.
// //
// This parameter allows (through its regex pattern) a string of characters // This parameter allows (through its regex pattern) a string of characters
// that can consist of any upper- or lowercased letter or digit. // that can consist of any upper- or lowercase letter or digit.
// //
// AccessKeyId is a required field // AccessKeyId is a required field
AccessKeyId *string `min:"16" type:"string" required:"true"` AccessKeyId *string `min:"16" type:"string" required:"true"`
@ -2418,10 +2662,7 @@ type GetFederationTokenInput struct {
// use as managed session policies. // use as managed session policies.
// //
// This parameter is optional. However, if you do not pass any session policies, // This parameter is optional. However, if you do not pass any session policies,
// then the resulting federated user session has no permissions. The only exception // then the resulting federated user session has no permissions.
// is when the credentials are used to access a resource that has a resource-based
// policy that specifically references the federated user session in the Principal
// element of the policy.
// //
// When you pass session policies, the session permissions are the intersection // When you pass session policies, the session permissions are the intersection
// of the IAM user policies and the session policies that you pass. This gives // of the IAM user policies and the session policies that you pass. This gives
@ -2431,17 +2672,23 @@ type GetFederationTokenInput struct {
// Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
// in the IAM User Guide. // in the IAM User Guide.
// //
// The resulting credentials can be used to access a resource that has a resource-based
// policy. If that policy specifically references the federated user session
// in the Principal element of the policy, the session has the permissions allowed
// by the policy. These permissions are granted in addition to the permissions
// that are granted by the session policies.
//
// The plain text that you use for both inline and managed session policies // The plain text that you use for both inline and managed session policies
// shouldn't exceed 2048 characters. The JSON policy characters can be any ASCII // can't exceed 2,048 characters. The JSON policy characters can be any ASCII
// character from the space character to the end of the valid character list // character from the space character to the end of the valid character list
// (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A), // (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A),
// and carriage return (\u000D) characters. // and carriage return (\u000D) characters.
// //
// The characters in this parameter count towards the 2048 character session // An AWS conversion compresses the passed session policies and session tags
// policy guideline. However, an AWS conversion compresses the session policies // into a packed binary format that has a separate limit. Your request can fail
// into a packed binary format that has a separate limit. This is the enforced // for this limit even if your plain text meets the other requirements. The
// limit. The PackedPolicySize response element indicates by percentage how // PackedPolicySize response element indicates by percentage how close the policies
// close the policy is to the upper size limit. // and tags for your request are to the upper size limit.
Policy *string `min:"1" type:"string"` Policy *string `min:"1" type:"string"`
// The Amazon Resource Names (ARNs) of the IAM managed policies that you want // The Amazon Resource Names (ARNs) of the IAM managed policies that you want
@ -2452,16 +2699,13 @@ type GetFederationTokenInput struct {
// to this operation. You can pass a single JSON policy document to use as an // to this operation. You can pass a single JSON policy document to use as an
// inline session policy. You can also specify up to 10 managed policies to // inline session policy. You can also specify up to 10 managed policies to
// use as managed session policies. The plain text that you use for both inline // use as managed session policies. The plain text that you use for both inline
// and managed session policies shouldn't exceed 2048 characters. You can provide // and managed session policies can't exceed 2,048 characters. You can provide
// up to 10 managed policy ARNs. For more information about ARNs, see Amazon // up to 10 managed policy ARNs. For more information about ARNs, see Amazon
// Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) // Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)
// in the AWS General Reference. // in the AWS General Reference.
// //
// This parameter is optional. However, if you do not pass any session policies, // This parameter is optional. However, if you do not pass any session policies,
// then the resulting federated user session has no permissions. The only exception // then the resulting federated user session has no permissions.
// is when the credentials are used to access a resource that has a resource-based
// policy that specifically references the federated user session in the Principal
// element of the policy.
// //
// When you pass session policies, the session permissions are the intersection // When you pass session policies, the session permissions are the intersection
// of the IAM user policies and the session policies that you pass. This gives // of the IAM user policies and the session policies that you pass. This gives
@ -2471,12 +2715,46 @@ type GetFederationTokenInput struct {
// Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
// in the IAM User Guide. // in the IAM User Guide.
// //
// The characters in this parameter count towards the 2048 character session // The resulting credentials can be used to access a resource that has a resource-based
// policy guideline. However, an AWS conversion compresses the session policies // policy. If that policy specifically references the federated user session
// into a packed binary format that has a separate limit. This is the enforced // in the Principal element of the policy, the session has the permissions allowed
// limit. The PackedPolicySize response element indicates by percentage how // by the policy. These permissions are granted in addition to the permissions
// close the policy is to the upper size limit. // that are granted by the session policies.
//
// An AWS conversion compresses the passed session policies and session tags
// into a packed binary format that has a separate limit. Your request can fail
// for this limit even if your plain text meets the other requirements. The
// PackedPolicySize response element indicates by percentage how close the policies
// and tags for your request are to the upper size limit.
PolicyArns []*PolicyDescriptorType `type:"list"` PolicyArns []*PolicyDescriptorType `type:"list"`
// A list of session tags. Each session tag consists of a key name and an associated
// value. For more information about session tags, see Passing Session Tags
// in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
// in the IAM User Guide.
//
// This parameter is optional. You can pass up to 50 session tags. The plain
// text session tag keys cant exceed 128 characters and the values cant
// exceed 256 characters. For these and additional limits, see IAM and STS Character
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length)
// in the IAM User Guide.
//
// An AWS conversion compresses the passed session policies and session tags
// into a packed binary format that has a separate limit. Your request can fail
// for this limit even if your plain text meets the other requirements. The
// PackedPolicySize response element indicates by percentage how close the policies
// and tags for your request are to the upper size limit.
//
// You can pass a session tag with the same key as a tag that is already attached
// to the user you are federating. When you do, session tags override a user
// tag with the same key.
//
// Tag keyvalue pairs are not case sensitive, but case is preserved. This
// means that you cannot have separate Department and department tag keys. Assume
// that the role has the Department=Marketing tag and you pass the department=engineering
// session tag. Department and department are not saved as separate tags, and
// the session tag passed in the request takes precedence over the role tag.
Tags []*Tag `type:"list"`
} }
// String returns the string representation // String returns the string representation
@ -2514,6 +2792,16 @@ func (s *GetFederationTokenInput) Validate() error {
} }
} }
} }
if s.Tags != nil {
for i, v := range s.Tags {
if v == nil {
continue
}
if err := v.Validate(); err != nil {
invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Tags", i), err.(request.ErrInvalidParams))
}
}
}
if invalidParams.Len() > 0 { if invalidParams.Len() > 0 {
return invalidParams return invalidParams
@ -2545,6 +2833,12 @@ func (s *GetFederationTokenInput) SetPolicyArns(v []*PolicyDescriptorType) *GetF
return s return s
} }
// SetTags sets the Tags field's value.
func (s *GetFederationTokenInput) SetTags(v []*Tag) *GetFederationTokenInput {
s.Tags = v
return s
}
// Contains the response to a successful GetFederationToken request, including // Contains the response to a successful GetFederationToken request, including
// temporary AWS credentials that can be used to make AWS requests. // temporary AWS credentials that can be used to make AWS requests.
type GetFederationTokenOutput struct { type GetFederationTokenOutput struct {
@ -2563,9 +2857,10 @@ type GetFederationTokenOutput struct {
// an Amazon S3 bucket policy. // an Amazon S3 bucket policy.
FederatedUser *FederatedUser `type:"structure"` FederatedUser *FederatedUser `type:"structure"`
// A percentage value indicating the size of the policy in packed form. The // A percentage value that indicates the packed size of the session policies
// service rejects policies for which the packed size is greater than 100 percent // and session tags combined passed in the request. The request fails if the
// of the allowed value. // packed size is greater than 100 percent, which means the policies and tags
// exceeded the allowed space.
PackedPolicySize *int64 `type:"integer"` PackedPolicySize *int64 `type:"integer"`
} }
@ -2748,3 +3043,73 @@ func (s *PolicyDescriptorType) SetArn(v string) *PolicyDescriptorType {
s.Arn = &v s.Arn = &v
return s return s
} }
// You can pass custom key-value pair attributes when you assume a role or federate
// a user. These are called session tags. You can then use the session tags
// to control access to resources. For more information, see Tagging AWS STS
// Sessions (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
// in the IAM User Guide.
type Tag struct {
_ struct{} `type:"structure"`
// The key for a session tag.
//
// You can pass up to 50 session tags. The plain text session tag keys cant
// exceed 128 characters. For these and additional limits, see IAM and STS Character
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length)
// in the IAM User Guide.
//
// Key is a required field
Key *string `min:"1" type:"string" required:"true"`
// The value for a session tag.
//
// You can pass up to 50 session tags. The plain text session tag values cant
// exceed 256 characters. For these and additional limits, see IAM and STS Character
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length)
// in the IAM User Guide.
//
// Value is a required field
Value *string `type:"string" required:"true"`
}
// String returns the string representation
func (s Tag) String() string {
return awsutil.Prettify(s)
}
// GoString returns the string representation
func (s Tag) GoString() string {
return s.String()
}
// Validate inspects the fields of the type to determine if they are valid.
func (s *Tag) Validate() error {
invalidParams := request.ErrInvalidParams{Context: "Tag"}
if s.Key == nil {
invalidParams.Add(request.NewErrParamRequired("Key"))
}
if s.Key != nil && len(*s.Key) < 1 {
invalidParams.Add(request.NewErrParamMinLen("Key", 1))
}
if s.Value == nil {
invalidParams.Add(request.NewErrParamRequired("Value"))
}
if invalidParams.Len() > 0 {
return invalidParams
}
return nil
}
// SetKey sets the Key field's value.
func (s *Tag) SetKey(v string) *Tag {
s.Key = &v
return s
}
// SetValue sets the Value field's value.
func (s *Tag) SetValue(v string) *Tag {
s.Value = &v
return s
}

View File

@ -14,11 +14,11 @@ const (
// ErrCodeIDPCommunicationErrorException for service response error code // ErrCodeIDPCommunicationErrorException for service response error code
// "IDPCommunicationError". // "IDPCommunicationError".
// //
// The request could not be fulfilled because the non-AWS identity provider // The request could not be fulfilled because the identity provider (IDP) that
// (IDP) that was asked to verify the incoming identity token could not be reached. // was asked to verify the incoming identity token could not be reached. This
// This is often a transient error caused by network conditions. Retry the request // is often a transient error caused by network conditions. Retry the request
// a limited number of times so that you don't exceed the request rate. If the // a limited number of times so that you don't exceed the request rate. If the
// error persists, the non-AWS identity provider might be down or not responding. // error persists, the identity provider might be down or not responding.
ErrCodeIDPCommunicationErrorException = "IDPCommunicationError" ErrCodeIDPCommunicationErrorException = "IDPCommunicationError"
// ErrCodeIDPRejectedClaimException for service response error code // ErrCodeIDPRejectedClaimException for service response error code
@ -56,9 +56,18 @@ const (
// ErrCodePackedPolicyTooLargeException for service response error code // ErrCodePackedPolicyTooLargeException for service response error code
// "PackedPolicyTooLarge". // "PackedPolicyTooLarge".
// //
// The request was rejected because the policy document was too large. The error // The request was rejected because the total packed size of the session policies
// message describes how big the policy document is, in packed form, as a percentage // and session tags combined was too large. An AWS conversion compresses the
// of what the API allows. // session policy document, session policy ARNs, and session tags into a packed
// binary format that has a separate limit. The error message indicates by percentage
// how close the policies and tags are to the upper size limit. For more information,
// see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
// in the IAM User Guide.
//
// You could receive this error even though you meet other defined session policy
// and session tag limits. For more information, see IAM and STS Entity Character
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
// in the IAM User Guide.
ErrCodePackedPolicyTooLargeException = "PackedPolicyTooLarge" ErrCodePackedPolicyTooLargeException = "PackedPolicyTooLarge"
// ErrCodeRegionDisabledException for service response error code // ErrCodeRegionDisabledException for service response error code

View File

@ -31,7 +31,7 @@ var initRequest func(*request.Request)
const ( const (
ServiceName = "sts" // Name of service. ServiceName = "sts" // Name of service.
EndpointsID = ServiceName // ID to lookup a service endpoint with. EndpointsID = ServiceName // ID to lookup a service endpoint with.
ServiceID = "STS" // ServiceID is a unique identifer of a specific service. ServiceID = "STS" // ServiceID is a unique identifier of a specific service.
) )
// New creates a new instance of the STS client with a session. // New creates a new instance of the STS client with a session.
@ -39,6 +39,8 @@ const (
// aws.Config parameter to add your extra config. // aws.Config parameter to add your extra config.
// //
// Example: // Example:
// mySession := session.Must(session.NewSession())
//
// // Create a STS client from just a session. // // Create a STS client from just a session.
// svc := sts.New(mySession) // svc := sts.New(mySession)
// //
@ -46,11 +48,11 @@ const (
// svc := sts.New(mySession, aws.NewConfig().WithRegion("us-west-2")) // svc := sts.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
func New(p client.ConfigProvider, cfgs ...*aws.Config) *STS { func New(p client.ConfigProvider, cfgs ...*aws.Config) *STS {
c := p.ClientConfig(EndpointsID, cfgs...) c := p.ClientConfig(EndpointsID, cfgs...)
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) return newClient(*c.Config, c.Handlers, c.PartitionID, c.Endpoint, c.SigningRegion, c.SigningName)
} }
// newClient creates, initializes and returns a new service client instance. // newClient creates, initializes and returns a new service client instance.
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *STS { func newClient(cfg aws.Config, handlers request.Handlers, partitionID, endpoint, signingRegion, signingName string) *STS {
svc := &STS{ svc := &STS{
Client: client.New( Client: client.New(
cfg, cfg,
@ -59,6 +61,7 @@ func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
ServiceID: ServiceID, ServiceID: ServiceID,
SigningName: signingName, SigningName: signingName,
SigningRegion: signingRegion, SigningRegion: signingRegion,
PartitionID: partitionID,
Endpoint: endpoint, Endpoint: endpoint,
APIVersion: "2011-06-15", APIVersion: "2011-06-15",
}, },

View File

@ -3,7 +3,15 @@ language: go
sudo: false sudo: false
go: go:
- 1.4 - 1.5.x
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
- 1.10.x
- 1.11.x
- 1.12.x
- 1.13.x
install: go get -v -t ./... install: go get -v -t ./...
script: make test script: make test

View File

@ -4,4 +4,84 @@
See http://jmespath.org for more info. go-jmespath is a GO implementation of JMESPath,
which is a query language for JSON. It will take a JSON
document and transform it into another JSON document
through a JMESPath expression.
Using go-jmespath is really easy. There's a single function
you use, `jmespath.search`:
```go
> import "github.com/jmespath/go-jmespath"
>
> var jsondata = []byte(`{"foo": {"bar": {"baz": [0, 1, 2, 3, 4]}}}`) // your data
> var data interface{}
> err := json.Unmarshal(jsondata, &data)
> result, err := jmespath.Search("foo.bar.baz[2]", data)
result = 2
```
In the example we gave the ``search`` function input data of
`{"foo": {"bar": {"baz": [0, 1, 2, 3, 4]}}}` as well as the JMESPath
expression `foo.bar.baz[2]`, and the `search` function evaluated
the expression against the input data to produce the result ``2``.
The JMESPath language can do a lot more than select an element
from a list. Here are a few more examples:
```go
> var jsondata = []byte(`{"foo": {"bar": {"baz": [0, 1, 2, 3, 4]}}}`) // your data
> var data interface{}
> err := json.Unmarshal(jsondata, &data)
> result, err := jmespath.search("foo.bar", data)
result = { "baz": [ 0, 1, 2, 3, 4 ] }
> var jsondata = []byte(`{"foo": [{"first": "a", "last": "b"},
{"first": "c", "last": "d"}]}`) // your data
> var data interface{}
> err := json.Unmarshal(jsondata, &data)
> result, err := jmespath.search({"foo[*].first", data)
result [ 'a', 'c' ]
> var jsondata = []byte(`{"foo": [{"age": 20}, {"age": 25},
{"age": 30}, {"age": 35},
{"age": 40}]}`) // your data
> var data interface{}
> err := json.Unmarshal(jsondata, &data)
> result, err := jmespath.search("foo[?age > `30`]")
result = [ { age: 35 }, { age: 40 } ]
```
You can also pre-compile your query. This is usefull if
you are going to run multiple searches with it:
```go
> var jsondata = []byte(`{"foo": "bar"}`)
> var data interface{}
> err := json.Unmarshal(jsondata, &data)
> precompiled, err := Compile("foo")
> if err != nil{
> // ... handle the error
> }
> result, err := precompiled.Search(data)
result = "bar"
```
## More Resources
The example above only show a small amount of what
a JMESPath expression can do. If you want to take a
tour of the language, the *best* place to go is the
[JMESPath Tutorial](http://jmespath.org/tutorial.html).
One of the best things about JMESPath is that it is
implemented in many different programming languages including
python, ruby, php, lua, etc. To see a complete list of libraries,
check out the [JMESPath libraries page](http://jmespath.org/libraries.html).
And finally, the full JMESPath specification can be found
on the [JMESPath site](http://jmespath.org/specification.html).

View File

@ -2,7 +2,7 @@ package jmespath
import "strconv" import "strconv"
// JMESPath is the epresentation of a compiled JMES path query. A JMESPath is // JMESPath is the representation of a compiled JMES path query. A JMESPath is
// safe for concurrent use by multiple goroutines. // safe for concurrent use by multiple goroutines.
type JMESPath struct { type JMESPath struct {
ast ASTNode ast ASTNode

5
vendor/github.com/jmespath/go-jmespath/go.mod generated vendored Normal file
View File

@ -0,0 +1,5 @@
module github.com/jmespath/go-jmespath
go 1.14
require github.com/stretchr/testify v1.5.1

11
vendor/github.com/jmespath/go-jmespath/go.sum generated vendored Normal file
View File

@ -0,0 +1,11 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -137,7 +137,7 @@ func (p *Parser) Parse(expression string) (ASTNode, error) {
} }
if p.current() != tEOF { if p.current() != tEOF {
return ASTNode{}, p.syntaxError(fmt.Sprintf( return ASTNode{}, p.syntaxError(fmt.Sprintf(
"Unexpected token at the end of the expresssion: %s", p.current())) "Unexpected token at the end of the expression: %s", p.current()))
} }
return parsed, nil return parsed, nil
} }

View File

@ -1,11 +1,10 @@
language: go language: go
go_import_path: github.com/pkg/errors go_import_path: github.com/pkg/errors
go: go:
- 1.4.3 - 1.11.x
- 1.5.4 - 1.12.x
- 1.6.2 - 1.13.x
- 1.7.1
- tip - tip
script: script:
- go test -v ./... - make check

44
vendor/github.com/pkg/errors/Makefile generated vendored Normal file
View File

@ -0,0 +1,44 @@
PKGS := github.com/pkg/errors
SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS))
GO := go
check: test vet gofmt misspell unconvert staticcheck ineffassign unparam
test:
$(GO) test $(PKGS)
vet: | test
$(GO) vet $(PKGS)
staticcheck:
$(GO) get honnef.co/go/tools/cmd/staticcheck
staticcheck -checks all $(PKGS)
misspell:
$(GO) get github.com/client9/misspell/cmd/misspell
misspell \
-locale GB \
-error \
*.md *.go
unconvert:
$(GO) get github.com/mdempsky/unconvert
unconvert -v $(PKGS)
ineffassign:
$(GO) get github.com/gordonklaus/ineffassign
find $(SRCDIRS) -name '*.go' | xargs ineffassign
pedantic: check errcheck
unparam:
$(GO) get mvdan.cc/unparam
unparam ./...
errcheck:
$(GO) get github.com/kisielk/errcheck
errcheck $(PKGS)
gofmt:
@echo Checking code is gofmted
@test -z "$(shell gofmt -s -l -d -e $(SRCDIRS) | tee /dev/stderr)"

Some files were not shown because too many files have changed in this diff Show More