Update Go AWS SDK to the latest version

This commit is contained in:
Andrey Smirnov
2019-07-13 00:03:55 +03:00
committed by Andrey Smirnov
parent d08be990ef
commit 94a72b23ff
2183 changed files with 885887 additions and 228114 deletions
+2 -1
View File
@@ -21,7 +21,8 @@ func Build(r *request.Request) {
"Version": {r.ClientInfo.APIVersion},
}
if err := queryutil.Parse(body, r.Params, true); err != nil {
r.Error = awserr.New("SerializationError", "failed encoding EC2 Query request", err)
r.Error = awserr.New(request.ErrCodeSerialization,
"failed encoding EC2 Query request", err)
}
if !r.IsPresigned() {
@@ -49,7 +49,7 @@ func BenchmarkEC2QueryBuild_Complex_ec2AuthorizeSecurityGroupEgress(b *testing.B
IpProtocol: aws.String("String"),
SourceSecurityGroupName: aws.String("String"),
SourceSecurityGroupOwnerId: aws.String("String"),
ToPort: aws.Int64(1),
ToPort: aws.Int64(1),
}
benchEC2QueryBuild(b, "AuthorizeSecurityGroupEgress", params)
+432 -71
View File
@@ -75,7 +75,8 @@ func newInputService1ProtocolTestClient(cfg aws.Config, handlers request.Handler
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "inputservice1protocoltest",
ServiceName: "InputService1ProtocolTest",
ServiceID: "InputService1ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -108,7 +109,7 @@ const opInputService1TestCaseOperation1 = "OperationName"
// InputService1TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the InputService1TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -139,8 +140,7 @@ func (c *InputService1ProtocolTest) InputService1TestCaseOperation1Request(input
output = &InputService1TestShapeInputService1TestCaseOperation1Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler)
req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler)
req.Handlers.Unmarshal.Swap(ec2query.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
return
}
@@ -228,7 +228,8 @@ func newInputService2ProtocolTestClient(cfg aws.Config, handlers request.Handler
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "inputservice2protocoltest",
ServiceName: "InputService2ProtocolTest",
ServiceID: "InputService2ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -261,7 +262,7 @@ const opInputService2TestCaseOperation1 = "OperationName"
// InputService2TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the InputService2TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -292,8 +293,7 @@ func (c *InputService2ProtocolTest) InputService2TestCaseOperation1Request(input
output = &InputService2TestShapeInputService2TestCaseOperation1Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler)
req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler)
req.Handlers.Unmarshal.Swap(ec2query.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
return
}
@@ -389,7 +389,8 @@ func newInputService3ProtocolTestClient(cfg aws.Config, handlers request.Handler
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "inputservice3protocoltest",
ServiceName: "InputService3ProtocolTest",
ServiceID: "InputService3ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -422,7 +423,7 @@ const opInputService3TestCaseOperation1 = "OperationName"
// InputService3TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the InputService3TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -453,8 +454,7 @@ func (c *InputService3ProtocolTest) InputService3TestCaseOperation1Request(input
output = &InputService3TestShapeInputService3TestCaseOperation1Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler)
req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler)
req.Handlers.Unmarshal.Swap(ec2query.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
return
}
@@ -546,7 +546,8 @@ func newInputService4ProtocolTestClient(cfg aws.Config, handlers request.Handler
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "inputservice4protocoltest",
ServiceName: "InputService4ProtocolTest",
ServiceID: "InputService4ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -579,7 +580,7 @@ const opInputService4TestCaseOperation1 = "OperationName"
// InputService4TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the InputService4TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -610,8 +611,7 @@ func (c *InputService4ProtocolTest) InputService4TestCaseOperation1Request(input
output = &InputService4TestShapeInputService4TestCaseOperation1Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler)
req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler)
req.Handlers.Unmarshal.Swap(ec2query.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
return
}
@@ -715,7 +715,8 @@ func newInputService5ProtocolTestClient(cfg aws.Config, handlers request.Handler
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "inputservice5protocoltest",
ServiceName: "InputService5ProtocolTest",
ServiceID: "InputService5ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -748,7 +749,7 @@ const opInputService5TestCaseOperation1 = "OperationName"
// InputService5TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the InputService5TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -779,8 +780,7 @@ func (c *InputService5ProtocolTest) InputService5TestCaseOperation1Request(input
output = &InputService5TestShapeInputService5TestCaseOperation1Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler)
req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler)
req.Handlers.Unmarshal.Swap(ec2query.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
return
}
@@ -860,7 +860,8 @@ func newInputService6ProtocolTestClient(cfg aws.Config, handlers request.Handler
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "inputservice6protocoltest",
ServiceName: "InputService6ProtocolTest",
ServiceID: "InputService6ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -893,7 +894,7 @@ const opInputService6TestCaseOperation1 = "OperationName"
// InputService6TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the InputService6TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -924,8 +925,7 @@ func (c *InputService6ProtocolTest) InputService6TestCaseOperation1Request(input
output = &InputService6TestShapeInputService6TestCaseOperation1Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler)
req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler)
req.Handlers.Unmarshal.Swap(ec2query.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
return
}
@@ -1005,7 +1005,8 @@ func newInputService7ProtocolTestClient(cfg aws.Config, handlers request.Handler
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "inputservice7protocoltest",
ServiceName: "InputService7ProtocolTest",
ServiceID: "InputService7ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1038,7 +1039,7 @@ const opInputService7TestCaseOperation1 = "OperationName"
// InputService7TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the InputService7TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1069,8 +1070,7 @@ func (c *InputService7ProtocolTest) InputService7TestCaseOperation1Request(input
output = &InputService7TestShapeInputService7TestCaseOperation1Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler)
req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler)
req.Handlers.Unmarshal.Swap(ec2query.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
return
}
@@ -1151,7 +1151,8 @@ func newInputService8ProtocolTestClient(cfg aws.Config, handlers request.Handler
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "inputservice8protocoltest",
ServiceName: "InputService8ProtocolTest",
ServiceID: "InputService8ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1184,7 +1185,7 @@ const opInputService8TestCaseOperation1 = "OperationName"
// InputService8TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the InputService8TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1215,8 +1216,7 @@ func (c *InputService8ProtocolTest) InputService8TestCaseOperation1Request(input
output = &InputService8TestShapeInputService8TestCaseOperation1Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler)
req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler)
req.Handlers.Unmarshal.Swap(ec2query.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
return
}
@@ -1252,7 +1252,11 @@ func (c *InputService8ProtocolTest) InputService8TestCaseOperation1WithContext(c
type InputService8TestShapeInputService8TestCaseOperation1Input struct {
_ struct{} `type:"structure"`
TimeArg *time.Time `type:"timestamp" timestampFormat:"iso8601"`
TimeArg *time.Time `type:"timestamp"`
TimeCustom *time.Time `type:"timestamp" timestampFormat:"unixTimestamp"`
TimeFormat *time.Time `type:"timestamp" timestampFormat:"unixTimestamp"`
}
// SetTimeArg sets the TimeArg field's value.
@@ -1261,6 +1265,18 @@ func (s *InputService8TestShapeInputService8TestCaseOperation1Input) SetTimeArg(
return s
}
// SetTimeCustom sets the TimeCustom field's value.
func (s *InputService8TestShapeInputService8TestCaseOperation1Input) SetTimeCustom(v time.Time) *InputService8TestShapeInputService8TestCaseOperation1Input {
s.TimeCustom = &v
return s
}
// SetTimeFormat sets the TimeFormat field's value.
func (s *InputService8TestShapeInputService8TestCaseOperation1Input) SetTimeFormat(v time.Time) *InputService8TestShapeInputService8TestCaseOperation1Input {
s.TimeFormat = &v
return s
}
type InputService8TestShapeInputService8TestCaseOperation1Output struct {
_ struct{} `type:"structure"`
}
@@ -1296,7 +1312,8 @@ func newInputService9ProtocolTestClient(cfg aws.Config, handlers request.Handler
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "inputservice9protocoltest",
ServiceName: "InputService9ProtocolTest",
ServiceID: "InputService9ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1329,7 +1346,7 @@ const opInputService9TestCaseOperation1 = "OperationName"
// InputService9TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the InputService9TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1348,20 +1365,19 @@ const opInputService9TestCaseOperation1 = "OperationName"
// if err == nil { // resp is now filled
// fmt.Println(resp)
// }
func (c *InputService9ProtocolTest) InputService9TestCaseOperation1Request(input *InputService9TestShapeInputService9TestCaseOperation2Input) (req *request.Request, output *InputService9TestShapeInputService9TestCaseOperation1Output) {
func (c *InputService9ProtocolTest) InputService9TestCaseOperation1Request(input *InputService9TestShapeInputService9TestCaseOperation1Input) (req *request.Request, output *InputService9TestShapeInputService9TestCaseOperation1Output) {
op := &request.Operation{
Name: opInputService9TestCaseOperation1,
HTTPPath: "/",
}
if input == nil {
input = &InputService9TestShapeInputService9TestCaseOperation2Input{}
input = &InputService9TestShapeInputService9TestCaseOperation1Input{}
}
output = &InputService9TestShapeInputService9TestCaseOperation1Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler)
req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler)
req.Handlers.Unmarshal.Swap(ec2query.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
return
}
@@ -1373,7 +1389,7 @@ func (c *InputService9ProtocolTest) InputService9TestCaseOperation1Request(input
//
// See the AWS API reference guide for 's
// API operation InputService9TestCaseOperation1 for usage and error information.
func (c *InputService9ProtocolTest) InputService9TestCaseOperation1(input *InputService9TestShapeInputService9TestCaseOperation2Input) (*InputService9TestShapeInputService9TestCaseOperation1Output, error) {
func (c *InputService9ProtocolTest) InputService9TestCaseOperation1(input *InputService9TestShapeInputService9TestCaseOperation1Input) (*InputService9TestShapeInputService9TestCaseOperation1Output, error) {
req, out := c.InputService9TestCaseOperation1Request(input)
return out, req.Send()
}
@@ -1387,7 +1403,7 @@ func (c *InputService9ProtocolTest) InputService9TestCaseOperation1(input *Input
// the context is nil a panic will occur. In the future the SDK may create
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
// for more information on using Contexts.
func (c *InputService9ProtocolTest) InputService9TestCaseOperation1WithContext(ctx aws.Context, input *InputService9TestShapeInputService9TestCaseOperation2Input, opts ...request.Option) (*InputService9TestShapeInputService9TestCaseOperation1Output, error) {
func (c *InputService9ProtocolTest) InputService9TestCaseOperation1WithContext(ctx aws.Context, input *InputService9TestShapeInputService9TestCaseOperation1Input, opts ...request.Option) (*InputService9TestShapeInputService9TestCaseOperation1Output, error) {
req, out := c.InputService9TestCaseOperation1Request(input)
req.SetContext(ctx)
req.ApplyOptions(opts...)
@@ -1399,7 +1415,7 @@ const opInputService9TestCaseOperation2 = "OperationName"
// InputService9TestCaseOperation2Request generates a "aws/request.Request" representing the
// client's request for the InputService9TestCaseOperation2 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1430,8 +1446,7 @@ func (c *InputService9ProtocolTest) InputService9TestCaseOperation2Request(input
output = &InputService9TestShapeInputService9TestCaseOperation2Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler)
req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler)
req.Handlers.Unmarshal.Swap(ec2query.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
return
}
@@ -1464,6 +1479,18 @@ func (c *InputService9ProtocolTest) InputService9TestCaseOperation2WithContext(c
return out, req.Send()
}
type InputService9TestShapeInputService9TestCaseOperation1Input struct {
_ struct{} `type:"structure"`
Token *string `type:"string" idempotencyToken:"true"`
}
// SetToken sets the Token field's value.
func (s *InputService9TestShapeInputService9TestCaseOperation1Input) SetToken(v string) *InputService9TestShapeInputService9TestCaseOperation1Input {
s.Token = &v
return s
}
type InputService9TestShapeInputService9TestCaseOperation1Output struct {
_ struct{} `type:"structure"`
}
@@ -1515,7 +1542,8 @@ func newInputService10ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "inputservice10protocoltest",
ServiceName: "InputService10ProtocolTest",
ServiceID: "InputService10ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1548,7 +1576,7 @@ const opInputService10TestCaseOperation1 = "OperationName"
// InputService10TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the InputService10TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1567,20 +1595,19 @@ const opInputService10TestCaseOperation1 = "OperationName"
// if err == nil { // resp is now filled
// fmt.Println(resp)
// }
func (c *InputService10ProtocolTest) InputService10TestCaseOperation1Request(input *InputService10TestShapeInputService10TestCaseOperation2Input) (req *request.Request, output *InputService10TestShapeInputService10TestCaseOperation1Output) {
func (c *InputService10ProtocolTest) InputService10TestCaseOperation1Request(input *InputService10TestShapeInputService10TestCaseOperation1Input) (req *request.Request, output *InputService10TestShapeInputService10TestCaseOperation1Output) {
op := &request.Operation{
Name: opInputService10TestCaseOperation1,
HTTPPath: "/",
}
if input == nil {
input = &InputService10TestShapeInputService10TestCaseOperation2Input{}
input = &InputService10TestShapeInputService10TestCaseOperation1Input{}
}
output = &InputService10TestShapeInputService10TestCaseOperation1Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler)
req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler)
req.Handlers.Unmarshal.Swap(ec2query.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
return
}
@@ -1592,7 +1619,7 @@ func (c *InputService10ProtocolTest) InputService10TestCaseOperation1Request(inp
//
// See the AWS API reference guide for 's
// API operation InputService10TestCaseOperation1 for usage and error information.
func (c *InputService10ProtocolTest) InputService10TestCaseOperation1(input *InputService10TestShapeInputService10TestCaseOperation2Input) (*InputService10TestShapeInputService10TestCaseOperation1Output, error) {
func (c *InputService10ProtocolTest) InputService10TestCaseOperation1(input *InputService10TestShapeInputService10TestCaseOperation1Input) (*InputService10TestShapeInputService10TestCaseOperation1Output, error) {
req, out := c.InputService10TestCaseOperation1Request(input)
return out, req.Send()
}
@@ -1606,7 +1633,7 @@ func (c *InputService10ProtocolTest) InputService10TestCaseOperation1(input *Inp
// the context is nil a panic will occur. In the future the SDK may create
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
// for more information on using Contexts.
func (c *InputService10ProtocolTest) InputService10TestCaseOperation1WithContext(ctx aws.Context, input *InputService10TestShapeInputService10TestCaseOperation2Input, opts ...request.Option) (*InputService10TestShapeInputService10TestCaseOperation1Output, error) {
func (c *InputService10ProtocolTest) InputService10TestCaseOperation1WithContext(ctx aws.Context, input *InputService10TestShapeInputService10TestCaseOperation1Input, opts ...request.Option) (*InputService10TestShapeInputService10TestCaseOperation1Output, error) {
req, out := c.InputService10TestCaseOperation1Request(input)
req.SetContext(ctx)
req.ApplyOptions(opts...)
@@ -1618,7 +1645,7 @@ const opInputService10TestCaseOperation2 = "OperationName"
// InputService10TestCaseOperation2Request generates a "aws/request.Request" representing the
// client's request for the InputService10TestCaseOperation2 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1649,8 +1676,7 @@ func (c *InputService10ProtocolTest) InputService10TestCaseOperation2Request(inp
output = &InputService10TestShapeInputService10TestCaseOperation2Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler)
req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler)
req.Handlers.Unmarshal.Swap(ec2query.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
return
}
@@ -1683,6 +1709,26 @@ func (c *InputService10ProtocolTest) InputService10TestCaseOperation2WithContext
return out, req.Send()
}
type InputService10TestShapeInputService10TestCaseOperation1Input struct {
_ struct{} `type:"structure"`
FooEnum *string `type:"string" enum:"InputService10TestShapeEnumType"`
ListEnums []*string `type:"list"`
}
// SetFooEnum sets the FooEnum field's value.
func (s *InputService10TestShapeInputService10TestCaseOperation1Input) SetFooEnum(v string) *InputService10TestShapeInputService10TestCaseOperation1Input {
s.FooEnum = &v
return s
}
// SetListEnums sets the ListEnums field's value.
func (s *InputService10TestShapeInputService10TestCaseOperation1Input) SetListEnums(v []*string) *InputService10TestShapeInputService10TestCaseOperation1Input {
s.ListEnums = v
return s
}
type InputService10TestShapeInputService10TestCaseOperation1Output struct {
_ struct{} `type:"structure"`
}
@@ -1719,6 +1765,263 @@ const (
EnumTypeBar = "bar"
)
// InputService11ProtocolTest provides the API operation methods for making requests to
// . See this package's package overview docs
// for details on the service.
//
// InputService11ProtocolTest methods are safe to use concurrently. It is not safe to
// modify mutate any of the struct's properties though.
type InputService11ProtocolTest struct {
*client.Client
}
// New creates a new instance of the InputService11ProtocolTest client with a session.
// If additional configuration is needed for the client instance use the optional
// aws.Config parameter to add your extra config.
//
// Example:
// // Create a InputService11ProtocolTest client from just a session.
// svc := inputservice11protocoltest.New(mySession)
//
// // Create a InputService11ProtocolTest client with additional configuration
// svc := inputservice11protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
func NewInputService11ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService11ProtocolTest {
c := p.ClientConfig("inputservice11protocoltest", cfgs...)
return newInputService11ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName)
}
// newClient creates, initializes and returns a new service client instance.
func newInputService11ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService11ProtocolTest {
svc := &InputService11ProtocolTest{
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "InputService11ProtocolTest",
ServiceID: "InputService11ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
APIVersion: "2014-01-01",
},
handlers,
),
}
// Handlers
svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler)
svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler)
svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler)
svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler)
svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler)
return svc
}
// newRequest creates a new request for a InputService11ProtocolTest operation and runs any
// custom request initialization.
func (c *InputService11ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request {
req := c.NewRequest(op, params, data)
return req
}
const opInputService11TestCaseOperation1 = "StaticOp"
// InputService11TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the InputService11TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
//
// See InputService11TestCaseOperation1 for more information on using the InputService11TestCaseOperation1
// API call, and error handling.
//
// This method is useful when you want to inject custom logic or configuration
// into the SDK's request lifecycle. Such as custom headers, or retry logic.
//
//
// // Example sending a request using the InputService11TestCaseOperation1Request method.
// req, resp := client.InputService11TestCaseOperation1Request(params)
//
// err := req.Send()
// if err == nil { // resp is now filled
// fmt.Println(resp)
// }
func (c *InputService11ProtocolTest) InputService11TestCaseOperation1Request(input *InputService11TestShapeInputService11TestCaseOperation1Input) (req *request.Request, output *InputService11TestShapeInputService11TestCaseOperation1Output) {
op := &request.Operation{
Name: opInputService11TestCaseOperation1,
HTTPPath: "/",
}
if input == nil {
input = &InputService11TestShapeInputService11TestCaseOperation1Input{}
}
output = &InputService11TestShapeInputService11TestCaseOperation1Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Swap(ec2query.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
req.Handlers.Build.PushBackNamed(protocol.NewHostPrefixHandler("data-", nil))
req.Handlers.Build.PushBackNamed(protocol.ValidateEndpointHostHandler)
return
}
// InputService11TestCaseOperation1 API operation for .
//
// 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
// the error.
//
// See the AWS API reference guide for 's
// API operation InputService11TestCaseOperation1 for usage and error information.
func (c *InputService11ProtocolTest) InputService11TestCaseOperation1(input *InputService11TestShapeInputService11TestCaseOperation1Input) (*InputService11TestShapeInputService11TestCaseOperation1Output, error) {
req, out := c.InputService11TestCaseOperation1Request(input)
return out, req.Send()
}
// InputService11TestCaseOperation1WithContext is the same as InputService11TestCaseOperation1 with the addition of
// the ability to pass a context and additional request options.
//
// See InputService11TestCaseOperation1 for details on how to use this API operation.
//
// The context must be non-nil and will be used for request cancellation. If
// the context is nil a panic will occur. In the future the SDK may create
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
// for more information on using Contexts.
func (c *InputService11ProtocolTest) InputService11TestCaseOperation1WithContext(ctx aws.Context, input *InputService11TestShapeInputService11TestCaseOperation1Input, opts ...request.Option) (*InputService11TestShapeInputService11TestCaseOperation1Output, error) {
req, out := c.InputService11TestCaseOperation1Request(input)
req.SetContext(ctx)
req.ApplyOptions(opts...)
return out, req.Send()
}
const opInputService11TestCaseOperation2 = "MemberRefOp"
// InputService11TestCaseOperation2Request generates a "aws/request.Request" representing the
// client's request for the InputService11TestCaseOperation2 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
//
// See InputService11TestCaseOperation2 for more information on using the InputService11TestCaseOperation2
// API call, and error handling.
//
// This method is useful when you want to inject custom logic or configuration
// into the SDK's request lifecycle. Such as custom headers, or retry logic.
//
//
// // Example sending a request using the InputService11TestCaseOperation2Request method.
// req, resp := client.InputService11TestCaseOperation2Request(params)
//
// err := req.Send()
// if err == nil { // resp is now filled
// fmt.Println(resp)
// }
func (c *InputService11ProtocolTest) InputService11TestCaseOperation2Request(input *InputService11TestShapeInputService11TestCaseOperation2Input) (req *request.Request, output *InputService11TestShapeInputService11TestCaseOperation2Output) {
op := &request.Operation{
Name: opInputService11TestCaseOperation2,
HTTPPath: "/",
}
if input == nil {
input = &InputService11TestShapeInputService11TestCaseOperation2Input{}
}
output = &InputService11TestShapeInputService11TestCaseOperation2Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Swap(ec2query.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
req.Handlers.Build.PushBackNamed(protocol.NewHostPrefixHandler("foo-{Name}.", input.hostLabels))
req.Handlers.Build.PushBackNamed(protocol.ValidateEndpointHostHandler)
return
}
// InputService11TestCaseOperation2 API operation for .
//
// 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
// the error.
//
// See the AWS API reference guide for 's
// API operation InputService11TestCaseOperation2 for usage and error information.
func (c *InputService11ProtocolTest) InputService11TestCaseOperation2(input *InputService11TestShapeInputService11TestCaseOperation2Input) (*InputService11TestShapeInputService11TestCaseOperation2Output, error) {
req, out := c.InputService11TestCaseOperation2Request(input)
return out, req.Send()
}
// InputService11TestCaseOperation2WithContext is the same as InputService11TestCaseOperation2 with the addition of
// the ability to pass a context and additional request options.
//
// See InputService11TestCaseOperation2 for details on how to use this API operation.
//
// The context must be non-nil and will be used for request cancellation. If
// the context is nil a panic will occur. In the future the SDK may create
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
// for more information on using Contexts.
func (c *InputService11ProtocolTest) InputService11TestCaseOperation2WithContext(ctx aws.Context, input *InputService11TestShapeInputService11TestCaseOperation2Input, opts ...request.Option) (*InputService11TestShapeInputService11TestCaseOperation2Output, error) {
req, out := c.InputService11TestCaseOperation2Request(input)
req.SetContext(ctx)
req.ApplyOptions(opts...)
return out, req.Send()
}
type InputService11TestShapeInputService11TestCaseOperation1Input struct {
_ struct{} `type:"structure"`
Name *string `type:"string"`
}
// SetName sets the Name field's value.
func (s *InputService11TestShapeInputService11TestCaseOperation1Input) SetName(v string) *InputService11TestShapeInputService11TestCaseOperation1Input {
s.Name = &v
return s
}
type InputService11TestShapeInputService11TestCaseOperation1Output struct {
_ struct{} `type:"structure"`
}
type InputService11TestShapeInputService11TestCaseOperation2Input struct {
_ struct{} `type:"structure"`
// Name is a required field
Name *string `type:"string" required:"true"`
}
// Validate inspects the fields of the type to determine if they are valid.
func (s *InputService11TestShapeInputService11TestCaseOperation2Input) Validate() error {
invalidParams := request.ErrInvalidParams{Context: "InputService11TestShapeInputService11TestCaseOperation2Input"}
if s.Name == nil {
invalidParams.Add(request.NewErrParamRequired("Name"))
}
if s.Name != nil && len(*s.Name) < 1 {
invalidParams.Add(request.NewErrParamMinLen("Name", 1))
}
if invalidParams.Len() > 0 {
return invalidParams
}
return nil
}
// SetName sets the Name field's value.
func (s *InputService11TestShapeInputService11TestCaseOperation2Input) SetName(v string) *InputService11TestShapeInputService11TestCaseOperation2Input {
s.Name = &v
return s
}
func (s *InputService11TestShapeInputService11TestCaseOperation2Input) hostLabels() map[string]string {
return map[string]string{
"Name": aws.StringValue(s.Name),
}
}
type InputService11TestShapeInputService11TestCaseOperation2Output struct {
_ struct{} `type:"structure"`
}
//
// Tests begin here
//
@@ -1733,7 +2036,7 @@ func TestInputService1ProtocolTestScalarMembersCase1(t *testing.T) {
r := req.HTTPRequest
// build request
ec2query.Build(req)
req.Build()
if req.Error != nil {
t.Errorf("expect no error, got %v", req.Error)
}
@@ -1763,7 +2066,7 @@ func TestInputService2ProtocolTestStructureWithLocationNameAndQueryNameAppliedTo
r := req.HTTPRequest
// build request
ec2query.Build(req)
req.Build()
if req.Error != nil {
t.Errorf("expect no error, got %v", req.Error)
}
@@ -1793,7 +2096,7 @@ func TestInputService3ProtocolTestNestedStructureMembersCase1(t *testing.T) {
r := req.HTTPRequest
// build request
ec2query.Build(req)
req.Build()
if req.Error != nil {
t.Errorf("expect no error, got %v", req.Error)
}
@@ -1840,7 +2143,7 @@ func TestInputService4ProtocolTestListTypesCase1(t *testing.T) {
r := req.HTTPRequest
// build request
ec2query.Build(req)
req.Build()
if req.Error != nil {
t.Errorf("expect no error, got %v", req.Error)
}
@@ -1872,7 +2175,7 @@ func TestInputService5ProtocolTestListWithLocationNameAppliedToMemberCase1(t *te
r := req.HTTPRequest
// build request
ec2query.Build(req)
req.Build()
if req.Error != nil {
t.Errorf("expect no error, got %v", req.Error)
}
@@ -1904,7 +2207,7 @@ func TestInputService6ProtocolTestListWithLocationNameAndQueryNameCase1(t *testi
r := req.HTTPRequest
// build request
ec2query.Build(req)
req.Build()
if req.Error != nil {
t.Errorf("expect no error, got %v", req.Error)
}
@@ -1932,7 +2235,7 @@ func TestInputService7ProtocolTestBase64EncodedBlobsCase1(t *testing.T) {
r := req.HTTPRequest
// build request
ec2query.Build(req)
req.Build()
if req.Error != nil {
t.Errorf("expect no error, got %v", req.Error)
}
@@ -1954,13 +2257,15 @@ func TestInputService7ProtocolTestBase64EncodedBlobsCase1(t *testing.T) {
func TestInputService8ProtocolTestTimestampValuesCase1(t *testing.T) {
svc := NewInputService8ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")})
input := &InputService8TestShapeInputService8TestCaseOperation1Input{
TimeArg: aws.Time(time.Unix(1422172800, 0)),
TimeArg: aws.Time(time.Unix(1422172800, 0)),
TimeCustom: aws.Time(time.Unix(1422172800, 0)),
TimeFormat: aws.Time(time.Unix(1422172800, 0)),
}
req, _ := svc.InputService8TestCaseOperation1Request(input)
r := req.HTTPRequest
// build request
ec2query.Build(req)
req.Build()
if req.Error != nil {
t.Errorf("expect no error, got %v", req.Error)
}
@@ -1970,7 +2275,7 @@ func TestInputService8ProtocolTestTimestampValuesCase1(t *testing.T) {
t.Errorf("expect body not to be nil")
}
body, _ := ioutil.ReadAll(r.Body)
awstesting.AssertQuery(t, `Action=OperationName&TimeArg=2015-01-25T08%3A00%3A00Z&Version=2014-01-01`, util.Trim(string(body)))
awstesting.AssertQuery(t, `Action=OperationName&TimeArg=2015-01-25T08%3A00%3A00Z&TimeCustom=1422172800&TimeFormat=1422172800&Version=2014-01-01`, util.Trim(string(body)))
// assert URL
awstesting.AssertURL(t, "https://test/", r.URL.String())
@@ -1981,14 +2286,14 @@ func TestInputService8ProtocolTestTimestampValuesCase1(t *testing.T) {
func TestInputService9ProtocolTestIdempotencyTokenAutoFillCase1(t *testing.T) {
svc := NewInputService9ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")})
input := &InputService9TestShapeInputService9TestCaseOperation2Input{
input := &InputService9TestShapeInputService9TestCaseOperation1Input{
Token: aws.String("abc123"),
}
req, _ := svc.InputService9TestCaseOperation1Request(input)
r := req.HTTPRequest
// build request
ec2query.Build(req)
req.Build()
if req.Error != nil {
t.Errorf("expect no error, got %v", req.Error)
}
@@ -2014,7 +2319,7 @@ func TestInputService9ProtocolTestIdempotencyTokenAutoFillCase2(t *testing.T) {
r := req.HTTPRequest
// build request
ec2query.Build(req)
req.Build()
if req.Error != nil {
t.Errorf("expect no error, got %v", req.Error)
}
@@ -2035,7 +2340,7 @@ func TestInputService9ProtocolTestIdempotencyTokenAutoFillCase2(t *testing.T) {
func TestInputService10ProtocolTestEnumCase1(t *testing.T) {
svc := NewInputService10ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")})
input := &InputService10TestShapeInputService10TestCaseOperation2Input{
input := &InputService10TestShapeInputService10TestCaseOperation1Input{
ListEnums: []*string{
aws.String("foo"),
aws.String(""),
@@ -2046,7 +2351,7 @@ func TestInputService10ProtocolTestEnumCase1(t *testing.T) {
r := req.HTTPRequest
// build request
ec2query.Build(req)
req.Build()
if req.Error != nil {
t.Errorf("expect no error, got %v", req.Error)
}
@@ -2072,7 +2377,7 @@ func TestInputService10ProtocolTestEnumCase2(t *testing.T) {
r := req.HTTPRequest
// build request
ec2query.Build(req)
req.Build()
if req.Error != nil {
t.Errorf("expect no error, got %v", req.Error)
}
@@ -2090,3 +2395,59 @@ func TestInputService10ProtocolTestEnumCase2(t *testing.T) {
// assert headers
}
func TestInputService11ProtocolTestEndpointHostTraitCase1(t *testing.T) {
svc := NewInputService11ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://service.region.amazonaws.com")})
input := &InputService11TestShapeInputService11TestCaseOperation1Input{
Name: aws.String("myname"),
}
req, _ := svc.InputService11TestCaseOperation1Request(input)
r := req.HTTPRequest
// build request
req.Build()
if req.Error != nil {
t.Errorf("expect no error, got %v", req.Error)
}
// assert body
if r.Body == nil {
t.Errorf("expect body not to be nil")
}
body, _ := ioutil.ReadAll(r.Body)
awstesting.AssertQuery(t, `Action=StaticOp&Name=myname&Version=2014-01-01`, util.Trim(string(body)))
// assert URL
awstesting.AssertURL(t, "https://data-service.region.amazonaws.com/", r.URL.String())
// assert headers
}
func TestInputService11ProtocolTestEndpointHostTraitCase2(t *testing.T) {
svc := NewInputService11ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://service.region.amazonaws.com")})
input := &InputService11TestShapeInputService11TestCaseOperation2Input{
Name: aws.String("myname"),
}
req, _ := svc.InputService11TestCaseOperation2Request(input)
r := req.HTTPRequest
// build request
req.Build()
if req.Error != nil {
t.Errorf("expect no error, got %v", req.Error)
}
// assert body
if r.Body == nil {
t.Errorf("expect body not to be nil")
}
body, _ := ioutil.ReadAll(r.Body)
awstesting.AssertQuery(t, `Action=MemberRefOp&Name=myname&Version=2014-01-01`, util.Trim(string(body)))
// assert URL
awstesting.AssertURL(t, "https://foo-myname.service.region.amazonaws.com/", r.URL.String())
// assert headers
}
+24 -10
View File
@@ -4,7 +4,6 @@ package ec2query
import (
"encoding/xml"
"io"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
@@ -27,7 +26,12 @@ func Unmarshal(r *request.Request) {
decoder := xml.NewDecoder(r.HTTPResponse.Body)
err := xmlutil.UnmarshalXML(r.Data, decoder, "")
if err != nil {
r.Error = awserr.New("SerializationError", "failed decoding EC2 Query response", err)
r.Error = awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization,
"failed decoding EC2 Query response", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
return
}
}
@@ -35,7 +39,11 @@ func Unmarshal(r *request.Request) {
// UnmarshalMeta unmarshals response headers for the EC2 protocol.
func UnmarshalMeta(r *request.Request) {
// TODO implement unmarshaling of request IDs
r.RequestID = r.HTTPResponse.Header.Get("X-Amzn-Requestid")
if r.RequestID == "" {
// Alternative version of request id in the header
r.RequestID = r.HTTPResponse.Header.Get("X-Amz-Request-Id")
}
}
type xmlErrorResponse struct {
@@ -49,15 +57,21 @@ type xmlErrorResponse struct {
func UnmarshalError(r *request.Request) {
defer r.HTTPResponse.Body.Close()
resp := &xmlErrorResponse{}
err := xml.NewDecoder(r.HTTPResponse.Body).Decode(resp)
if err != nil && err != io.EOF {
r.Error = awserr.New("SerializationError", "failed decoding EC2 Query error response", err)
} else {
var respErr xmlErrorResponse
err := xmlutil.UnmarshalXMLError(&respErr, r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.NewRequestFailure(
awserr.New(resp.Code, resp.Message, nil),
awserr.New(request.ErrCodeSerialization,
"failed to unmarshal error message", err),
r.HTTPResponse.StatusCode,
resp.RequestID,
r.RequestID,
)
return
}
r.Error = awserr.NewRequestFailure(
awserr.New(respErr.Code, respErr.Message, nil),
r.HTTPResponse.StatusCode,
respErr.RequestID,
)
}
@@ -0,0 +1,82 @@
// +build go1.8
package ec2query
import (
"io/ioutil"
"net/http"
"strings"
"testing"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
)
func TestUnmarshalError(t *testing.T) {
cases := map[string]struct {
Request *request.Request
Code, Msg string
ReqID string
Status int
}{
"ErrorResponse": {
Request: &request.Request{
HTTPResponse: &http.Response{
StatusCode: 400,
Header: http.Header{},
Body: ioutil.NopCloser(strings.NewReader(
`<Response>
<Errors>
<Error>
<Code>codeAbc</Code>
<Message>msg123</Message>
</Error>
</Errors>
<RequestID>reqID123</RequestID>
</Response>`)),
},
},
Code: "codeAbc", Msg: "msg123",
Status: 400, ReqID: "reqID123",
},
"unknown tag": {
Request: &request.Request{
HTTPResponse: &http.Response{
StatusCode: 400,
Header: http.Header{},
Body: ioutil.NopCloser(strings.NewReader(
`<Hello>
<World>.</World>
</Hello>`)),
},
},
Code: request.ErrCodeSerialization,
Msg: "failed to unmarshal error message",
Status: 400,
},
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
r := c.Request
UnmarshalError(r)
if r.Error == nil {
t.Fatalf("expect error, got none")
}
aerr := r.Error.(awserr.RequestFailure)
if e, a := c.Code, aerr.Code(); e != a {
t.Errorf("expect %v code, got %v", e, a)
}
if e, a := c.Msg, aerr.Message(); e != a {
t.Errorf("expect %q message, got %q", e, a)
}
if e, a := c.ReqID, aerr.RequestID(); e != a {
t.Errorf("expect %v request ID, got %v", e, a)
}
if e, a := c.Status, aerr.StatusCode(); e != a {
t.Errorf("expect %v status code, got %v", e, a)
}
})
}
}
+283 -47
View File
@@ -75,7 +75,8 @@ func newOutputService1ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice1protocoltest",
ServiceName: "OutputService1ProtocolTest",
ServiceID: "OutputService1ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -108,7 +109,7 @@ const opOutputService1TestCaseOperation1 = "OperationName"
// OutputService1TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService1TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -274,7 +275,8 @@ func newOutputService2ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice2protocoltest",
ServiceName: "OutputService2ProtocolTest",
ServiceID: "OutputService2ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -307,7 +309,7 @@ const opOutputService2TestCaseOperation1 = "OperationName"
// OutputService2TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService2TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -418,7 +420,8 @@ func newOutputService3ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice3protocoltest",
ServiceName: "OutputService3ProtocolTest",
ServiceID: "OutputService3ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -451,7 +454,7 @@ const opOutputService3TestCaseOperation1 = "OperationName"
// OutputService3TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService3TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -561,7 +564,8 @@ func newOutputService4ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice4protocoltest",
ServiceName: "OutputService4ProtocolTest",
ServiceID: "OutputService4ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -594,7 +598,7 @@ const opOutputService4TestCaseOperation1 = "OperationName"
// OutputService4TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService4TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -704,7 +708,8 @@ func newOutputService5ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice5protocoltest",
ServiceName: "OutputService5ProtocolTest",
ServiceID: "OutputService5ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -737,7 +742,7 @@ const opOutputService5TestCaseOperation1 = "OperationName"
// OutputService5TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService5TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -847,7 +852,8 @@ func newOutputService6ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice6protocoltest",
ServiceName: "OutputService6ProtocolTest",
ServiceID: "OutputService6ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -880,7 +886,7 @@ const opOutputService6TestCaseOperation1 = "OperationName"
// OutputService6TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService6TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1002,7 +1008,8 @@ func newOutputService7ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice7protocoltest",
ServiceName: "OutputService7ProtocolTest",
ServiceID: "OutputService7ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1035,7 +1042,7 @@ const opOutputService7TestCaseOperation1 = "OperationName"
// OutputService7TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService7TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1145,7 +1152,8 @@ func newOutputService8ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice8protocoltest",
ServiceName: "OutputService8ProtocolTest",
ServiceID: "OutputService8ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1178,7 +1186,7 @@ const opOutputService8TestCaseOperation1 = "OperationName"
// OutputService8TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService8TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1288,7 +1296,8 @@ func newOutputService9ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice9protocoltest",
ServiceName: "OutputService9ProtocolTest",
ServiceID: "OutputService9ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1321,7 +1330,7 @@ const opOutputService9TestCaseOperation1 = "OperationName"
// OutputService9TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService9TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1431,7 +1440,8 @@ func newOutputService10ProtocolTestClient(cfg aws.Config, handlers request.Handl
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice10protocoltest",
ServiceName: "OutputService10ProtocolTest",
ServiceID: "OutputService10ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1464,7 +1474,7 @@ const opOutputService10TestCaseOperation1 = "OperationName"
// OutputService10TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService10TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1534,28 +1544,216 @@ type OutputService10TestShapeOutputService10TestCaseOperation1Input struct {
type OutputService10TestShapeOutputService10TestCaseOperation1Output struct {
_ struct{} `type:"structure"`
FooEnum *string `type:"string" enum:"OutputService10TestShapeEC2EnumType"`
StructMember *OutputService10TestShapeTimeContainer `type:"structure"`
TimeArg *time.Time `type:"timestamp"`
TimeCustom *time.Time `type:"timestamp" timestampFormat:"rfc822"`
TimeFormat *time.Time `type:"timestamp" timestampFormat:"unixTimestamp"`
}
// SetStructMember sets the StructMember field's value.
func (s *OutputService10TestShapeOutputService10TestCaseOperation1Output) SetStructMember(v *OutputService10TestShapeTimeContainer) *OutputService10TestShapeOutputService10TestCaseOperation1Output {
s.StructMember = v
return s
}
// SetTimeArg sets the TimeArg field's value.
func (s *OutputService10TestShapeOutputService10TestCaseOperation1Output) SetTimeArg(v time.Time) *OutputService10TestShapeOutputService10TestCaseOperation1Output {
s.TimeArg = &v
return s
}
// SetTimeCustom sets the TimeCustom field's value.
func (s *OutputService10TestShapeOutputService10TestCaseOperation1Output) SetTimeCustom(v time.Time) *OutputService10TestShapeOutputService10TestCaseOperation1Output {
s.TimeCustom = &v
return s
}
// SetTimeFormat sets the TimeFormat field's value.
func (s *OutputService10TestShapeOutputService10TestCaseOperation1Output) SetTimeFormat(v time.Time) *OutputService10TestShapeOutputService10TestCaseOperation1Output {
s.TimeFormat = &v
return s
}
type OutputService10TestShapeTimeContainer struct {
_ struct{} `type:"structure"`
Bar *time.Time `locationName:"bar" type:"timestamp" timestampFormat:"unixTimestamp"`
Foo *time.Time `locationName:"foo" type:"timestamp"`
}
// SetBar sets the Bar field's value.
func (s *OutputService10TestShapeTimeContainer) SetBar(v time.Time) *OutputService10TestShapeTimeContainer {
s.Bar = &v
return s
}
// SetFoo sets the Foo field's value.
func (s *OutputService10TestShapeTimeContainer) SetFoo(v time.Time) *OutputService10TestShapeTimeContainer {
s.Foo = &v
return s
}
// OutputService11ProtocolTest provides the API operation methods for making requests to
// . See this package's package overview docs
// for details on the service.
//
// OutputService11ProtocolTest methods are safe to use concurrently. It is not safe to
// modify mutate any of the struct's properties though.
type OutputService11ProtocolTest struct {
*client.Client
}
// New creates a new instance of the OutputService11ProtocolTest client with a session.
// If additional configuration is needed for the client instance use the optional
// aws.Config parameter to add your extra config.
//
// Example:
// // Create a OutputService11ProtocolTest client from just a session.
// svc := outputservice11protocoltest.New(mySession)
//
// // Create a OutputService11ProtocolTest client with additional configuration
// svc := outputservice11protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
func NewOutputService11ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService11ProtocolTest {
c := p.ClientConfig("outputservice11protocoltest", cfgs...)
return newOutputService11ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName)
}
// newClient creates, initializes and returns a new service client instance.
func newOutputService11ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService11ProtocolTest {
svc := &OutputService11ProtocolTest{
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "OutputService11ProtocolTest",
ServiceID: "OutputService11ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
APIVersion: "",
},
handlers,
),
}
// Handlers
svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler)
svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler)
svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler)
svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler)
svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler)
return svc
}
// newRequest creates a new request for a OutputService11ProtocolTest operation and runs any
// custom request initialization.
func (c *OutputService11ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request {
req := c.NewRequest(op, params, data)
return req
}
const opOutputService11TestCaseOperation1 = "OperationName"
// OutputService11TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService11TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
//
// See OutputService11TestCaseOperation1 for more information on using the OutputService11TestCaseOperation1
// API call, and error handling.
//
// This method is useful when you want to inject custom logic or configuration
// into the SDK's request lifecycle. Such as custom headers, or retry logic.
//
//
// // Example sending a request using the OutputService11TestCaseOperation1Request method.
// req, resp := client.OutputService11TestCaseOperation1Request(params)
//
// err := req.Send()
// if err == nil { // resp is now filled
// fmt.Println(resp)
// }
func (c *OutputService11ProtocolTest) OutputService11TestCaseOperation1Request(input *OutputService11TestShapeOutputService11TestCaseOperation1Input) (req *request.Request, output *OutputService11TestShapeOutputService11TestCaseOperation1Output) {
op := &request.Operation{
Name: opOutputService11TestCaseOperation1,
HTTPPath: "/",
}
if input == nil {
input = &OutputService11TestShapeOutputService11TestCaseOperation1Input{}
}
output = &OutputService11TestShapeOutputService11TestCaseOperation1Output{}
req = c.newRequest(op, input, output)
return
}
// OutputService11TestCaseOperation1 API operation for .
//
// 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
// the error.
//
// See the AWS API reference guide for 's
// API operation OutputService11TestCaseOperation1 for usage and error information.
func (c *OutputService11ProtocolTest) OutputService11TestCaseOperation1(input *OutputService11TestShapeOutputService11TestCaseOperation1Input) (*OutputService11TestShapeOutputService11TestCaseOperation1Output, error) {
req, out := c.OutputService11TestCaseOperation1Request(input)
return out, req.Send()
}
// OutputService11TestCaseOperation1WithContext is the same as OutputService11TestCaseOperation1 with the addition of
// the ability to pass a context and additional request options.
//
// See OutputService11TestCaseOperation1 for details on how to use this API operation.
//
// The context must be non-nil and will be used for request cancellation. If
// the context is nil a panic will occur. In the future the SDK may create
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
// for more information on using Contexts.
func (c *OutputService11ProtocolTest) OutputService11TestCaseOperation1WithContext(ctx aws.Context, input *OutputService11TestShapeOutputService11TestCaseOperation1Input, opts ...request.Option) (*OutputService11TestShapeOutputService11TestCaseOperation1Output, error) {
req, out := c.OutputService11TestCaseOperation1Request(input)
req.SetContext(ctx)
req.ApplyOptions(opts...)
return out, req.Send()
}
type OutputService11TestShapeOutputService11TestCaseOperation1Input struct {
_ struct{} `type:"structure"`
}
type OutputService11TestShapeOutputService11TestCaseOperation1Output struct {
_ struct{} `type:"structure"`
FooEnum *string `type:"string" enum:"OutputService11TestShapeEC2EnumType"`
ListEnums []*string `type:"list"`
}
// SetFooEnum sets the FooEnum field's value.
func (s *OutputService10TestShapeOutputService10TestCaseOperation1Output) SetFooEnum(v string) *OutputService10TestShapeOutputService10TestCaseOperation1Output {
func (s *OutputService11TestShapeOutputService11TestCaseOperation1Output) SetFooEnum(v string) *OutputService11TestShapeOutputService11TestCaseOperation1Output {
s.FooEnum = &v
return s
}
// SetListEnums sets the ListEnums field's value.
func (s *OutputService10TestShapeOutputService10TestCaseOperation1Output) SetListEnums(v []*string) *OutputService10TestShapeOutputService10TestCaseOperation1Output {
func (s *OutputService11TestShapeOutputService11TestCaseOperation1Output) SetListEnums(v []*string) *OutputService11TestShapeOutputService11TestCaseOperation1Output {
s.ListEnums = v
return s
}
const (
// EC2EnumTypeFoo is a OutputService10TestShapeEC2EnumType enum value
// EC2EnumTypeFoo is a OutputService11TestShapeEC2EnumType enum value
EC2EnumTypeFoo = "foo"
// EC2EnumTypeBar is a OutputService10TestShapeEC2EnumType enum value
// EC2EnumTypeBar is a OutputService11TestShapeEC2EnumType enum value
EC2EnumTypeBar = "bar"
)
@@ -1573,8 +1771,8 @@ func TestOutputService1ProtocolTestScalarMembersCase1(t *testing.T) {
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1620,8 +1818,8 @@ func TestOutputService2ProtocolTestBlobCase1(t *testing.T) {
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1646,8 +1844,8 @@ func TestOutputService3ProtocolTestListsCase1(t *testing.T) {
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1675,8 +1873,8 @@ func TestOutputService4ProtocolTestListWithCustomMemberNameCase1(t *testing.T) {
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1704,8 +1902,8 @@ func TestOutputService5ProtocolTestFlattenedListCase1(t *testing.T) {
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1733,8 +1931,8 @@ func TestOutputService6ProtocolTestNormalMapCase1(t *testing.T) {
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1762,8 +1960,8 @@ func TestOutputService7ProtocolTestFlattenedMapCase1(t *testing.T) {
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1791,8 +1989,8 @@ func TestOutputService8ProtocolTestNamedMapCase1(t *testing.T) {
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1820,8 +2018,8 @@ func TestOutputService9ProtocolTestEmptyStringCase1(t *testing.T) {
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1836,18 +2034,56 @@ func TestOutputService9ProtocolTestEmptyStringCase1(t *testing.T) {
}
func TestOutputService10ProtocolTestEnumOutputCase1(t *testing.T) {
func TestOutputService10ProtocolTestTimestampMembersCase1(t *testing.T) {
svc := NewOutputService10ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")})
buf := bytes.NewReader([]byte("<OperationNameResponse><FooEnum>foo</FooEnum><ListEnums><member>foo</member><member>bar</member></ListEnums></OperationNameResponse>"))
buf := bytes.NewReader([]byte("<OperationNameResponse><StructMember><foo>2014-04-29T18:30:38Z</foo><bar>1398796238</bar></StructMember><TimeArg>2014-04-29T18:30:38Z</TimeArg><TimeCustom>Tue, 29 Apr 2014 18:30:38 GMT</TimeCustom><TimeFormat>1398796238</TimeFormat><RequestId>requestid</RequestId></OperationNameResponse>"))
req, out := svc.OutputService10TestCaseOperation1Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
// assert response
if out == nil {
t.Errorf("expect not to be nil")
}
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.StructMember.Bar.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.StructMember.Foo.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.TimeArg.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.TimeCustom.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.TimeFormat.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
}
func TestOutputService11ProtocolTestEnumOutputCase1(t *testing.T) {
svc := NewOutputService11ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")})
buf := bytes.NewReader([]byte("<OperationNameResponse><FooEnum>foo</FooEnum><ListEnums><member>foo</member><member>bar</member></ListEnums></OperationNameResponse>"))
req, out := svc.OutputService11TestCaseOperation1Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
+144
View File
@@ -0,0 +1,144 @@
package eventstream
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"strconv"
)
type decodedMessage struct {
rawMessage
Headers decodedHeaders `json:"headers"`
}
type jsonMessage struct {
Length json.Number `json:"total_length"`
HeadersLen json.Number `json:"headers_length"`
PreludeCRC json.Number `json:"prelude_crc"`
Headers decodedHeaders `json:"headers"`
Payload []byte `json:"payload"`
CRC json.Number `json:"message_crc"`
}
func (d *decodedMessage) UnmarshalJSON(b []byte) (err error) {
var jsonMsg jsonMessage
if err = json.Unmarshal(b, &jsonMsg); err != nil {
return err
}
d.Length, err = numAsUint32(jsonMsg.Length)
if err != nil {
return err
}
d.HeadersLen, err = numAsUint32(jsonMsg.HeadersLen)
if err != nil {
return err
}
d.PreludeCRC, err = numAsUint32(jsonMsg.PreludeCRC)
if err != nil {
return err
}
d.Headers = jsonMsg.Headers
d.Payload = jsonMsg.Payload
d.CRC, err = numAsUint32(jsonMsg.CRC)
if err != nil {
return err
}
return nil
}
func (d *decodedMessage) MarshalJSON() ([]byte, error) {
jsonMsg := jsonMessage{
Length: json.Number(strconv.Itoa(int(d.Length))),
HeadersLen: json.Number(strconv.Itoa(int(d.HeadersLen))),
PreludeCRC: json.Number(strconv.Itoa(int(d.PreludeCRC))),
Headers: d.Headers,
Payload: d.Payload,
CRC: json.Number(strconv.Itoa(int(d.CRC))),
}
return json.Marshal(jsonMsg)
}
func numAsUint32(n json.Number) (uint32, error) {
v, err := n.Int64()
if err != nil {
return 0, fmt.Errorf("failed to get int64 json number, %v", err)
}
return uint32(v), nil
}
func (d decodedMessage) Message() Message {
return Message{
Headers: Headers(d.Headers),
Payload: d.Payload,
}
}
type decodedHeaders Headers
func (hs *decodedHeaders) UnmarshalJSON(b []byte) error {
var jsonHeaders []struct {
Name string `json:"name"`
Type valueType `json:"type"`
Value interface{} `json:"value"`
}
decoder := json.NewDecoder(bytes.NewReader(b))
decoder.UseNumber()
if err := decoder.Decode(&jsonHeaders); err != nil {
return err
}
var headers Headers
for _, h := range jsonHeaders {
value, err := valueFromType(h.Type, h.Value)
if err != nil {
return err
}
headers.Set(h.Name, value)
}
(*hs) = decodedHeaders(headers)
return nil
}
func valueFromType(typ valueType, val interface{}) (Value, error) {
switch typ {
case trueValueType:
return BoolValue(true), nil
case falseValueType:
return BoolValue(false), nil
case int8ValueType:
v, err := val.(json.Number).Int64()
return Int8Value(int8(v)), err
case int16ValueType:
v, err := val.(json.Number).Int64()
return Int16Value(int16(v)), err
case int32ValueType:
v, err := val.(json.Number).Int64()
return Int32Value(int32(v)), err
case int64ValueType:
v, err := val.(json.Number).Int64()
return Int64Value(v), err
case bytesValueType:
v, err := base64.StdEncoding.DecodeString(val.(string))
return BytesValue(v), err
case stringValueType:
v, err := base64.StdEncoding.DecodeString(val.(string))
return StringValue(string(v)), err
case timestampValueType:
v, err := val.(json.Number).Int64()
return TimestampValue(timeFromEpochMilli(v)), err
case uuidValueType:
v, err := base64.StdEncoding.DecodeString(val.(string))
var tv UUIDValue
copy(tv[:], v)
return tv, err
default:
panic(fmt.Sprintf("unknown type, %s, %T", typ.String(), val))
}
}
+199
View File
@@ -0,0 +1,199 @@
package eventstream
import (
"bytes"
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"hash"
"hash/crc32"
"io"
"github.com/aws/aws-sdk-go/aws"
)
// Decoder provides decoding of an Event Stream messages.
type Decoder struct {
r io.Reader
logger aws.Logger
}
// NewDecoder initializes and returns a Decoder for decoding event
// stream messages from the reader provided.
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{
r: r,
}
}
// Decode attempts to decode a single message from the event stream reader.
// Will return the event stream message, or error if Decode fails to read
// the message from the stream.
func (d *Decoder) Decode(payloadBuf []byte) (m Message, err error) {
reader := d.r
if d.logger != nil {
debugMsgBuf := bytes.NewBuffer(nil)
reader = io.TeeReader(reader, debugMsgBuf)
defer func() {
logMessageDecode(d.logger, debugMsgBuf, m, err)
}()
}
crc := crc32.New(crc32IEEETable)
hashReader := io.TeeReader(reader, crc)
prelude, err := decodePrelude(hashReader, crc)
if err != nil {
return Message{}, err
}
if prelude.HeadersLen > 0 {
lr := io.LimitReader(hashReader, int64(prelude.HeadersLen))
m.Headers, err = decodeHeaders(lr)
if err != nil {
return Message{}, err
}
}
if payloadLen := prelude.PayloadLen(); payloadLen > 0 {
buf, err := decodePayload(payloadBuf, io.LimitReader(hashReader, int64(payloadLen)))
if err != nil {
return Message{}, err
}
m.Payload = buf
}
msgCRC := crc.Sum32()
if err := validateCRC(reader, msgCRC); err != nil {
return Message{}, err
}
return m, nil
}
// UseLogger specifies the Logger that that the decoder should use to log the
// message decode to.
func (d *Decoder) UseLogger(logger aws.Logger) {
d.logger = logger
}
func logMessageDecode(logger aws.Logger, msgBuf *bytes.Buffer, msg Message, decodeErr error) {
w := bytes.NewBuffer(nil)
defer func() { logger.Log(w.String()) }()
fmt.Fprintf(w, "Raw message:\n%s\n",
hex.Dump(msgBuf.Bytes()))
if decodeErr != nil {
fmt.Fprintf(w, "Decode error: %v\n", decodeErr)
return
}
rawMsg, err := msg.rawMessage()
if err != nil {
fmt.Fprintf(w, "failed to create raw message, %v\n", err)
return
}
decodedMsg := decodedMessage{
rawMessage: rawMsg,
Headers: decodedHeaders(msg.Headers),
}
fmt.Fprintf(w, "Decoded message:\n")
encoder := json.NewEncoder(w)
if err := encoder.Encode(decodedMsg); err != nil {
fmt.Fprintf(w, "failed to generate decoded message, %v\n", err)
}
}
func decodePrelude(r io.Reader, crc hash.Hash32) (messagePrelude, error) {
var p messagePrelude
var err error
p.Length, err = decodeUint32(r)
if err != nil {
return messagePrelude{}, err
}
p.HeadersLen, err = decodeUint32(r)
if err != nil {
return messagePrelude{}, err
}
if err := p.ValidateLens(); err != nil {
return messagePrelude{}, err
}
preludeCRC := crc.Sum32()
if err := validateCRC(r, preludeCRC); err != nil {
return messagePrelude{}, err
}
p.PreludeCRC = preludeCRC
return p, nil
}
func decodePayload(buf []byte, r io.Reader) ([]byte, error) {
w := bytes.NewBuffer(buf[0:0])
_, err := io.Copy(w, r)
return w.Bytes(), err
}
func decodeUint8(r io.Reader) (uint8, error) {
type byteReader interface {
ReadByte() (byte, error)
}
if br, ok := r.(byteReader); ok {
v, err := br.ReadByte()
return uint8(v), err
}
var b [1]byte
_, err := io.ReadFull(r, b[:])
return uint8(b[0]), err
}
func decodeUint16(r io.Reader) (uint16, error) {
var b [2]byte
bs := b[:]
_, err := io.ReadFull(r, bs)
if err != nil {
return 0, err
}
return binary.BigEndian.Uint16(bs), nil
}
func decodeUint32(r io.Reader) (uint32, error) {
var b [4]byte
bs := b[:]
_, err := io.ReadFull(r, bs)
if err != nil {
return 0, err
}
return binary.BigEndian.Uint32(bs), nil
}
func decodeUint64(r io.Reader) (uint64, error) {
var b [8]byte
bs := b[:]
_, err := io.ReadFull(r, bs)
if err != nil {
return 0, err
}
return binary.BigEndian.Uint64(bs), nil
}
func validateCRC(r io.Reader, expect uint32) error {
msgCRC, err := decodeUint32(r)
if err != nil {
return err
}
if msgCRC != expect {
return ChecksumError{}
}
return nil
}
@@ -0,0 +1,168 @@
package eventstream
import (
"bytes"
"encoding/hex"
"os"
"path/filepath"
"reflect"
"testing"
)
func TestWriteEncodedFromDecoded(t *testing.T) {
cases, err := readPositiveTests("testdata")
if err != nil {
t.Fatalf("failed to load positive tests, %v", err)
}
for _, c := range cases {
f, err := os.Create(filepath.Join("testdata", "encoded", "positive", c.Name))
if err != nil {
t.Fatalf("failed to open %q, %v", c.Name, err)
}
defer f.Close()
encoder := NewEncoder(f)
msg := c.Decoded.Message()
if err := encoder.Encode(msg); err != nil {
t.Errorf("failed to encode %q, %v", c.Name, err)
}
}
}
func TestDecoder_Decode(t *testing.T) {
cases, err := readPositiveTests("testdata")
if err != nil {
t.Fatalf("failed to load positive tests, %v", err)
}
for _, c := range cases {
decoder := NewDecoder(bytes.NewBuffer(c.Encoded))
msg, err := decoder.Decode(nil)
if err != nil {
t.Fatalf("%s, expect no decode error, got %v", c.Name, err)
}
raw, err := msg.rawMessage() // rawMessage will fail if payload read CRC fails
if err != nil {
t.Fatalf("%s, failed to get raw decoded message %v", c.Name, err)
}
if e, a := c.Decoded.Length, raw.Length; e != a {
t.Errorf("%s, expect %v length, got %v", c.Name, e, a)
}
if e, a := c.Decoded.HeadersLen, raw.HeadersLen; e != a {
t.Errorf("%s, expect %v HeadersLen, got %v", c.Name, e, a)
}
if e, a := c.Decoded.PreludeCRC, raw.PreludeCRC; e != a {
t.Errorf("%s, expect %v PreludeCRC, got %v", c.Name, e, a)
}
if e, a := Headers(c.Decoded.Headers), msg.Headers; !reflect.DeepEqual(e, a) {
t.Errorf("%s, expect %v headers, got %v", c.Name, e, a)
}
if e, a := c.Decoded.Payload, raw.Payload; !bytes.Equal(e, a) {
t.Errorf("%s, expect %v payload, got %v", c.Name, e, a)
}
if e, a := c.Decoded.CRC, raw.CRC; e != a {
t.Errorf("%s, expect %v CRC, got %v", c.Name, e, a)
}
}
}
func TestDecoder_Decode_Negative(t *testing.T) {
cases, err := readNegativeTests("testdata")
if err != nil {
t.Fatalf("failed to load negative tests, %v", err)
}
for _, c := range cases {
decoder := NewDecoder(bytes.NewBuffer(c.Encoded))
msg, err := decoder.Decode(nil)
if err == nil {
rawMsg, rawMsgErr := msg.rawMessage()
t.Fatalf("%s, expect error, got none, %s,\n%s\n%#v, %v\n", c.Name,
c.Err, hex.Dump(c.Encoded), rawMsg, rawMsgErr)
}
}
}
var testEncodedMsg = []byte{0, 0, 0, 61, 0, 0, 0, 32, 7, 253, 131, 150, 12, 99, 111, 110, 116, 101, 110, 116, 45, 116, 121, 112, 101, 7, 0, 16, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 106, 115, 111, 110, 123, 39, 102, 111, 111, 39, 58, 39, 98, 97, 114, 39, 125, 141, 156, 8, 177}
func TestDecoder_DecodeMultipleMessages(t *testing.T) {
const (
expectMsgCount = 10
expectPayloadLen = 13
)
r := bytes.NewBuffer(nil)
for i := 0; i < expectMsgCount; i++ {
r.Write(testEncodedMsg)
}
decoder := NewDecoder(r)
var err error
var msg Message
var count int
for {
msg, err = decoder.Decode(nil)
if err != nil {
break
}
count++
if e, a := expectPayloadLen, len(msg.Payload); e != a {
t.Errorf("expect %v payload len, got %v", e, a)
}
if e, a := []byte(`{'foo':'bar'}`), msg.Payload; !bytes.Equal(e, a) {
t.Errorf("expect %v payload, got %v", e, a)
}
}
type causer interface {
Cause() error
}
if err != nil && count != expectMsgCount {
t.Fatalf("expect, no error, got %v", err)
}
if e, a := expectMsgCount, count; e != a {
t.Errorf("expect %v messages read, got %v", e, a)
}
}
func BenchmarkDecode(b *testing.B) {
r := bytes.NewReader(testEncodedMsg)
decoder := NewDecoder(r)
payloadBuf := make([]byte, 0, 5*1024)
b.ResetTimer()
for i := 0; i < b.N; i++ {
msg, err := decoder.Decode(payloadBuf)
if err != nil {
b.Fatal(err)
}
// Release the payload buffer
payloadBuf = msg.Payload[0:0]
r.Seek(0, 0)
}
}
func BenchmarkDecode_NoPayloadBuf(b *testing.B) {
r := bytes.NewReader(testEncodedMsg)
decoder := NewDecoder(r)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := decoder.Decode(nil)
if err != nil {
b.Fatal(err)
}
r.Seek(0, 0)
}
}
+114
View File
@@ -0,0 +1,114 @@
package eventstream
import (
"bytes"
"encoding/binary"
"hash"
"hash/crc32"
"io"
)
// Encoder provides EventStream message encoding.
type Encoder struct {
w io.Writer
headersBuf *bytes.Buffer
}
// NewEncoder initializes and returns an Encoder to encode Event Stream
// messages to an io.Writer.
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{
w: w,
headersBuf: bytes.NewBuffer(nil),
}
}
// Encode encodes a single EventStream message to the io.Writer the Encoder
// was created with. An error is returned if writing the message fails.
func (e *Encoder) Encode(msg Message) error {
e.headersBuf.Reset()
err := encodeHeaders(e.headersBuf, msg.Headers)
if err != nil {
return err
}
crc := crc32.New(crc32IEEETable)
hashWriter := io.MultiWriter(e.w, crc)
headersLen := uint32(e.headersBuf.Len())
payloadLen := uint32(len(msg.Payload))
if err := encodePrelude(hashWriter, crc, headersLen, payloadLen); err != nil {
return err
}
if headersLen > 0 {
if _, err := io.Copy(hashWriter, e.headersBuf); err != nil {
return err
}
}
if payloadLen > 0 {
if _, err := hashWriter.Write(msg.Payload); err != nil {
return err
}
}
msgCRC := crc.Sum32()
return binary.Write(e.w, binary.BigEndian, msgCRC)
}
func encodePrelude(w io.Writer, crc hash.Hash32, headersLen, payloadLen uint32) error {
p := messagePrelude{
Length: minMsgLen + headersLen + payloadLen,
HeadersLen: headersLen,
}
if err := p.ValidateLens(); err != nil {
return err
}
err := binaryWriteFields(w, binary.BigEndian,
p.Length,
p.HeadersLen,
)
if err != nil {
return err
}
p.PreludeCRC = crc.Sum32()
err = binary.Write(w, binary.BigEndian, p.PreludeCRC)
if err != nil {
return err
}
return nil
}
func encodeHeaders(w io.Writer, headers Headers) error {
for _, h := range headers {
hn := headerName{
Len: uint8(len(h.Name)),
}
copy(hn.Name[:hn.Len], h.Name)
if err := hn.encode(w); err != nil {
return err
}
if err := h.Value.encode(w); err != nil {
return err
}
}
return nil
}
func binaryWriteFields(w io.Writer, order binary.ByteOrder, vs ...interface{}) error {
for _, v := range vs {
if err := binary.Write(w, order, v); err != nil {
return err
}
}
return nil
}
@@ -0,0 +1,50 @@
package eventstream
import (
"bytes"
"encoding/hex"
"reflect"
"testing"
)
func TestEncoder_Encode(t *testing.T) {
cases, err := readPositiveTests("testdata")
if err != nil {
t.Fatalf("failed to load positive tests, %v", err)
}
for _, c := range cases {
var w bytes.Buffer
encoder := NewEncoder(&w)
err = encoder.Encode(c.Decoded.Message())
if err != nil {
t.Fatalf("%s, failed to encode message, %v", c.Name, err)
}
if e, a := c.Encoded, w.Bytes(); !reflect.DeepEqual(e, a) {
t.Errorf("%s, expect:\n%v\nactual:\n%v\n", c.Name,
hex.Dump(e), hex.Dump(a))
}
}
}
func BenchmarkEncode(b *testing.B) {
var w bytes.Buffer
encoder := NewEncoder(&w)
msg := Message{
Headers: Headers{
{Name: "event-id", Value: Int16Value(123)},
},
Payload: []byte(`{"abc":123}`),
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := encoder.Encode(msg)
if err != nil {
b.Fatal(err)
}
}
}
+23
View File
@@ -0,0 +1,23 @@
package eventstream
import "fmt"
// LengthError provides the error for items being larger than a maximum length.
type LengthError struct {
Part string
Want int
Have int
Value interface{}
}
func (e LengthError) Error() string {
return fmt.Sprintf("%s length invalid, %d/%d, %v",
e.Part, e.Want, e.Have, e.Value)
}
// ChecksumError provides the error for message checksum invalidation errors.
type ChecksumError struct{}
func (e ChecksumError) Error() string {
return "message checksum mismatch"
}
@@ -0,0 +1,196 @@
package eventstreamapi
import (
"fmt"
"io"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/private/protocol"
"github.com/aws/aws-sdk-go/private/protocol/eventstream"
)
// Unmarshaler provides the interface for unmarshaling a EventStream
// message into a SDK type.
type Unmarshaler interface {
UnmarshalEvent(protocol.PayloadUnmarshaler, eventstream.Message) error
}
// EventStream headers with specific meaning to async API functionality.
const (
MessageTypeHeader = `:message-type` // Identifies type of message.
EventMessageType = `event`
ErrorMessageType = `error`
ExceptionMessageType = `exception`
// Message Events
EventTypeHeader = `:event-type` // Identifies message event type e.g. "Stats".
// Message Error
ErrorCodeHeader = `:error-code`
ErrorMessageHeader = `:error-message`
// Message Exception
ExceptionTypeHeader = `:exception-type`
)
// EventReader provides reading from the EventStream of an reader.
type EventReader struct {
reader io.ReadCloser
decoder *eventstream.Decoder
unmarshalerForEventType func(string) (Unmarshaler, error)
payloadUnmarshaler protocol.PayloadUnmarshaler
payloadBuf []byte
}
// NewEventReader returns a EventReader built from the reader and unmarshaler
// provided. Use ReadStream method to start reading from the EventStream.
func NewEventReader(
reader io.ReadCloser,
payloadUnmarshaler protocol.PayloadUnmarshaler,
unmarshalerForEventType func(string) (Unmarshaler, error),
) *EventReader {
return &EventReader{
reader: reader,
decoder: eventstream.NewDecoder(reader),
payloadUnmarshaler: payloadUnmarshaler,
unmarshalerForEventType: unmarshalerForEventType,
payloadBuf: make([]byte, 10*1024),
}
}
// UseLogger instructs the EventReader to use the logger and log level
// specified.
func (r *EventReader) UseLogger(logger aws.Logger, logLevel aws.LogLevelType) {
if logger != nil && logLevel.Matches(aws.LogDebugWithEventStreamBody) {
r.decoder.UseLogger(logger)
}
}
// ReadEvent attempts to read a message from the EventStream and return the
// unmarshaled event value that the message is for.
//
// For EventStream API errors check if the returned error satisfies the
// awserr.Error interface to get the error's Code and Message components.
//
// EventUnmarshalers called with EventStream messages must take copies of the
// message's Payload. The payload will is reused between events read.
func (r *EventReader) ReadEvent() (event interface{}, err error) {
msg, err := r.decoder.Decode(r.payloadBuf)
if err != nil {
return nil, err
}
defer func() {
// Reclaim payload buffer for next message read.
r.payloadBuf = msg.Payload[0:0]
}()
typ, err := GetHeaderString(msg, MessageTypeHeader)
if err != nil {
return nil, err
}
switch typ {
case EventMessageType:
return r.unmarshalEventMessage(msg)
case ExceptionMessageType:
err = r.unmarshalEventException(msg)
return nil, err
case ErrorMessageType:
return nil, r.unmarshalErrorMessage(msg)
default:
return nil, fmt.Errorf("unknown eventstream message type, %v", typ)
}
}
func (r *EventReader) unmarshalEventMessage(
msg eventstream.Message,
) (event interface{}, err error) {
eventType, err := GetHeaderString(msg, EventTypeHeader)
if err != nil {
return nil, err
}
ev, err := r.unmarshalerForEventType(eventType)
if err != nil {
return nil, err
}
err = ev.UnmarshalEvent(r.payloadUnmarshaler, msg)
if err != nil {
return nil, err
}
return ev, nil
}
func (r *EventReader) unmarshalEventException(
msg eventstream.Message,
) (err error) {
eventType, err := GetHeaderString(msg, ExceptionTypeHeader)
if err != nil {
return err
}
ev, err := r.unmarshalerForEventType(eventType)
if err != nil {
return err
}
err = ev.UnmarshalEvent(r.payloadUnmarshaler, msg)
if err != nil {
return err
}
var ok bool
err, ok = ev.(error)
if !ok {
err = messageError{
code: "SerializationError",
msg: fmt.Sprintf(
"event stream exception %s mapped to non-error %T, %v",
eventType, ev, ev,
),
}
}
return err
}
func (r *EventReader) unmarshalErrorMessage(msg eventstream.Message) (err error) {
var msgErr messageError
msgErr.code, err = GetHeaderString(msg, ErrorCodeHeader)
if err != nil {
return err
}
msgErr.msg, err = GetHeaderString(msg, ErrorMessageHeader)
if err != nil {
return err
}
return msgErr
}
// Close closes the EventReader's EventStream reader.
func (r *EventReader) Close() error {
return r.reader.Close()
}
// GetHeaderString returns the value of the header as a string. If the header
// is not set or the value is not a string an error will be returned.
func GetHeaderString(msg eventstream.Message, headerName string) (string, error) {
headerVal := msg.Headers.Get(headerName)
if headerVal == nil {
return "", fmt.Errorf("error header %s not present", headerName)
}
v, ok := headerVal.Get().(string)
if !ok {
return "", fmt.Errorf("error header value is not a string, %T", headerVal)
}
return v, nil
}
@@ -0,0 +1,253 @@
package eventstreamapi
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"testing"
"github.com/aws/aws-sdk-go/aws/request"
"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/restjson"
)
var eventMessageTypeHeader = eventstream.Header{
Name: MessageTypeHeader,
Value: eventstream.StringValue(EventMessageType),
}
func TestEventReader(t *testing.T) {
stream := createStream(
eventstream.Message{
Headers: eventstream.Headers{
eventMessageTypeHeader,
eventstream.Header{
Name: EventTypeHeader,
Value: eventstream.StringValue("eventABC"),
},
},
},
eventstream.Message{
Headers: eventstream.Headers{
eventMessageTypeHeader,
eventstream.Header{
Name: EventTypeHeader,
Value: eventstream.StringValue("eventEFG"),
},
},
},
)
var unmarshalers request.HandlerList
unmarshalers.PushBackNamed(restjson.UnmarshalHandler)
eventReader := NewEventReader(stream,
protocol.HandlerPayloadUnmarshal{
Unmarshalers: unmarshalers,
},
unmarshalerForEventType,
)
event, err := eventReader.ReadEvent()
if err != nil {
t.Fatalf("expect no error, got %v", err)
}
if event == nil {
t.Fatalf("expect event got none")
}
event, err = eventReader.ReadEvent()
if err == nil {
t.Fatalf("expect error for unknown event, got none")
}
if event != nil {
t.Fatalf("expect no event, got %T, %v", event, event)
}
}
func TestEventReader_Error(t *testing.T) {
stream := createStream(
eventstream.Message{
Headers: eventstream.Headers{
eventstream.Header{
Name: MessageTypeHeader,
Value: eventstream.StringValue(ErrorMessageType),
},
eventstream.Header{
Name: ErrorCodeHeader,
Value: eventstream.StringValue("errorCode"),
},
eventstream.Header{
Name: ErrorMessageHeader,
Value: eventstream.StringValue("error message occur"),
},
},
},
)
var unmarshalers request.HandlerList
unmarshalers.PushBackNamed(restjson.UnmarshalHandler)
eventReader := NewEventReader(stream,
protocol.HandlerPayloadUnmarshal{
Unmarshalers: unmarshalers,
},
unmarshalerForEventType,
)
event, err := eventReader.ReadEvent()
if err == nil {
t.Fatalf("expect error got none")
}
if event != nil {
t.Fatalf("expect no event, got %v", event)
}
if e, a := "errorCode: error message occur", err.Error(); e != a {
t.Errorf("expect %v error, got %v", e, a)
}
}
func TestEventReader_Exception(t *testing.T) {
eventMsgs := []eventstream.Message{
{
Headers: eventstream.Headers{
eventstream.Header{
Name: MessageTypeHeader,
Value: eventstream.StringValue(ExceptionMessageType),
},
eventstream.Header{
Name: ExceptionTypeHeader,
Value: eventstream.StringValue("exception"),
},
},
Payload: []byte(`{"message":"exception message"}`),
},
}
stream := createStream(eventMsgs...)
var unmarshalers request.HandlerList
unmarshalers.PushBackNamed(restjson.UnmarshalHandler)
eventReader := NewEventReader(stream,
protocol.HandlerPayloadUnmarshal{
Unmarshalers: unmarshalers,
},
unmarshalerForEventType,
)
event, err := eventReader.ReadEvent()
if err == nil {
t.Fatalf("expect error got none")
}
if event != nil {
t.Fatalf("expect no event, got %v", event)
}
et := err.(*exceptionType)
if e, a := string(eventMsgs[0].Payload), string(et.Payload); e != a {
t.Errorf("expect %v payload, got %v", e, a)
}
}
func BenchmarkEventReader(b *testing.B) {
var buf bytes.Buffer
encoder := eventstream.NewEncoder(&buf)
msg := eventstream.Message{
Headers: eventstream.Headers{
eventMessageTypeHeader,
eventstream.Header{
Name: EventTypeHeader,
Value: eventstream.StringValue("eventABC"),
},
},
}
if err := encoder.Encode(msg); err != nil {
b.Fatalf("failed to encode message, %v", err)
}
stream := bytes.NewReader(buf.Bytes())
var unmarshalers request.HandlerList
unmarshalers.PushBackNamed(restjson.UnmarshalHandler)
eventReader := NewEventReader(ioutil.NopCloser(stream),
protocol.HandlerPayloadUnmarshal{
Unmarshalers: unmarshalers,
},
unmarshalerForEventType,
)
b.ResetTimer()
for i := 0; i < b.N; i++ {
stream.Seek(0, 0)
event, err := eventReader.ReadEvent()
if err != nil {
b.Fatalf("expect no error, got %v", err)
}
if event == nil {
b.Fatalf("expect event got none")
}
}
}
func unmarshalerForEventType(eventType string) (Unmarshaler, error) {
switch eventType {
case "eventABC":
return &eventABC{}, nil
case "exception":
return &exceptionType{}, nil
default:
return nil, fmt.Errorf("unknown event type, %v", eventType)
}
}
type eventABC struct {
_ struct{}
HeaderField string
Payload []byte
}
func (e *eventABC) UnmarshalEvent(
unmarshaler protocol.PayloadUnmarshaler,
msg eventstream.Message,
) error {
return nil
}
func createStream(msgs ...eventstream.Message) io.ReadCloser {
w := bytes.NewBuffer(nil)
encoder := eventstream.NewEncoder(w)
for _, msg := range msgs {
if err := encoder.Encode(msg); err != nil {
panic("createStream failed, " + err.Error())
}
}
return ioutil.NopCloser(w)
}
type exceptionType struct {
Payload []byte
}
func (e exceptionType) Error() string {
return fmt.Sprintf("exception error message")
}
func (e *exceptionType) UnmarshalEvent(
unmarshaler protocol.PayloadUnmarshaler,
msg eventstream.Message,
) error {
e.Payload = msg.Payload
return nil
}
@@ -0,0 +1,24 @@
package eventstreamapi
import "fmt"
type messageError struct {
code string
msg string
}
func (e messageError) Code() string {
return e.code
}
func (e messageError) Message() string {
return e.msg
}
func (e messageError) Error() string {
return fmt.Sprintf("%s: %s", e.code, e.msg)
}
func (e messageError) OrigErr() error {
return nil
}
@@ -0,0 +1,17 @@
// +build !go1.10
package eventstreamtest
import (
"net/http"
"net/http/httptest"
)
// /x/net/http2 is only available for the latest two versions of Go. Any Go
// version older than that cannot use the utility to configure the http2
// server.
func setupServer(server *httptest.Server, useH2 bool) *http.Client {
server.Start()
return nil
}
@@ -0,0 +1,40 @@
// +build go1.10
package eventstreamtest
import (
"crypto/tls"
"net/http"
"net/http/httptest"
"golang.org/x/net/http2"
)
// /x/net/http2 is only available for the latest two versions of Go. Any Go
// version older than that cannot use the utility to configure the http2
// server.
func setupServer(server *httptest.Server, useH2 bool) *http.Client {
server.Config.TLSConfig = &tls.Config{
InsecureSkipVerify: true,
}
clientTrans := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
if useH2 {
http2.ConfigureServer(server.Config, nil)
http2.ConfigureTransport(clientTrans)
server.Config.TLSConfig.NextProtos = []string{http2.NextProtoTLS}
clientTrans.TLSClientConfig.NextProtos = []string{http2.NextProtoTLS}
}
server.TLS = server.Config.TLSConfig
server.StartTLS()
return &http.Client{
Transport: clientTrans,
}
}
@@ -0,0 +1,101 @@
package eventstreamtest
import (
"bytes"
"fmt"
"io"
"net/http"
"net/http/httptest"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/awstesting/unit"
"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/eventstreamapi"
)
// ServeEventStream provides serving EventStream messages from a HTTP server to
// the client. The events are sent sequentially to the client without delay.
type ServeEventStream struct {
T *testing.T
Events []eventstream.Message
}
func (s ServeEventStream) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
encoder := eventstream.NewEncoder(flushWriter{w})
for _, event := range s.Events {
encoder.Encode(event)
}
}
// SetupEventStreamSession creates a HTTP server SDK session for communicating
// with that server to be used for EventStream APIs. If HTTP/2 is enabled the
// server/client will only attempt to use HTTP/2.
func SetupEventStreamSession(
t *testing.T, handler http.Handler, h2 bool,
) (sess *session.Session, cleanupFn func(), err error) {
server := httptest.NewUnstartedServer(handler)
client := setupServer(server, h2)
cleanupFn = func() {
server.Close()
}
sess, err = session.NewSession(unit.Session.Config, &aws.Config{
Endpoint: &server.URL,
DisableParamValidation: aws.Bool(true),
HTTPClient: client,
// LogLevel: aws.LogLevel(aws.LogDebugWithEventStreamBody),
})
if err != nil {
return nil, nil, err
}
return sess, cleanupFn, nil
}
type flushWriter struct {
w io.Writer
}
func (fw flushWriter) Write(p []byte) (n int, err error) {
n, err = fw.w.Write(p)
if f, ok := fw.w.(http.Flusher); ok {
f.Flush()
}
return
}
// MarshalEventPayload marshals a SDK API shape into its associated wire
// protocol payload.
func MarshalEventPayload(
payloadMarshaler protocol.PayloadMarshaler,
v interface{},
) []byte {
var w bytes.Buffer
err := payloadMarshaler.MarshalPayload(&w, v)
if err != nil {
panic(fmt.Sprintf("failed to marshal event %T, %v", v, v))
}
return w.Bytes()
}
// EventMessageTypeHeader is an event message type header for specifying an
// event is an message type.
var EventMessageTypeHeader = eventstream.Header{
Name: eventstreamapi.MessageTypeHeader,
Value: eventstream.StringValue(eventstreamapi.EventMessageType),
}
// EventExceptionTypeHeader is an event exception type header for specifying an
// event is an exeption type.
var EventExceptionTypeHeader = eventstream.Header{
Name: eventstreamapi.MessageTypeHeader,
Value: eventstream.StringValue(eventstreamapi.ExceptionMessageType),
}
+166
View File
@@ -0,0 +1,166 @@
package eventstream
import (
"encoding/binary"
"fmt"
"io"
)
// Headers are a collection of EventStream header values.
type Headers []Header
// Header is a single EventStream Key Value header pair.
type Header struct {
Name string
Value Value
}
// Set associates the name with a value. If the header name already exists in
// the Headers the value will be replaced with the new one.
func (hs *Headers) Set(name string, value Value) {
var i int
for ; i < len(*hs); i++ {
if (*hs)[i].Name == name {
(*hs)[i].Value = value
return
}
}
*hs = append(*hs, Header{
Name: name, Value: value,
})
}
// Get returns the Value associated with the header. Nil is returned if the
// value does not exist.
func (hs Headers) Get(name string) Value {
for i := 0; i < len(hs); i++ {
if h := hs[i]; h.Name == name {
return h.Value
}
}
return nil
}
// Del deletes the value in the Headers if it exists.
func (hs *Headers) Del(name string) {
for i := 0; i < len(*hs); i++ {
if (*hs)[i].Name == name {
copy((*hs)[i:], (*hs)[i+1:])
(*hs) = (*hs)[:len(*hs)-1]
}
}
}
func decodeHeaders(r io.Reader) (Headers, error) {
hs := Headers{}
for {
name, err := decodeHeaderName(r)
if err != nil {
if err == io.EOF {
// EOF while getting header name means no more headers
break
}
return nil, err
}
value, err := decodeHeaderValue(r)
if err != nil {
return nil, err
}
hs.Set(name, value)
}
return hs, nil
}
func decodeHeaderName(r io.Reader) (string, error) {
var n headerName
var err error
n.Len, err = decodeUint8(r)
if err != nil {
return "", err
}
name := n.Name[:n.Len]
if _, err := io.ReadFull(r, name); err != nil {
return "", err
}
return string(name), nil
}
func decodeHeaderValue(r io.Reader) (Value, error) {
var raw rawValue
typ, err := decodeUint8(r)
if err != nil {
return nil, err
}
raw.Type = valueType(typ)
var v Value
switch raw.Type {
case trueValueType:
v = BoolValue(true)
case falseValueType:
v = BoolValue(false)
case int8ValueType:
var tv Int8Value
err = tv.decode(r)
v = tv
case int16ValueType:
var tv Int16Value
err = tv.decode(r)
v = tv
case int32ValueType:
var tv Int32Value
err = tv.decode(r)
v = tv
case int64ValueType:
var tv Int64Value
err = tv.decode(r)
v = tv
case bytesValueType:
var tv BytesValue
err = tv.decode(r)
v = tv
case stringValueType:
var tv StringValue
err = tv.decode(r)
v = tv
case timestampValueType:
var tv TimestampValue
err = tv.decode(r)
v = tv
case uuidValueType:
var tv UUIDValue
err = tv.decode(r)
v = tv
default:
panic(fmt.Sprintf("unknown value type %d", raw.Type))
}
// Error could be EOF, let caller deal with it
return v, err
}
const maxHeaderNameLen = 255
type headerName struct {
Len uint8
Name [maxHeaderNameLen]byte
}
func (v headerName) encode(w io.Writer) error {
if err := binary.Write(w, binary.BigEndian, v.Len); err != nil {
return err
}
_, err := w.Write(v.Name[:v.Len])
return err
}
@@ -0,0 +1,66 @@
package eventstream
import (
"reflect"
"testing"
"time"
)
func TestHeaders_Set(t *testing.T) {
expect := Headers{
{Name: "ABC", Value: StringValue("123")},
{Name: "EFG", Value: TimestampValue(time.Time{})},
}
var actual Headers
actual.Set("ABC", Int32Value(123))
actual.Set("ABC", StringValue("123")) // replace case
actual.Set("EFG", TimestampValue(time.Time{}))
if e, a := expect, actual; !reflect.DeepEqual(e, a) {
t.Errorf("expect %v headers, got %v", e, a)
}
}
func TestHeaders_Get(t *testing.T) {
headers := Headers{
{Name: "ABC", Value: StringValue("123")},
{Name: "EFG", Value: TimestampValue(time.Time{})},
}
cases := []struct {
Name string
Value Value
}{
{Name: "ABC", Value: StringValue("123")},
{Name: "EFG", Value: TimestampValue(time.Time{})},
{Name: "NotFound"},
}
for i, c := range cases {
actual := headers.Get(c.Name)
if e, a := c.Value, actual; !reflect.DeepEqual(e, a) {
t.Errorf("%d, expect %v value, got %v", i, e, a)
}
}
}
func TestHeaders_Del(t *testing.T) {
headers := Headers{
{Name: "ABC", Value: StringValue("123")},
{Name: "EFG", Value: TimestampValue(time.Time{})},
{Name: "HIJ", Value: StringValue("123")},
{Name: "KML", Value: TimestampValue(time.Time{})},
}
expectAfterDel := Headers{
{Name: "EFG", Value: TimestampValue(time.Time{})},
}
headers.Del("HIJ")
headers.Del("ABC")
headers.Del("KML")
if e, a := expectAfterDel, headers; !reflect.DeepEqual(e, a) {
t.Errorf("expect %v headers, got %v", e, a)
}
}
@@ -0,0 +1,501 @@
package eventstream
import (
"encoding/base64"
"encoding/binary"
"fmt"
"io"
"strconv"
"time"
)
const maxHeaderValueLen = 1<<15 - 1 // 2^15-1 or 32KB - 1
// valueType is the EventStream header value type.
type valueType uint8
// Header value types
const (
trueValueType valueType = iota
falseValueType
int8ValueType // Byte
int16ValueType // Short
int32ValueType // Integer
int64ValueType // Long
bytesValueType
stringValueType
timestampValueType
uuidValueType
)
func (t valueType) String() string {
switch t {
case trueValueType:
return "bool"
case falseValueType:
return "bool"
case int8ValueType:
return "int8"
case int16ValueType:
return "int16"
case int32ValueType:
return "int32"
case int64ValueType:
return "int64"
case bytesValueType:
return "byte_array"
case stringValueType:
return "string"
case timestampValueType:
return "timestamp"
case uuidValueType:
return "uuid"
default:
return fmt.Sprintf("unknown value type %d", uint8(t))
}
}
type rawValue struct {
Type valueType
Len uint16 // Only set for variable length slices
Value []byte // byte representation of value, BigEndian encoding.
}
func (r rawValue) encodeScalar(w io.Writer, v interface{}) error {
return binaryWriteFields(w, binary.BigEndian,
r.Type,
v,
)
}
func (r rawValue) encodeFixedSlice(w io.Writer, v []byte) error {
binary.Write(w, binary.BigEndian, r.Type)
_, err := w.Write(v)
return err
}
func (r rawValue) encodeBytes(w io.Writer, v []byte) error {
if len(v) > maxHeaderValueLen {
return LengthError{
Part: "header value",
Want: maxHeaderValueLen, Have: len(v),
Value: v,
}
}
r.Len = uint16(len(v))
err := binaryWriteFields(w, binary.BigEndian,
r.Type,
r.Len,
)
if err != nil {
return err
}
_, err = w.Write(v)
return err
}
func (r rawValue) encodeString(w io.Writer, v string) error {
if len(v) > maxHeaderValueLen {
return LengthError{
Part: "header value",
Want: maxHeaderValueLen, Have: len(v),
Value: v,
}
}
r.Len = uint16(len(v))
type stringWriter interface {
WriteString(string) (int, error)
}
err := binaryWriteFields(w, binary.BigEndian,
r.Type,
r.Len,
)
if err != nil {
return err
}
if sw, ok := w.(stringWriter); ok {
_, err = sw.WriteString(v)
} else {
_, err = w.Write([]byte(v))
}
return err
}
func decodeFixedBytesValue(r io.Reader, buf []byte) error {
_, err := io.ReadFull(r, buf)
return err
}
func decodeBytesValue(r io.Reader) ([]byte, error) {
var raw rawValue
var err error
raw.Len, err = decodeUint16(r)
if err != nil {
return nil, err
}
buf := make([]byte, raw.Len)
_, err = io.ReadFull(r, buf)
if err != nil {
return nil, err
}
return buf, nil
}
func decodeStringValue(r io.Reader) (string, error) {
v, err := decodeBytesValue(r)
return string(v), err
}
// Value represents the abstract header value.
type Value interface {
Get() interface{}
String() string
valueType() valueType
encode(io.Writer) error
}
// An BoolValue provides eventstream encoding, and representation
// of a Go bool value.
type BoolValue bool
// Get returns the underlying type
func (v BoolValue) Get() interface{} {
return bool(v)
}
// valueType returns the EventStream header value type value.
func (v BoolValue) valueType() valueType {
if v {
return trueValueType
}
return falseValueType
}
func (v BoolValue) String() string {
return strconv.FormatBool(bool(v))
}
// encode encodes the BoolValue into an eventstream binary value
// representation.
func (v BoolValue) encode(w io.Writer) error {
return binary.Write(w, binary.BigEndian, v.valueType())
}
// An Int8Value provides eventstream encoding, and representation of a Go
// int8 value.
type Int8Value int8
// Get returns the underlying value.
func (v Int8Value) Get() interface{} {
return int8(v)
}
// valueType returns the EventStream header value type value.
func (Int8Value) valueType() valueType {
return int8ValueType
}
func (v Int8Value) String() string {
return fmt.Sprintf("0x%02x", int8(v))
}
// encode encodes the Int8Value into an eventstream binary value
// representation.
func (v Int8Value) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
return raw.encodeScalar(w, v)
}
func (v *Int8Value) decode(r io.Reader) error {
n, err := decodeUint8(r)
if err != nil {
return err
}
*v = Int8Value(n)
return nil
}
// An Int16Value provides eventstream encoding, and representation of a Go
// int16 value.
type Int16Value int16
// Get returns the underlying value.
func (v Int16Value) Get() interface{} {
return int16(v)
}
// valueType returns the EventStream header value type value.
func (Int16Value) valueType() valueType {
return int16ValueType
}
func (v Int16Value) String() string {
return fmt.Sprintf("0x%04x", int16(v))
}
// encode encodes the Int16Value into an eventstream binary value
// representation.
func (v Int16Value) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
return raw.encodeScalar(w, v)
}
func (v *Int16Value) decode(r io.Reader) error {
n, err := decodeUint16(r)
if err != nil {
return err
}
*v = Int16Value(n)
return nil
}
// An Int32Value provides eventstream encoding, and representation of a Go
// int32 value.
type Int32Value int32
// Get returns the underlying value.
func (v Int32Value) Get() interface{} {
return int32(v)
}
// valueType returns the EventStream header value type value.
func (Int32Value) valueType() valueType {
return int32ValueType
}
func (v Int32Value) String() string {
return fmt.Sprintf("0x%08x", int32(v))
}
// encode encodes the Int32Value into an eventstream binary value
// representation.
func (v Int32Value) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
return raw.encodeScalar(w, v)
}
func (v *Int32Value) decode(r io.Reader) error {
n, err := decodeUint32(r)
if err != nil {
return err
}
*v = Int32Value(n)
return nil
}
// An Int64Value provides eventstream encoding, and representation of a Go
// int64 value.
type Int64Value int64
// Get returns the underlying value.
func (v Int64Value) Get() interface{} {
return int64(v)
}
// valueType returns the EventStream header value type value.
func (Int64Value) valueType() valueType {
return int64ValueType
}
func (v Int64Value) String() string {
return fmt.Sprintf("0x%016x", int64(v))
}
// encode encodes the Int64Value into an eventstream binary value
// representation.
func (v Int64Value) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
return raw.encodeScalar(w, v)
}
func (v *Int64Value) decode(r io.Reader) error {
n, err := decodeUint64(r)
if err != nil {
return err
}
*v = Int64Value(n)
return nil
}
// An BytesValue provides eventstream encoding, and representation of a Go
// byte slice.
type BytesValue []byte
// Get returns the underlying value.
func (v BytesValue) Get() interface{} {
return []byte(v)
}
// valueType returns the EventStream header value type value.
func (BytesValue) valueType() valueType {
return bytesValueType
}
func (v BytesValue) String() string {
return base64.StdEncoding.EncodeToString([]byte(v))
}
// encode encodes the BytesValue into an eventstream binary value
// representation.
func (v BytesValue) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
return raw.encodeBytes(w, []byte(v))
}
func (v *BytesValue) decode(r io.Reader) error {
buf, err := decodeBytesValue(r)
if err != nil {
return err
}
*v = BytesValue(buf)
return nil
}
// An StringValue provides eventstream encoding, and representation of a Go
// string.
type StringValue string
// Get returns the underlying value.
func (v StringValue) Get() interface{} {
return string(v)
}
// valueType returns the EventStream header value type value.
func (StringValue) valueType() valueType {
return stringValueType
}
func (v StringValue) String() string {
return string(v)
}
// encode encodes the StringValue into an eventstream binary value
// representation.
func (v StringValue) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
return raw.encodeString(w, string(v))
}
func (v *StringValue) decode(r io.Reader) error {
s, err := decodeStringValue(r)
if err != nil {
return err
}
*v = StringValue(s)
return nil
}
// An TimestampValue provides eventstream encoding, and representation of a Go
// timestamp.
type TimestampValue time.Time
// Get returns the underlying value.
func (v TimestampValue) Get() interface{} {
return time.Time(v)
}
// valueType returns the EventStream header value type value.
func (TimestampValue) valueType() valueType {
return timestampValueType
}
func (v TimestampValue) epochMilli() int64 {
nano := time.Time(v).UnixNano()
msec := nano / int64(time.Millisecond)
return msec
}
func (v TimestampValue) String() string {
msec := v.epochMilli()
return strconv.FormatInt(msec, 10)
}
// encode encodes the TimestampValue into an eventstream binary value
// representation.
func (v TimestampValue) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
msec := v.epochMilli()
return raw.encodeScalar(w, msec)
}
func (v *TimestampValue) decode(r io.Reader) error {
n, err := decodeUint64(r)
if err != nil {
return err
}
*v = TimestampValue(timeFromEpochMilli(int64(n)))
return nil
}
func timeFromEpochMilli(t int64) time.Time {
secs := t / 1e3
msec := t % 1e3
return time.Unix(secs, msec*int64(time.Millisecond)).UTC()
}
// An UUIDValue provides eventstream encoding, and representation of a UUID
// value.
type UUIDValue [16]byte
// Get returns the underlying value.
func (v UUIDValue) Get() interface{} {
return v[:]
}
// valueType returns the EventStream header value type value.
func (UUIDValue) valueType() valueType {
return uuidValueType
}
func (v UUIDValue) String() string {
return fmt.Sprintf(`%X-%X-%X-%X-%X`, v[0:4], v[4:6], v[6:8], v[8:10], v[10:])
}
// encode encodes the UUIDValue into an eventstream binary value
// representation.
func (v UUIDValue) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
return raw.encodeFixedSlice(w, v[:])
}
func (v *UUIDValue) decode(r io.Reader) error {
tv := (*v)[:]
return decodeFixedBytesValue(r, tv)
}
@@ -0,0 +1,203 @@
package eventstream
import (
"bytes"
"encoding/binary"
"io"
"reflect"
"testing"
"time"
)
func binWrite(v interface{}) []byte {
var w bytes.Buffer
binary.Write(&w, binary.BigEndian, v)
return w.Bytes()
}
var testValueEncodingCases = []struct {
Val Value
Expect []byte
Decode func(io.Reader) (Value, error)
}{
{
BoolValue(true),
[]byte{byte(trueValueType)},
nil,
},
{
BoolValue(false),
[]byte{byte(falseValueType)},
nil,
},
{
Int8Value(0x0f),
[]byte{byte(int8ValueType), 0x0f},
func(r io.Reader) (Value, error) {
var v Int8Value
err := v.decode(r)
return v, err
},
},
{
Int16Value(0x0f),
append([]byte{byte(int16ValueType)}, binWrite(int16(0x0f))...),
func(r io.Reader) (Value, error) {
var v Int16Value
err := v.decode(r)
return v, err
},
},
{
Int32Value(0x0f),
append([]byte{byte(int32ValueType)}, binWrite(int32(0x0f))...),
func(r io.Reader) (Value, error) {
var v Int32Value
err := v.decode(r)
return v, err
},
},
{
Int64Value(0x0f),
append([]byte{byte(int64ValueType)}, binWrite(int64(0x0f))...),
func(r io.Reader) (Value, error) {
var v Int64Value
err := v.decode(r)
return v, err
},
},
{
BytesValue([]byte{0, 1, 2, 3}),
[]byte{byte(bytesValueType), 0x00, 0x04, 0, 1, 2, 3},
func(r io.Reader) (Value, error) {
var v BytesValue
err := v.decode(r)
return v, err
},
},
{
StringValue("abc123"),
append([]byte{byte(stringValueType), 0, 6}, []byte("abc123")...),
func(r io.Reader) (Value, error) {
var v StringValue
err := v.decode(r)
return v, err
},
},
{
TimestampValue(
time.Date(2014, 04, 04, 0, 1, 0, 0, time.FixedZone("PDT", -7)),
),
append([]byte{byte(timestampValueType)}, binWrite(int64(1396569667000))...),
func(r io.Reader) (Value, error) {
var v TimestampValue
err := v.decode(r)
return v, err
},
},
{
UUIDValue(
[16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf},
),
[]byte{byte(uuidValueType), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf},
func(r io.Reader) (Value, error) {
var v UUIDValue
err := v.decode(r)
return v, err
},
},
}
func TestValue_MarshalValue(t *testing.T) {
for i, c := range testValueEncodingCases {
var w bytes.Buffer
if err := c.Val.encode(&w); err != nil {
t.Fatalf("%d, expect no error, got %v", i, err)
}
if e, a := c.Expect, w.Bytes(); !reflect.DeepEqual(e, a) {
t.Errorf("%d, expect %v, got %v", i, e, a)
}
}
}
func TestHeader_DecodeValues(t *testing.T) {
for i, c := range testValueEncodingCases {
r := bytes.NewBuffer(c.Expect)
v, err := decodeHeaderValue(r)
if err != nil {
t.Fatalf("%d, expect no error, got %v", i, err)
}
switch tv := v.(type) {
case TimestampValue:
exp := time.Time(c.Val.(TimestampValue))
if e, a := exp, time.Time(tv); !e.Equal(a) {
t.Errorf("%d, expect %v, got %v", i, e, a)
}
default:
if e, a := c.Val, v; !reflect.DeepEqual(e, a) {
t.Errorf("%d, expect %v, got %v", i, e, a)
}
}
}
}
func TestValue_Decode(t *testing.T) {
for i, c := range testValueEncodingCases {
if c.Decode == nil {
continue
}
r := bytes.NewBuffer(c.Expect)
r.ReadByte() // strip off Type field
v, err := c.Decode(r)
if err != nil {
t.Fatalf("%d, expect no error, got %v", i, err)
}
switch tv := v.(type) {
case TimestampValue:
exp := time.Time(c.Val.(TimestampValue))
if e, a := exp, time.Time(tv); !e.Equal(a) {
t.Errorf("%d, expect %v, got %v", i, e, a)
}
default:
if e, a := c.Val, v; !reflect.DeepEqual(e, a) {
t.Errorf("%d, expect %v, got %v", i, e, a)
}
}
}
}
func TestValue_String(t *testing.T) {
cases := []struct {
Val Value
Expect string
}{
{BoolValue(true), "true"},
{BoolValue(false), "false"},
{Int8Value(0x0f), "0x0f"},
{Int16Value(0x0f), "0x000f"},
{Int32Value(0x0f), "0x0000000f"},
{Int64Value(0x0f), "0x000000000000000f"},
{BytesValue([]byte{0, 1, 2, 3}), "AAECAw=="},
{StringValue("abc123"), "abc123"},
{TimestampValue(
time.Date(2014, 04, 04, 0, 1, 0, 0, time.FixedZone("PDT", -7)),
),
"1396569667000",
},
{UUIDValue([16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}),
"00010203-0405-0607-0809-0A0B0C0D0E0F",
},
}
for i, c := range cases {
if e, a := c.Expect, c.Val.String(); e != a {
t.Errorf("%d, expect %v, got %v", i, e, a)
}
}
}
@@ -0,0 +1,103 @@
package eventstream
import (
"bytes"
"encoding/binary"
"hash/crc32"
)
const preludeLen = 8
const preludeCRCLen = 4
const msgCRCLen = 4
const minMsgLen = preludeLen + preludeCRCLen + msgCRCLen
const maxPayloadLen = 1024 * 1024 * 16 // 16MB
const maxHeadersLen = 1024 * 128 // 128KB
const maxMsgLen = minMsgLen + maxHeadersLen + maxPayloadLen
var crc32IEEETable = crc32.MakeTable(crc32.IEEE)
// A Message provides the eventstream message representation.
type Message struct {
Headers Headers
Payload []byte
}
func (m *Message) rawMessage() (rawMessage, error) {
var raw rawMessage
if len(m.Headers) > 0 {
var headers bytes.Buffer
if err := encodeHeaders(&headers, m.Headers); err != nil {
return rawMessage{}, err
}
raw.Headers = headers.Bytes()
raw.HeadersLen = uint32(len(raw.Headers))
}
raw.Length = raw.HeadersLen + uint32(len(m.Payload)) + minMsgLen
hash := crc32.New(crc32IEEETable)
binaryWriteFields(hash, binary.BigEndian, raw.Length, raw.HeadersLen)
raw.PreludeCRC = hash.Sum32()
binaryWriteFields(hash, binary.BigEndian, raw.PreludeCRC)
if raw.HeadersLen > 0 {
hash.Write(raw.Headers)
}
// Read payload bytes and update hash for it as well.
if len(m.Payload) > 0 {
raw.Payload = m.Payload
hash.Write(raw.Payload)
}
raw.CRC = hash.Sum32()
return raw, nil
}
type messagePrelude struct {
Length uint32
HeadersLen uint32
PreludeCRC uint32
}
func (p messagePrelude) PayloadLen() uint32 {
return p.Length - p.HeadersLen - minMsgLen
}
func (p messagePrelude) ValidateLens() error {
if p.Length == 0 || p.Length > maxMsgLen {
return LengthError{
Part: "message prelude",
Want: maxMsgLen,
Have: int(p.Length),
}
}
if p.HeadersLen > maxHeadersLen {
return LengthError{
Part: "message headers",
Want: maxHeadersLen,
Have: int(p.HeadersLen),
}
}
if payloadLen := p.PayloadLen(); payloadLen > maxPayloadLen {
return LengthError{
Part: "message payload",
Want: maxPayloadLen,
Have: int(payloadLen),
}
}
return nil
}
type rawMessage struct {
messagePrelude
Headers []byte
Payload []byte
CRC uint32
}
@@ -0,0 +1,152 @@
package eventstream
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"testing"
)
type testCase struct {
Name string
Encoded []byte
Decoded decodedMessage
}
type testErrorCase struct {
Name string
Encoded []byte
Err string
}
type rawTestCase struct {
Name string
Encoded, Decoded []byte
}
func readRawTestCases(root, class string) (map[string]rawTestCase, error) {
encoded, err := readTests(filepath.Join(root, "encoded", class))
if err != nil {
return nil, err
}
decoded, err := readTests(filepath.Join(root, "decoded", class))
if err != nil {
return nil, err
}
if len(encoded) == 0 {
return nil, fmt.Errorf("expect encoded cases, found none")
}
if len(encoded) != len(decoded) {
return nil, fmt.Errorf("encoded and decoded sets different")
}
rawCases := map[string]rawTestCase{}
for name, encData := range encoded {
decData, ok := decoded[name]
if !ok {
return nil, fmt.Errorf("encoded %q case not found in decoded set", name)
}
rawCases[name] = rawTestCase{
Name: name,
Encoded: encData,
Decoded: decData,
}
}
return rawCases, nil
}
func readNegativeTests(root string) ([]testErrorCase, error) {
rawCases, err := readRawTestCases(root, "negative")
if err != nil {
return nil, err
}
cases := make([]testErrorCase, 0, len(rawCases))
for name, rawCase := range rawCases {
cases = append(cases, testErrorCase{
Name: name,
Encoded: rawCase.Encoded,
Err: string(rawCase.Decoded),
})
}
return cases, nil
}
func readPositiveTests(root string) ([]testCase, error) {
rawCases, err := readRawTestCases(root, "positive")
if err != nil {
return nil, err
}
cases := make([]testCase, 0, len(rawCases))
for name, rawCase := range rawCases {
var dec decodedMessage
if err := json.Unmarshal(rawCase.Decoded, &dec); err != nil {
return nil, fmt.Errorf("failed to decode %q, %v", name, err)
}
cases = append(cases, testCase{
Name: name,
Encoded: rawCase.Encoded,
Decoded: dec,
})
}
return cases, nil
}
func readTests(root string) (map[string][]byte, error) {
items, err := ioutil.ReadDir(root)
if err != nil {
return nil, fmt.Errorf("failed to read test suite %q dirs, %v", root, err)
}
cases := map[string][]byte{}
for _, item := range items {
if item.IsDir() {
continue
}
filename := filepath.Join(root, item.Name())
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("failed to read test_data file %q, %v", filename, err)
}
cases[item.Name()] = data
}
return cases, nil
}
func compareLines(t *testing.T, a, b []byte) bool {
as := bufio.NewScanner(bytes.NewBuffer(a))
bs := bufio.NewScanner(bytes.NewBuffer(b))
var failed bool
for {
if ab, bb := as.Scan(), bs.Scan(); ab != bb {
t.Errorf("expect a & b to have same number of lines")
return false
} else if !ab {
break
}
if v1, v2 := as.Text(), bs.Text(); v1 != v2 {
t.Errorf("expect %q to be %q", v1, v2)
failed = true
}
}
return !failed
}
@@ -0,0 +1 @@
Prelude checksum mismatch
@@ -0,0 +1 @@
Message checksum mismatch
@@ -0,0 +1 @@
Prelude checksum mismatch
@@ -0,0 +1 @@
Message checksum mismatch
@@ -0,0 +1,58 @@
{
"total_length": 204,
"headers_length": 175,
"prelude_crc": 263087306,
"headers": [ {
"name": "event-type",
"type": 4,
"value": 40972
},
{
"name": "content-type",
"type": 7,
"value": "YXBwbGljYXRpb24vanNvbg=="
},
{
"name": "bool false",
"type": 1,
"value": false
},
{
"name": "bool true",
"type": 0,
"value": true
},
{
"name": "byte",
"type": 2,
"value": -49
},
{
"name": "byte buf",
"type": 6,
"value": "SSdtIGEgbGl0dGxlIHRlYXBvdCE="
},
{
"name": "timestamp",
"type": 8,
"value": 8675309
},
{
"name": "int16",
"type": 3,
"value": 42
},
{
"name": "int64",
"type": 5,
"value": 42424242
},
{
"name": "uuid",
"type": 9,
"value": "AQIDBAUGBwgJCgsMDQ4PEA=="
}
],
"payload": "eydmb28nOidiYXInfQ==",
"message_crc": -1415188212
}
@@ -0,0 +1,8 @@
{
"total_length": 16,
"headers_length": 0,
"prelude_crc": 96618731,
"headers": [ ],
"payload": "",
"message_crc": 2107164927
}
@@ -0,0 +1,13 @@
{
"total_length": 45,
"headers_length": 16,
"prelude_crc": 1103373496,
"headers": [ {
"name": "event-type",
"type": 4,
"value": 40972
}
],
"payload": "eydmb28nOidiYXInfQ==",
"message_crc": 921993376
}
@@ -0,0 +1,8 @@
{
"total_length": 29,
"headers_length": 0,
"prelude_crc": -44921766,
"headers": [ ],
"payload": "eydmb28nOidiYXInfQ==",
"message_crc": -1016776394
}
@@ -0,0 +1,13 @@
{
"total_length": 61,
"headers_length": 32,
"prelude_crc": 134054806,
"headers": [ {
"name": "content-type",
"type": 7,
"value": "YXBwbGljYXRpb24vanNvbg=="
}
],
"payload": "eydmb28nOidiYXInfQ==",
"message_crc": -1919153999
}
+68
View File
@@ -0,0 +1,68 @@
package protocol
import (
"strings"
"github.com/aws/aws-sdk-go/aws/request"
)
// ValidateEndpointHostHandler is a request handler that will validate the
// request endpoint's hosts is a valid RFC 3986 host.
var ValidateEndpointHostHandler = request.NamedHandler{
Name: "awssdk.protocol.ValidateEndpointHostHandler",
Fn: func(r *request.Request) {
err := ValidateEndpointHost(r.Operation.Name, r.HTTPRequest.URL.Host)
if err != nil {
r.Error = err
}
},
}
// ValidateEndpointHost validates that the host string passed in is a valid RFC
// 3986 host. Returns error if the host is not valid.
func ValidateEndpointHost(opName, host string) error {
paramErrs := request.ErrInvalidParams{Context: opName}
labels := strings.Split(host, ".")
for i, label := range labels {
if i == len(labels)-1 && len(label) == 0 {
// Allow trailing dot for FQDN hosts.
continue
}
if !ValidHostLabel(label) {
paramErrs.Add(request.NewErrParamFormat(
"endpoint host label", "[a-zA-Z0-9-]{1,63}", label))
}
}
if len(host) > 255 {
paramErrs.Add(request.NewErrParamMaxLen(
"endpoint host", 255, host,
))
}
if paramErrs.Len() > 0 {
return paramErrs
}
return nil
}
// ValidHostLabel returns if the label is a valid RFC 3986 host label.
func ValidHostLabel(label string) bool {
if l := len(label); l == 0 || l > 63 {
return false
}
for _, r := range label {
switch {
case r >= '0' && r <= '9':
case r >= 'A' && r <= 'Z':
case r >= 'a' && r <= 'z':
case r == '-':
default:
return false
}
}
return true
}
+54
View File
@@ -0,0 +1,54 @@
package protocol
import (
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/request"
)
// HostPrefixHandlerName is the handler name for the host prefix request
// handler.
const HostPrefixHandlerName = "awssdk.endpoint.HostPrefixHandler"
// NewHostPrefixHandler constructs a build handler
func NewHostPrefixHandler(prefix string, labelsFn func() map[string]string) request.NamedHandler {
builder := HostPrefixBuilder{
Prefix: prefix,
LabelsFn: labelsFn,
}
return request.NamedHandler{
Name: HostPrefixHandlerName,
Fn: builder.Build,
}
}
// HostPrefixBuilder provides the request handler to expand and prepend
// the host prefix into the operation's request endpoint host.
type HostPrefixBuilder struct {
Prefix string
LabelsFn func() map[string]string
}
// Build updates the passed in Request with the HostPrefix template expanded.
func (h HostPrefixBuilder) Build(r *request.Request) {
if aws.BoolValue(r.Config.DisableEndpointHostPrefix) {
return
}
var labels map[string]string
if h.LabelsFn != nil {
labels = h.LabelsFn()
}
prefix := h.Prefix
for name, value := range labels {
prefix = strings.Replace(prefix, "{"+name+"}", value, -1)
}
r.HTTPRequest.URL.Host = prefix + r.HTTPRequest.URL.Host
if len(r.HTTPRequest.Host) > 0 {
r.HTTPRequest.Host = prefix + r.HTTPRequest.Host
}
}
+110
View File
@@ -0,0 +1,110 @@
// +build go1.7
package protocol
import (
"net/http"
"net/url"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/request"
)
func TestHostPrefixBuilder(t *testing.T) {
cases := map[string]struct {
URLHost string
ReqHost string
Prefix string
LabelsFn func() map[string]string
Disabled bool
ExpectURLHost string
ExpectReqHost string
}{
"no labels": {
URLHost: "service.region.amazonaws.com",
Prefix: "data-",
ExpectURLHost: "data-service.region.amazonaws.com",
},
"with labels": {
URLHost: "service.region.amazonaws.com",
Prefix: "{first}-{second}.",
LabelsFn: func() map[string]string {
return map[string]string{
"first": "abc",
"second": "123",
}
},
ExpectURLHost: "abc-123.service.region.amazonaws.com",
},
"with host prefix disabled": {
Disabled: true,
URLHost: "service.region.amazonaws.com",
Prefix: "{first}-{second}.",
LabelsFn: func() map[string]string {
return map[string]string{
"first": "abc",
"second": "123",
}
},
ExpectURLHost: "service.region.amazonaws.com",
},
"with duplicate labels": {
URLHost: "service.region.amazonaws.com",
Prefix: "{first}-{second}-{first}.",
LabelsFn: func() map[string]string {
return map[string]string{
"first": "abc",
"second": "123",
}
},
ExpectURLHost: "abc-123-abc.service.region.amazonaws.com",
},
"with unbracketed labels": {
URLHost: "service.region.amazonaws.com",
Prefix: "first-{second}.",
LabelsFn: func() map[string]string {
return map[string]string{
"first": "abc",
"second": "123",
}
},
ExpectURLHost: "first-123.service.region.amazonaws.com",
},
"with req host": {
URLHost: "service.region.amazonaws.com:1234",
ReqHost: "service.region.amazonaws.com",
Prefix: "data-",
ExpectURLHost: "data-service.region.amazonaws.com:1234",
ExpectReqHost: "data-service.region.amazonaws.com",
},
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
builder := HostPrefixBuilder{
Prefix: c.Prefix, LabelsFn: c.LabelsFn,
}
req := &request.Request{
Config: aws.Config{
DisableEndpointHostPrefix: aws.Bool(c.Disabled),
},
HTTPRequest: &http.Request{
Host: c.ReqHost,
URL: &url.URL{
Host: c.URLHost,
},
},
}
builder.Build(req)
if e, a := c.ExpectURLHost, req.HTTPRequest.URL.Host; e != a {
t.Errorf("expect URL host %v, got %v", e, a)
}
if e, a := c.ExpectReqHost, req.HTTPRequest.Host; e != a {
t.Errorf("expect request host %v, got %v", e, a)
}
})
}
}
+63
View File
@@ -0,0 +1,63 @@
// +build go1.7
package protocol
import (
"strconv"
"testing"
)
func TestValidHostLabel(t *testing.T) {
cases := []struct {
Input string
Valid bool
}{
{Input: "abc123", Valid: true},
{Input: "123", Valid: true},
{Input: "abc", Valid: true},
{Input: "123-abc", Valid: true},
{Input: "{thing}-abc", Valid: false},
{Input: "abc.123", Valid: false},
{Input: "abc/123", Valid: false},
{Input: "012345678901234567890123456789012345678901234567890123456789123", Valid: true},
{Input: "0123456789012345678901234567890123456789012345678901234567891234", Valid: false},
{Input: "", Valid: false},
}
for i, c := range cases {
t.Run(strconv.Itoa(i), func(t *testing.T) {
valid := ValidHostLabel(c.Input)
if e, a := c.Valid, valid; e != a {
t.Errorf("expect valid %v, got %v", e, a)
}
})
}
}
func TestValidateEndpointHostHandler(t *testing.T) {
cases := map[string]struct {
Input string
Valid bool
}{
"valid host": {Input: "abc.123", Valid: true},
"fqdn host": {Input: "abc.123.", Valid: true},
"empty label": {Input: "abc..", Valid: false},
"max host len": {
Input: "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.12345",
Valid: true,
},
"too long host": {
Input: "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456",
Valid: false,
},
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
err := ValidateEndpointHost("OpName", c.Input)
if e, a := c.Valid, err == nil; e != a {
t.Errorf("expect valid %v, got %v, %v", e, a, err)
}
})
}
}
+12 -5
View File
@@ -5,7 +5,6 @@ import (
"testing"
"github.com/aws/aws-sdk-go/private/protocol"
"github.com/stretchr/testify/assert"
)
func TestCanSetIdempotencyToken(t *testing.T) {
@@ -55,7 +54,9 @@ func TestCanSetIdempotencyToken(t *testing.T) {
v := reflect.Indirect(reflect.ValueOf(c.Case))
ty := v.Type()
canSet := protocol.CanSetIdempotencyToken(v.Field(0), ty.Field(0))
assert.Equal(t, c.CanSet, canSet, "Expect case %d can set to match", i)
if e, a := c.CanSet, canSet; e != a {
t.Errorf("%d, expect %v, got %v", i, e, a)
}
}
}
@@ -89,18 +90,24 @@ func TestSetIdempotencyToken(t *testing.T) {
v := reflect.Indirect(reflect.ValueOf(c.Case))
protocol.SetIdempotencyToken(v.Field(0))
assert.NotEmpty(t, v.Field(0).Interface(), "Expect case %d to be set", i)
if v.Field(0).Interface() == nil {
t.Errorf("%d, expect not nil", i)
}
}
}
func TestUUIDVersion4(t *testing.T) {
uuid := protocol.UUIDVersion4(make([]byte, 16))
assert.Equal(t, `00000000-0000-4000-8000-000000000000`, uuid)
if e, a := `00000000-0000-4000-8000-000000000000`, uuid; e != a {
t.Errorf("expect %v, got %v", e, a)
}
b := make([]byte, 16)
for i := 0; i < len(b); i++ {
b[i] = 1
}
uuid = protocol.UUIDVersion4(b)
assert.Equal(t, `01010101-0101-4101-8101-010101010101`, uuid)
if e, a := `01010101-0101-4101-8101-010101010101`, uuid; e != a {
t.Errorf("expect %v, got %v", e, a)
}
}
+11 -1
View File
@@ -216,7 +216,17 @@ func buildScalar(v reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) erro
default:
switch converted := value.Interface().(type) {
case time.Time:
buf.Write(strconv.AppendInt(scratch[:0], converted.UTC().Unix(), 10))
format := tag.Get("timestampFormat")
if len(format) == 0 {
format = protocol.UnixTimeFormatName
}
ts := protocol.FormatTime(format, converted)
if format != protocol.UnixTimeFormatName {
ts = `"` + ts + `"`
}
buf.WriteString(ts)
case []byte:
if !value.IsNil() {
buf.WriteByte('"')
@@ -2,11 +2,11 @@ package jsonutil_test
import (
"encoding/json"
"strings"
"testing"
"time"
"github.com/aws/aws-sdk-go/private/protocol/json/jsonutil"
"github.com/stretchr/testify/assert"
)
func S(s string) *string {
@@ -83,11 +83,19 @@ func TestBuildJSON(t *testing.T) {
for _, test := range jsonTests {
out, err := jsonutil.BuildJSON(test.in)
if test.err != "" {
assert.Error(t, err)
assert.Contains(t, err.Error(), test.err)
if err == nil {
t.Errorf("expect error")
}
if e, a := test.err, err.Error(); !strings.Contains(a, e) {
t.Errorf("expect %v, to contain %v", e, a)
}
} else {
assert.NoError(t, err)
assert.Equal(t, string(out), test.out)
if err != nil {
t.Errorf("expect nil, %v", err)
}
if e, a := string(out), test.out; e != a {
t.Errorf("expect %v, got %v", e, a)
}
}
}
}
+40 -16
View File
@@ -1,32 +1,47 @@
package jsonutil
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"reflect"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/private/protocol"
)
// UnmarshalJSONError unmarshal's the reader's JSON document into the passed in
// type. The value to unmarshal the json document into must be a pointer to the
// type.
func UnmarshalJSONError(v interface{}, stream io.Reader) error {
var errBuf bytes.Buffer
body := io.TeeReader(stream, &errBuf)
err := json.NewDecoder(body).Decode(v)
if err != nil {
msg := "failed decoding error message"
if err == io.EOF {
msg = "error message missing"
err = nil
}
return awserr.NewUnmarshalError(err, msg, errBuf.Bytes())
}
return nil
}
// UnmarshalJSON reads a stream and unmarshals the results in object v.
func UnmarshalJSON(v interface{}, stream io.Reader) error {
var out interface{}
b, err := ioutil.ReadAll(stream)
if err != nil {
return err
}
if len(b) == 0 {
err := json.NewDecoder(stream).Decode(&out)
if err == io.EOF {
return nil
}
if err := json.Unmarshal(b, &out); err != nil {
} else if err != nil {
return err
}
@@ -172,9 +187,6 @@ func unmarshalMap(value reflect.Value, data interface{}, tag reflect.StructTag)
}
func unmarshalScalar(value reflect.Value, data interface{}, tag reflect.StructTag) error {
errf := func() error {
return fmt.Errorf("unsupported value: %v (%s)", value.Interface(), value.Type())
}
switch d := data.(type) {
case nil:
@@ -189,6 +201,17 @@ func unmarshalScalar(value reflect.Value, data interface{}, tag reflect.StructTa
return err
}
value.Set(reflect.ValueOf(b))
case *time.Time:
format := tag.Get("timestampFormat")
if len(format) == 0 {
format = protocol.ISO8601TimeFormatName
}
t, err := protocol.ParseTime(format, d)
if err != nil {
return err
}
value.Set(reflect.ValueOf(&t))
case aws.JSONValue:
// No need to use escaping as the value is a non-quoted string.
v, err := protocol.DecodeJSONValue(d, protocol.NoEscape)
@@ -197,7 +220,7 @@ func unmarshalScalar(value reflect.Value, data interface{}, tag reflect.StructTa
}
value.Set(reflect.ValueOf(v))
default:
return errf()
return fmt.Errorf("unsupported value: %v (%s)", value.Interface(), value.Type())
}
case float64:
switch value.Interface().(type) {
@@ -207,17 +230,18 @@ func unmarshalScalar(value reflect.Value, data interface{}, tag reflect.StructTa
case *float64:
value.Set(reflect.ValueOf(&d))
case *time.Time:
// Time unmarshaled from a float64 can only be epoch seconds
t := time.Unix(int64(d), 0).UTC()
value.Set(reflect.ValueOf(&t))
default:
return errf()
return fmt.Errorf("unsupported value: %v (%s)", value.Interface(), value.Type())
}
case bool:
switch value.Interface().(type) {
case *bool:
value.Set(reflect.ValueOf(&d))
default:
return errf()
return fmt.Errorf("unsupported value: %v (%s)", value.Interface(), value.Type())
}
default:
return fmt.Errorf("unsupported JSON value (%v)", data)
File diff suppressed because it is too large Load Diff
+20 -21
View File
@@ -6,8 +6,6 @@ package jsonrpc
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/json.json unmarshal_test.go
import (
"encoding/json"
"io/ioutil"
"strings"
"github.com/aws/aws-sdk-go/aws/awserr"
@@ -37,7 +35,7 @@ func Build(req *request.Request) {
if req.ParamsFilled() {
buf, err = jsonutil.BuildJSON(req.Params)
if err != nil {
req.Error = awserr.New("SerializationError", "failed encoding JSON RPC request", err)
req.Error = awserr.New(request.ErrCodeSerialization, "failed encoding JSON RPC request", err)
return
}
} else {
@@ -52,9 +50,12 @@ func Build(req *request.Request) {
target := req.ClientInfo.TargetPrefix + "." + req.Operation.Name
req.HTTPRequest.Header.Add("X-Amz-Target", target)
}
if req.ClientInfo.JSONVersion != "" {
// Only set the content type if one is not already specified and an
// JSONVersion is specified.
if ct, v := req.HTTPRequest.Header.Get("Content-Type"), req.ClientInfo.JSONVersion; len(ct) == 0 && len(v) != 0 {
jsonVersion := req.ClientInfo.JSONVersion
req.HTTPRequest.Header.Add("Content-Type", "application/x-amz-json-"+jsonVersion)
req.HTTPRequest.Header.Set("Content-Type", "application/x-amz-json-"+jsonVersion)
}
}
@@ -64,7 +65,11 @@ func Unmarshal(req *request.Request) {
if req.DataFilled() {
err := jsonutil.UnmarshalJSON(req.Data, req.HTTPResponse.Body)
if err != nil {
req.Error = awserr.New("SerializationError", "failed decoding JSON RPC response", err)
req.Error = awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization, "failed decoding JSON RPC response", err),
req.HTTPResponse.StatusCode,
req.RequestID,
)
}
}
return
@@ -78,22 +83,16 @@ func UnmarshalMeta(req *request.Request) {
// UnmarshalError unmarshals an error response for a JSON RPC service.
func UnmarshalError(req *request.Request) {
defer req.HTTPResponse.Body.Close()
bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body)
if err != nil {
req.Error = awserr.New("SerializationError", "failed reading JSON RPC error response", err)
return
}
if len(bodyBytes) == 0 {
req.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", req.HTTPResponse.Status, nil),
req.HTTPResponse.StatusCode,
"",
)
return
}
var jsonErr jsonErrorResponse
if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil {
req.Error = awserr.New("SerializationError", "failed decoding JSON RPC error response", err)
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
}
@@ -0,0 +1,79 @@
// +build go1.8
package jsonrpc
import (
"bytes"
"encoding/hex"
"io/ioutil"
"net/http"
"strings"
"testing"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
)
func TestUnmarshalError_SerializationError(t *testing.T) {
cases := map[string]struct {
Request *request.Request
ExpectMsg string
ExpectBytes []byte
}{
"empty body": {
Request: &request.Request{
Data: &struct{}{},
HTTPResponse: &http.Response{
StatusCode: 400,
Header: http.Header{
"X-Amzn-Requestid": []string{"abc123"},
},
Body: ioutil.NopCloser(
bytes.NewReader([]byte{}),
),
},
},
ExpectMsg: "error message missing",
},
"HTML body": {
Request: &request.Request{
Data: &struct{}{},
HTTPResponse: &http.Response{
StatusCode: 400,
Header: http.Header{
"X-Amzn-Requestid": []string{"abc123"},
},
Body: ioutil.NopCloser(
bytes.NewReader([]byte(`<html></html>`)),
),
},
},
ExpectBytes: []byte(`<html></html>`),
ExpectMsg: "failed decoding",
},
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
req := c.Request
UnmarshalError(req)
if req.Error == nil {
t.Fatal("expect error, got none")
}
aerr := req.Error.(awserr.RequestFailure)
if e, a := request.ErrCodeSerialization, aerr.Code(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
uerr := aerr.OrigErr().(awserr.UnmarshalError)
if e, a := c.ExpectMsg, uerr.Message(); !strings.Contains(a, e) {
t.Errorf("Expect %q, in %q", e, a)
}
if e, a := c.ExpectBytes, uerr.Bytes(); !bytes.Equal(e, a) {
t.Errorf("expect:\n%v\nactual:\n%v", hex.Dump(e), hex.Dump(a))
}
})
}
}
+471 -43
View File
@@ -75,7 +75,8 @@ func newOutputService1ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice1protocoltest",
ServiceName: "OutputService1ProtocolTest",
ServiceID: "OutputService1ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -108,7 +109,7 @@ const opOutputService1TestCaseOperation1 = "OperationName"
// OutputService1TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService1TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -274,7 +275,8 @@ func newOutputService2ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice2protocoltest",
ServiceName: "OutputService2ProtocolTest",
ServiceID: "OutputService2ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -307,7 +309,7 @@ const opOutputService2TestCaseOperation1 = "OperationName"
// OutputService2TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService2TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -439,7 +441,8 @@ func newOutputService3ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice3protocoltest",
ServiceName: "OutputService3ProtocolTest",
ServiceID: "OutputService3ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -472,7 +475,7 @@ const opOutputService3TestCaseOperation1 = "OperationName"
// OutputService3TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService3TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -544,7 +547,11 @@ type OutputService3TestShapeOutputService3TestCaseOperation1Output struct {
StructMember *OutputService3TestShapeTimeContainer `type:"structure"`
TimeMember *time.Time `type:"timestamp" timestampFormat:"unix"`
TimeArg *time.Time `type:"timestamp"`
TimeCustom *time.Time `type:"timestamp" timestampFormat:"rfc822"`
TimeFormat *time.Time `type:"timestamp" timestampFormat:"iso8601"`
}
// SetStructMember sets the StructMember field's value.
@@ -553,16 +560,36 @@ func (s *OutputService3TestShapeOutputService3TestCaseOperation1Output) SetStruc
return s
}
// SetTimeMember sets the TimeMember field's value.
func (s *OutputService3TestShapeOutputService3TestCaseOperation1Output) SetTimeMember(v time.Time) *OutputService3TestShapeOutputService3TestCaseOperation1Output {
s.TimeMember = &v
// SetTimeArg sets the TimeArg field's value.
func (s *OutputService3TestShapeOutputService3TestCaseOperation1Output) SetTimeArg(v time.Time) *OutputService3TestShapeOutputService3TestCaseOperation1Output {
s.TimeArg = &v
return s
}
// SetTimeCustom sets the TimeCustom field's value.
func (s *OutputService3TestShapeOutputService3TestCaseOperation1Output) SetTimeCustom(v time.Time) *OutputService3TestShapeOutputService3TestCaseOperation1Output {
s.TimeCustom = &v
return s
}
// SetTimeFormat sets the TimeFormat field's value.
func (s *OutputService3TestShapeOutputService3TestCaseOperation1Output) SetTimeFormat(v time.Time) *OutputService3TestShapeOutputService3TestCaseOperation1Output {
s.TimeFormat = &v
return s
}
type OutputService3TestShapeTimeContainer struct {
_ struct{} `type:"structure"`
Foo *time.Time `locationName:"foo" type:"timestamp" timestampFormat:"unix"`
Bar *time.Time `locationName:"bar" type:"timestamp" timestampFormat:"iso8601"`
Foo *time.Time `locationName:"foo" type:"timestamp"`
}
// SetBar sets the Bar field's value.
func (s *OutputService3TestShapeTimeContainer) SetBar(v time.Time) *OutputService3TestShapeTimeContainer {
s.Bar = &v
return s
}
// SetFoo sets the Foo field's value.
@@ -602,7 +629,8 @@ func newOutputService4ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice4protocoltest",
ServiceName: "OutputService4ProtocolTest",
ServiceID: "OutputService4ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -635,7 +663,7 @@ const opOutputService4TestCaseOperation1 = "OperationName"
// OutputService4TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService4TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -654,7 +682,7 @@ const opOutputService4TestCaseOperation1 = "OperationName"
// if err == nil { // resp is now filled
// fmt.Println(resp)
// }
func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1Request(input *OutputService4TestShapeOutputService4TestCaseOperation1Input) (req *request.Request, output *OutputService4TestShapeOutputService4TestCaseOperation2Output) {
func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1Request(input *OutputService4TestShapeOutputService4TestCaseOperation1Input) (req *request.Request, output *OutputService4TestShapeOutputService4TestCaseOperation1Output) {
op := &request.Operation{
Name: opOutputService4TestCaseOperation1,
HTTPPath: "/",
@@ -664,7 +692,7 @@ func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1Request(inp
input = &OutputService4TestShapeOutputService4TestCaseOperation1Input{}
}
output = &OutputService4TestShapeOutputService4TestCaseOperation2Output{}
output = &OutputService4TestShapeOutputService4TestCaseOperation1Output{}
req = c.newRequest(op, input, output)
return
}
@@ -677,7 +705,7 @@ func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1Request(inp
//
// See the AWS API reference guide for 's
// API operation OutputService4TestCaseOperation1 for usage and error information.
func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1(input *OutputService4TestShapeOutputService4TestCaseOperation1Input) (*OutputService4TestShapeOutputService4TestCaseOperation2Output, error) {
func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1(input *OutputService4TestShapeOutputService4TestCaseOperation1Input) (*OutputService4TestShapeOutputService4TestCaseOperation1Output, error) {
req, out := c.OutputService4TestCaseOperation1Request(input)
return out, req.Send()
}
@@ -691,7 +719,7 @@ func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1(input *Out
// the context is nil a panic will occur. In the future the SDK may create
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
// for more information on using Contexts.
func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1WithContext(ctx aws.Context, input *OutputService4TestShapeOutputService4TestCaseOperation1Input, opts ...request.Option) (*OutputService4TestShapeOutputService4TestCaseOperation2Output, error) {
func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1WithContext(ctx aws.Context, input *OutputService4TestShapeOutputService4TestCaseOperation1Input, opts ...request.Option) (*OutputService4TestShapeOutputService4TestCaseOperation1Output, error) {
req, out := c.OutputService4TestCaseOperation1Request(input)
req.SetContext(ctx)
req.ApplyOptions(opts...)
@@ -703,7 +731,7 @@ const opOutputService4TestCaseOperation2 = "OperationName"
// OutputService4TestCaseOperation2Request generates a "aws/request.Request" representing the
// client's request for the OutputService4TestCaseOperation2 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -770,6 +798,34 @@ type OutputService4TestShapeOutputService4TestCaseOperation1Input struct {
_ struct{} `type:"structure"`
}
type OutputService4TestShapeOutputService4TestCaseOperation1Output struct {
_ struct{} `type:"structure"`
ListMember []*string `type:"list"`
ListMemberMap []map[string]*string `type:"list"`
ListMemberStruct []*OutputService4TestShapeStructType `type:"list"`
}
// SetListMember sets the ListMember field's value.
func (s *OutputService4TestShapeOutputService4TestCaseOperation1Output) SetListMember(v []*string) *OutputService4TestShapeOutputService4TestCaseOperation1Output {
s.ListMember = v
return s
}
// SetListMemberMap sets the ListMemberMap field's value.
func (s *OutputService4TestShapeOutputService4TestCaseOperation1Output) SetListMemberMap(v []map[string]*string) *OutputService4TestShapeOutputService4TestCaseOperation1Output {
s.ListMemberMap = v
return s
}
// SetListMemberStruct sets the ListMemberStruct field's value.
func (s *OutputService4TestShapeOutputService4TestCaseOperation1Output) SetListMemberStruct(v []*OutputService4TestShapeStructType) *OutputService4TestShapeOutputService4TestCaseOperation1Output {
s.ListMemberStruct = v
return s
}
type OutputService4TestShapeOutputService4TestCaseOperation2Input struct {
_ struct{} `type:"structure"`
}
@@ -837,7 +893,8 @@ func newOutputService5ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice5protocoltest",
ServiceName: "OutputService5ProtocolTest",
ServiceID: "OutputService5ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -870,7 +927,7 @@ const opOutputService5TestCaseOperation1 = "OperationName"
// OutputService5TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService5TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -980,7 +1037,8 @@ func newOutputService6ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice6protocoltest",
ServiceName: "OutputService6ProtocolTest",
ServiceID: "OutputService6ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1013,7 +1071,7 @@ const opOutputService6TestCaseOperation1 = "OperationName"
// OutputService6TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService6TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1123,7 +1181,8 @@ func newOutputService7ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice7protocoltest",
ServiceName: "OutputService7ProtocolTest",
ServiceID: "OutputService7ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1156,7 +1215,7 @@ const opOutputService7TestCaseOperation1 = "OperationName"
// OutputService7TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService7TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1251,6 +1310,297 @@ const (
JSONEnumTypeBar = "bar"
)
// OutputService8ProtocolTest provides the API operation methods for making requests to
// . See this package's package overview docs
// for details on the service.
//
// OutputService8ProtocolTest methods are safe to use concurrently. It is not safe to
// modify mutate any of the struct's properties though.
type OutputService8ProtocolTest struct {
*client.Client
}
// New creates a new instance of the OutputService8ProtocolTest client with a session.
// If additional configuration is needed for the client instance use the optional
// aws.Config parameter to add your extra config.
//
// Example:
// // Create a OutputService8ProtocolTest client from just a session.
// svc := outputservice8protocoltest.New(mySession)
//
// // Create a OutputService8ProtocolTest client with additional configuration
// svc := outputservice8protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
func NewOutputService8ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService8ProtocolTest {
c := p.ClientConfig("outputservice8protocoltest", cfgs...)
return newOutputService8ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName)
}
// newClient creates, initializes and returns a new service client instance.
func newOutputService8ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService8ProtocolTest {
svc := &OutputService8ProtocolTest{
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "OutputService8ProtocolTest",
ServiceID: "OutputService8ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
APIVersion: "",
},
handlers,
),
}
// Handlers
svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler)
svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler)
svc.Handlers.Unmarshal.PushBackNamed(jsonrpc.UnmarshalHandler)
svc.Handlers.UnmarshalMeta.PushBackNamed(jsonrpc.UnmarshalMetaHandler)
svc.Handlers.UnmarshalError.PushBackNamed(jsonrpc.UnmarshalErrorHandler)
return svc
}
// newRequest creates a new request for a OutputService8ProtocolTest operation and runs any
// custom request initialization.
func (c *OutputService8ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request {
req := c.NewRequest(op, params, data)
return req
}
const opOutputService8TestCaseOperation1 = "OperationName"
// OutputService8TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService8TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
//
// See OutputService8TestCaseOperation1 for more information on using the OutputService8TestCaseOperation1
// API call, and error handling.
//
// This method is useful when you want to inject custom logic or configuration
// into the SDK's request lifecycle. Such as custom headers, or retry logic.
//
//
// // Example sending a request using the OutputService8TestCaseOperation1Request method.
// req, resp := client.OutputService8TestCaseOperation1Request(params)
//
// err := req.Send()
// if err == nil { // resp is now filled
// fmt.Println(resp)
// }
func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation1Request(input *OutputService8TestShapeOutputService8TestCaseOperation1Input) (req *request.Request, output *OutputService8TestShapeOutputService8TestCaseOperation1Output) {
op := &request.Operation{
Name: opOutputService8TestCaseOperation1,
HTTPPath: "/",
}
if input == nil {
input = &OutputService8TestShapeOutputService8TestCaseOperation1Input{}
}
output = &OutputService8TestShapeOutputService8TestCaseOperation1Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Swap(jsonrpc.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
return
}
// OutputService8TestCaseOperation1 API operation for .
//
// 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
// the error.
//
// See the AWS API reference guide for 's
// API operation OutputService8TestCaseOperation1 for usage and error information.
func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation1(input *OutputService8TestShapeOutputService8TestCaseOperation1Input) (*OutputService8TestShapeOutputService8TestCaseOperation1Output, error) {
req, out := c.OutputService8TestCaseOperation1Request(input)
return out, req.Send()
}
// OutputService8TestCaseOperation1WithContext is the same as OutputService8TestCaseOperation1 with the addition of
// the ability to pass a context and additional request options.
//
// See OutputService8TestCaseOperation1 for details on how to use this API operation.
//
// The context must be non-nil and will be used for request cancellation. If
// the context is nil a panic will occur. In the future the SDK may create
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
// for more information on using Contexts.
func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation1WithContext(ctx aws.Context, input *OutputService8TestShapeOutputService8TestCaseOperation1Input, opts ...request.Option) (*OutputService8TestShapeOutputService8TestCaseOperation1Output, error) {
req, out := c.OutputService8TestCaseOperation1Request(input)
req.SetContext(ctx)
req.ApplyOptions(opts...)
return out, req.Send()
}
const opOutputService8TestCaseOperation2 = "OperationName"
// OutputService8TestCaseOperation2Request generates a "aws/request.Request" representing the
// client's request for the OutputService8TestCaseOperation2 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
//
// See OutputService8TestCaseOperation2 for more information on using the OutputService8TestCaseOperation2
// API call, and error handling.
//
// This method is useful when you want to inject custom logic or configuration
// into the SDK's request lifecycle. Such as custom headers, or retry logic.
//
//
// // Example sending a request using the OutputService8TestCaseOperation2Request method.
// req, resp := client.OutputService8TestCaseOperation2Request(params)
//
// err := req.Send()
// if err == nil { // resp is now filled
// fmt.Println(resp)
// }
func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation2Request(input *OutputService8TestShapeOutputService8TestCaseOperation2Input) (req *request.Request, output *OutputService8TestShapeOutputService8TestCaseOperation2Output) {
op := &request.Operation{
Name: opOutputService8TestCaseOperation2,
HTTPPath: "/",
}
if input == nil {
input = &OutputService8TestShapeOutputService8TestCaseOperation2Input{}
}
output = &OutputService8TestShapeOutputService8TestCaseOperation2Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Swap(jsonrpc.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
return
}
// OutputService8TestCaseOperation2 API operation for .
//
// 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
// the error.
//
// See the AWS API reference guide for 's
// API operation OutputService8TestCaseOperation2 for usage and error information.
func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation2(input *OutputService8TestShapeOutputService8TestCaseOperation2Input) (*OutputService8TestShapeOutputService8TestCaseOperation2Output, error) {
req, out := c.OutputService8TestCaseOperation2Request(input)
return out, req.Send()
}
// OutputService8TestCaseOperation2WithContext is the same as OutputService8TestCaseOperation2 with the addition of
// the ability to pass a context and additional request options.
//
// See OutputService8TestCaseOperation2 for details on how to use this API operation.
//
// The context must be non-nil and will be used for request cancellation. If
// the context is nil a panic will occur. In the future the SDK may create
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
// for more information on using Contexts.
func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation2WithContext(ctx aws.Context, input *OutputService8TestShapeOutputService8TestCaseOperation2Input, opts ...request.Option) (*OutputService8TestShapeOutputService8TestCaseOperation2Output, error) {
req, out := c.OutputService8TestCaseOperation2Request(input)
req.SetContext(ctx)
req.ApplyOptions(opts...)
return out, req.Send()
}
const opOutputService8TestCaseOperation3 = "OperationName"
// OutputService8TestCaseOperation3Request generates a "aws/request.Request" representing the
// client's request for the OutputService8TestCaseOperation3 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
//
// See OutputService8TestCaseOperation3 for more information on using the OutputService8TestCaseOperation3
// API call, and error handling.
//
// This method is useful when you want to inject custom logic or configuration
// into the SDK's request lifecycle. Such as custom headers, or retry logic.
//
//
// // Example sending a request using the OutputService8TestCaseOperation3Request method.
// req, resp := client.OutputService8TestCaseOperation3Request(params)
//
// err := req.Send()
// if err == nil { // resp is now filled
// fmt.Println(resp)
// }
func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation3Request(input *OutputService8TestShapeOutputService8TestCaseOperation3Input) (req *request.Request, output *OutputService8TestShapeOutputService8TestCaseOperation3Output) {
op := &request.Operation{
Name: opOutputService8TestCaseOperation3,
HTTPPath: "/",
}
if input == nil {
input = &OutputService8TestShapeOutputService8TestCaseOperation3Input{}
}
output = &OutputService8TestShapeOutputService8TestCaseOperation3Output{}
req = c.newRequest(op, input, output)
req.Handlers.Unmarshal.Swap(jsonrpc.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler)
return
}
// OutputService8TestCaseOperation3 API operation for .
//
// 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
// the error.
//
// See the AWS API reference guide for 's
// API operation OutputService8TestCaseOperation3 for usage and error information.
func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation3(input *OutputService8TestShapeOutputService8TestCaseOperation3Input) (*OutputService8TestShapeOutputService8TestCaseOperation3Output, error) {
req, out := c.OutputService8TestCaseOperation3Request(input)
return out, req.Send()
}
// OutputService8TestCaseOperation3WithContext is the same as OutputService8TestCaseOperation3 with the addition of
// the ability to pass a context and additional request options.
//
// See OutputService8TestCaseOperation3 for details on how to use this API operation.
//
// The context must be non-nil and will be used for request cancellation. If
// the context is nil a panic will occur. In the future the SDK may create
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
// for more information on using Contexts.
func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation3WithContext(ctx aws.Context, input *OutputService8TestShapeOutputService8TestCaseOperation3Input, opts ...request.Option) (*OutputService8TestShapeOutputService8TestCaseOperation3Output, error) {
req, out := c.OutputService8TestCaseOperation3Request(input)
req.SetContext(ctx)
req.ApplyOptions(opts...)
return out, req.Send()
}
type OutputService8TestShapeOutputService8TestCaseOperation1Input struct {
_ struct{} `type:"structure"`
}
type OutputService8TestShapeOutputService8TestCaseOperation1Output struct {
_ struct{} `type:"structure"`
}
type OutputService8TestShapeOutputService8TestCaseOperation2Input struct {
_ struct{} `type:"structure"`
}
type OutputService8TestShapeOutputService8TestCaseOperation2Output struct {
_ struct{} `type:"structure"`
}
type OutputService8TestShapeOutputService8TestCaseOperation3Input struct {
_ struct{} `type:"structure"`
}
type OutputService8TestShapeOutputService8TestCaseOperation3Output struct {
_ struct{} `type:"structure"`
}
//
// Tests begin here
//
@@ -1265,8 +1615,8 @@ func TestOutputService1ProtocolTestScalarMembersCase1(t *testing.T) {
// set headers
// unmarshal response
jsonrpc.UnmarshalMeta(req)
jsonrpc.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1312,8 +1662,8 @@ func TestOutputService2ProtocolTestBlobMembersCase1(t *testing.T) {
// set headers
// unmarshal response
jsonrpc.UnmarshalMeta(req)
jsonrpc.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1334,15 +1684,15 @@ func TestOutputService2ProtocolTestBlobMembersCase1(t *testing.T) {
func TestOutputService3ProtocolTestTimestampMembersCase1(t *testing.T) {
svc := NewOutputService3ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")})
buf := bytes.NewReader([]byte("{\"TimeMember\": 1398796238, \"StructMember\": {\"foo\": 1398796238}}"))
buf := bytes.NewReader([]byte("{\"TimeArg\": 1398796238, \"TimeCustom\": \"Tue, 29 Apr 2014 18:30:38 GMT\", \"TimeFormat\": \"2014-04-29T18:30:38Z\", \"StructMember\": {\"foo\": 1398796238, \"bar\": \"2014-04-29T18:30:38Z\"}}"))
req, out := svc.OutputService3TestCaseOperation1Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
jsonrpc.UnmarshalMeta(req)
jsonrpc.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1351,10 +1701,19 @@ func TestOutputService3ProtocolTestTimestampMembersCase1(t *testing.T) {
if out == nil {
t.Errorf("expect not to be nil")
}
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.StructMember.Foo.String(); e != a {
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.StructMember.Bar.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.TimeMember.String(); e != a {
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.StructMember.Foo.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.TimeArg.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.TimeCustom.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.TimeFormat.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
@@ -1370,8 +1729,8 @@ func TestOutputService4ProtocolTestListsCase1(t *testing.T) {
// set headers
// unmarshal response
jsonrpc.UnmarshalMeta(req)
jsonrpc.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1399,8 +1758,8 @@ func TestOutputService4ProtocolTestListsCase2(t *testing.T) {
// set headers
// unmarshal response
jsonrpc.UnmarshalMeta(req)
jsonrpc.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1440,8 +1799,8 @@ func TestOutputService5ProtocolTestMapsCase1(t *testing.T) {
// set headers
// unmarshal response
jsonrpc.UnmarshalMeta(req)
jsonrpc.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1475,8 +1834,8 @@ func TestOutputService6ProtocolTestIgnoresExtraDataCase1(t *testing.T) {
// set headers
// unmarshal response
jsonrpc.UnmarshalMeta(req)
jsonrpc.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1498,8 +1857,8 @@ func TestOutputService7ProtocolTestEnumOutputCase1(t *testing.T) {
// set headers
// unmarshal response
jsonrpc.UnmarshalMeta(req)
jsonrpc.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -1519,3 +1878,72 @@ func TestOutputService7ProtocolTestEnumOutputCase1(t *testing.T) {
}
}
func TestOutputService8ProtocolTestunmodeledNonjsonResponsePayloadCase1(t *testing.T) {
svc := NewOutputService8ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")})
buf := bytes.NewReader([]byte("success"))
req, out := svc.OutputService8TestCaseOperation1Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
// assert response
if out == nil {
t.Errorf("expect not to be nil")
}
}
func TestOutputService8ProtocolTestunmodeledNonjsonResponsePayloadCase2(t *testing.T) {
svc := NewOutputService8ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")})
buf := bytes.NewReader([]byte("\"success\""))
req, out := svc.OutputService8TestCaseOperation2Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
// assert response
if out == nil {
t.Errorf("expect not to be nil")
}
}
func TestOutputService8ProtocolTestunmodeledNonjsonResponsePayloadCase3(t *testing.T) {
svc := NewOutputService8ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")})
buf := bytes.NewReader([]byte("{}"))
req, out := svc.OutputService8TestCaseOperation3Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
// assert response
if out == nil {
t.Errorf("expect not to be nil")
}
}
+81
View File
@@ -0,0 +1,81 @@
package protocol
import (
"io"
"io/ioutil"
"net/http"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/client/metadata"
"github.com/aws/aws-sdk-go/aws/request"
)
// PayloadUnmarshaler provides the interface for unmarshaling a payload's
// reader into a SDK shape.
type PayloadUnmarshaler interface {
UnmarshalPayload(io.Reader, interface{}) error
}
// HandlerPayloadUnmarshal implements the PayloadUnmarshaler from a
// HandlerList. This provides the support for unmarshaling a payload reader to
// a shape without needing a SDK request first.
type HandlerPayloadUnmarshal struct {
Unmarshalers request.HandlerList
}
// UnmarshalPayload unmarshals the io.Reader payload into the SDK shape using
// the Unmarshalers HandlerList provided. Returns an error if unable
// unmarshaling fails.
func (h HandlerPayloadUnmarshal) UnmarshalPayload(r io.Reader, v interface{}) error {
req := &request.Request{
HTTPRequest: &http.Request{},
HTTPResponse: &http.Response{
StatusCode: 200,
Header: http.Header{},
Body: ioutil.NopCloser(r),
},
Data: v,
}
h.Unmarshalers.Run(req)
return req.Error
}
// PayloadMarshaler provides the interface for marshaling a SDK shape into and
// io.Writer.
type PayloadMarshaler interface {
MarshalPayload(io.Writer, interface{}) error
}
// HandlerPayloadMarshal implements the PayloadMarshaler from a HandlerList.
// This provides support for marshaling a SDK shape into an io.Writer without
// needing a SDK request first.
type HandlerPayloadMarshal struct {
Marshalers request.HandlerList
}
// MarshalPayload marshals the SDK shape into the io.Writer using the
// Marshalers HandlerList provided. Returns an error if unable if marshal
// fails.
func (h HandlerPayloadMarshal) MarshalPayload(w io.Writer, v interface{}) error {
req := request.New(
aws.Config{},
metadata.ClientInfo{},
request.Handlers{},
nil,
&request.Operation{HTTPMethod: "GET"},
v,
nil,
)
h.Marshalers.Run(req)
if req.Error != nil {
return req.Error
}
io.Copy(w, req.GetBody())
return nil
}
+12 -6
View File
@@ -5,8 +5,6 @@ import (
"net/url"
"testing"
"github.com/stretchr/testify/assert"
"github.com/aws/aws-sdk-go/aws/client/metadata"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/awstesting"
@@ -117,13 +115,21 @@ func checkForLeak(data interface{}, build, fn func(*request.Request), t *testing
fn(req)
if result.errExists {
assert.NotNil(t, req.Error)
if err := req.Error; err == nil {
t.Errorf("expect error")
}
} else {
assert.Nil(t, req.Error)
if err := req.Error; err != nil {
t.Errorf("expect nil, %v", err)
}
}
assert.Equal(t, reader.Closed, result.closed)
assert.Equal(t, reader.Size, result.size)
if e, a := reader.Closed, result.closed; e != a {
t.Errorf("expect %v, got %v", e, a)
}
if e, a := reader.Size, result.size; e != a {
t.Errorf("expect %v, got %v", e, a)
}
}
func TestJSONRpc(t *testing.T) {
+1 -1
View File
@@ -21,7 +21,7 @@ func Build(r *request.Request) {
"Version": {r.ClientInfo.APIVersion},
}
if err := queryutil.Parse(body, r.Params, false); err != nil {
r.Error = awserr.New("SerializationError", "failed encoding Query request", err)
r.Error = awserr.New(request.ErrCodeSerialization, "failed encoding Query request", err)
return
}
File diff suppressed because it is too large Load Diff
@@ -233,7 +233,12 @@ func (q *queryParser) parseScalar(v url.Values, r reflect.Value, name string, ta
v.Set(name, strconv.FormatFloat(float64(value), 'f', -1, 32))
case time.Time:
const ISO8601UTC = "2006-01-02T15:04:05Z"
v.Set(name, value.UTC().Format(ISO8601UTC))
format := tag.Get("timestampFormat")
if len(format) == 0 {
format = protocol.ISO8601TimeFormatName
}
v.Set(name, protocol.FormatTime(format, value))
default:
return fmt.Errorf("unsupported value for param %s: %v (%s)", name, r.Interface(), r.Type().Name())
}
+5 -1
View File
@@ -23,7 +23,11 @@ func Unmarshal(r *request.Request) {
decoder := xml.NewDecoder(r.HTTPResponse.Body)
err := xmlutil.UnmarshalXML(r.Data, decoder, r.Operation.Name+"Result")
if err != nil {
r.Error = awserr.New("SerializationError", "failed decoding Query response", err)
r.Error = awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization, "failed decoding Query response", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
return
}
}
+44 -41
View File
@@ -2,65 +2,68 @@ package query
import (
"encoding/xml"
"io/ioutil"
"fmt"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
)
type xmlErrorResponse struct {
XMLName xml.Name `xml:"ErrorResponse"`
Code string `xml:"Error>Code"`
Message string `xml:"Error>Message"`
RequestID string `xml:"RequestId"`
}
type xmlServiceUnavailableResponse struct {
XMLName xml.Name `xml:"ServiceUnavailableException"`
}
// UnmarshalErrorHandler is a name request handler to unmarshal request errors
var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.query.UnmarshalError", Fn: UnmarshalError}
type xmlErrorResponse struct {
Code string `xml:"Error>Code"`
Message string `xml:"Error>Message"`
RequestID string `xml:"RequestId"`
}
type xmlResponseError struct {
xmlErrorResponse
}
func (e *xmlResponseError) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
const svcUnavailableTagName = "ServiceUnavailableException"
const errorResponseTagName = "ErrorResponse"
switch start.Name.Local {
case svcUnavailableTagName:
e.Code = svcUnavailableTagName
e.Message = "service is unavailable"
return d.Skip()
case errorResponseTagName:
return d.DecodeElement(&e.xmlErrorResponse, &start)
default:
return fmt.Errorf("unknown error response tag, %v", start)
}
}
// UnmarshalError unmarshals an error response for an AWS Query service.
func UnmarshalError(r *request.Request) {
defer r.HTTPResponse.Body.Close()
bodyBytes, err := ioutil.ReadAll(r.HTTPResponse.Body)
var respErr xmlResponseError
err := xmlutil.UnmarshalXMLError(&respErr, r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.New("SerializationError", "failed to read from query HTTP response body", err)
return
}
// First check for specific error
resp := xmlErrorResponse{}
decodeErr := xml.Unmarshal(bodyBytes, &resp)
if decodeErr == nil {
reqID := resp.RequestID
if reqID == "" {
reqID = r.RequestID
}
r.Error = awserr.NewRequestFailure(
awserr.New(resp.Code, resp.Message, nil),
r.HTTPResponse.StatusCode,
reqID,
)
return
}
// Check for unhandled error
servUnavailResp := xmlServiceUnavailableResponse{}
unavailErr := xml.Unmarshal(bodyBytes, &servUnavailResp)
if unavailErr == nil {
r.Error = awserr.NewRequestFailure(
awserr.New("ServiceUnavailableException", "service is unavailable", nil),
awserr.New(request.ErrCodeSerialization,
"failed to unmarshal error message", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
return
}
// Failed to retrieve any error message from the response body
r.Error = awserr.New("SerializationError",
"failed to decode query XML error response", decodeErr)
reqID := respErr.RequestID
if len(reqID) == 0 {
reqID = r.RequestID
}
r.Error = awserr.NewRequestFailure(
awserr.New(respErr.Code, respErr.Message, nil),
r.HTTPResponse.StatusCode,
reqID,
)
}
@@ -0,0 +1,94 @@
// +build go1.8
package query
import (
"io/ioutil"
"net/http"
"strings"
"testing"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
)
func TestUnmarshalError(t *testing.T) {
cases := map[string]struct {
Request *request.Request
Code, Msg string
ReqID string
Status int
}{
"ErrorResponse": {
Request: &request.Request{
HTTPResponse: &http.Response{
StatusCode: 400,
Header: http.Header{},
Body: ioutil.NopCloser(strings.NewReader(
`<ErrorResponse>
<Error>
<Code>codeAbc</Code><Message>msg123</Message>
</Error>
<RequestId>reqID123</RequestId>
</ErrorResponse>`)),
},
},
Code: "codeAbc", Msg: "msg123",
Status: 400, ReqID: "reqID123",
},
"ServiceUnavailableException": {
Request: &request.Request{
HTTPResponse: &http.Response{
StatusCode: 502,
Header: http.Header{},
Body: ioutil.NopCloser(strings.NewReader(
`<ServiceUnavailableException>
<Something>else</Something>
</ServiceUnavailableException>`)),
},
},
Code: "ServiceUnavailableException",
Msg: "service is unavailable",
Status: 502,
},
"unknown tag": {
Request: &request.Request{
HTTPResponse: &http.Response{
StatusCode: 400,
Header: http.Header{},
Body: ioutil.NopCloser(strings.NewReader(
`<Hello>
<World>.</World>
</Hello>`)),
},
},
Code: request.ErrCodeSerialization,
Msg: "failed to unmarshal error message",
Status: 400,
},
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
r := c.Request
UnmarshalError(r)
if r.Error == nil {
t.Fatalf("expect error, got none")
}
aerr := r.Error.(awserr.RequestFailure)
if e, a := c.Code, aerr.Code(); e != a {
t.Errorf("expect %v code, got %v", e, a)
}
if e, a := c.Msg, aerr.Message(); e != a {
t.Errorf("expect %q message, got %q", e, a)
}
if e, a := c.ReqID, aerr.RequestID(); e != a {
t.Errorf("expect %v request ID, got %v", e, a)
}
if e, a := c.Status, aerr.StatusCode(); e != a {
t.Errorf("expect %v status code, got %v", e, a)
}
})
}
}
+315 -73
View File
@@ -75,7 +75,8 @@ func newOutputService1ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice1protocoltest",
ServiceName: "OutputService1ProtocolTest",
ServiceID: "OutputService1ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -108,7 +109,7 @@ const opOutputService1TestCaseOperation1 = "OperationName"
// OutputService1TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService1TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -192,7 +193,7 @@ type OutputService1TestShapeOutputService1TestCaseOperation1Output struct {
Str *string `type:"string"`
Timestamp *time.Time `type:"timestamp" timestampFormat:"iso8601"`
Timestamp *time.Time `type:"timestamp"`
TrueBool *bool `type:"boolean"`
}
@@ -282,7 +283,8 @@ func newOutputService2ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice2protocoltest",
ServiceName: "OutputService2ProtocolTest",
ServiceID: "OutputService2ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -315,7 +317,7 @@ const opOutputService2TestCaseOperation1 = "OperationName"
// OutputService2TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService2TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -433,7 +435,8 @@ func newOutputService3ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice3protocoltest",
ServiceName: "OutputService3ProtocolTest",
ServiceID: "OutputService3ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -466,7 +469,7 @@ const opOutputService3TestCaseOperation1 = "OperationName"
// OutputService3TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService3TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -577,7 +580,8 @@ func newOutputService4ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice4protocoltest",
ServiceName: "OutputService4ProtocolTest",
ServiceID: "OutputService4ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -610,7 +614,7 @@ const opOutputService4TestCaseOperation1 = "OperationName"
// OutputService4TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService4TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -720,7 +724,8 @@ func newOutputService5ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice5protocoltest",
ServiceName: "OutputService5ProtocolTest",
ServiceID: "OutputService5ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -753,7 +758,7 @@ const opOutputService5TestCaseOperation1 = "OperationName"
// OutputService5TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService5TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -863,7 +868,8 @@ func newOutputService6ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice6protocoltest",
ServiceName: "OutputService6ProtocolTest",
ServiceID: "OutputService6ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -896,7 +902,7 @@ const opOutputService6TestCaseOperation1 = "OperationName"
// OutputService6TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService6TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1006,7 +1012,8 @@ func newOutputService7ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice7protocoltest",
ServiceName: "OutputService7ProtocolTest",
ServiceID: "OutputService7ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1039,7 +1046,7 @@ const opOutputService7TestCaseOperation1 = "OperationName"
// OutputService7TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService7TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1149,7 +1156,8 @@ func newOutputService8ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice8protocoltest",
ServiceName: "OutputService8ProtocolTest",
ServiceID: "OutputService8ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1182,7 +1190,7 @@ const opOutputService8TestCaseOperation1 = "OperationName"
// OutputService8TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService8TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1320,7 +1328,8 @@ func newOutputService9ProtocolTestClient(cfg aws.Config, handlers request.Handle
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice9protocoltest",
ServiceName: "OutputService9ProtocolTest",
ServiceID: "OutputService9ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1353,7 +1362,7 @@ const opOutputService9TestCaseOperation1 = "OperationName"
// OutputService9TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService9TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1491,7 +1500,8 @@ func newOutputService10ProtocolTestClient(cfg aws.Config, handlers request.Handl
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice10protocoltest",
ServiceName: "OutputService10ProtocolTest",
ServiceID: "OutputService10ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1524,7 +1534,7 @@ const opOutputService10TestCaseOperation1 = "OperationName"
// OutputService10TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService10TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1634,7 +1644,8 @@ func newOutputService11ProtocolTestClient(cfg aws.Config, handlers request.Handl
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice11protocoltest",
ServiceName: "OutputService11ProtocolTest",
ServiceID: "OutputService11ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1667,7 +1678,7 @@ const opOutputService11TestCaseOperation1 = "OperationName"
// OutputService11TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService11TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1789,7 +1800,8 @@ func newOutputService12ProtocolTestClient(cfg aws.Config, handlers request.Handl
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice12protocoltest",
ServiceName: "OutputService12ProtocolTest",
ServiceID: "OutputService12ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1822,7 +1834,7 @@ const opOutputService12TestCaseOperation1 = "OperationName"
// OutputService12TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService12TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -1932,7 +1944,8 @@ func newOutputService13ProtocolTestClient(cfg aws.Config, handlers request.Handl
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice13protocoltest",
ServiceName: "OutputService13ProtocolTest",
ServiceID: "OutputService13ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -1965,7 +1978,7 @@ const opOutputService13TestCaseOperation1 = "OperationName"
// OutputService13TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService13TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -2075,7 +2088,8 @@ func newOutputService14ProtocolTestClient(cfg aws.Config, handlers request.Handl
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice14protocoltest",
ServiceName: "OutputService14ProtocolTest",
ServiceID: "OutputService14ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -2108,7 +2122,7 @@ const opOutputService14TestCaseOperation1 = "OperationName"
// OutputService14TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService14TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -2218,7 +2232,8 @@ func newOutputService15ProtocolTestClient(cfg aws.Config, handlers request.Handl
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice15protocoltest",
ServiceName: "OutputService15ProtocolTest",
ServiceID: "OutputService15ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -2251,7 +2266,7 @@ const opOutputService15TestCaseOperation1 = "OperationName"
// OutputService15TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService15TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -2361,7 +2376,8 @@ func newOutputService16ProtocolTestClient(cfg aws.Config, handlers request.Handl
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "outputservice16protocoltest",
ServiceName: "OutputService16ProtocolTest",
ServiceID: "OutputService16ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
@@ -2394,7 +2410,7 @@ const opOutputService16TestCaseOperation1 = "OperationName"
// OutputService16TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService16TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfuly.
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
@@ -2464,28 +2480,216 @@ type OutputService16TestShapeOutputService16TestCaseOperation1Input struct {
type OutputService16TestShapeOutputService16TestCaseOperation1Output struct {
_ struct{} `type:"structure"`
FooEnum *string `type:"string" enum:"OutputService16TestShapeEC2EnumType"`
StructMember *OutputService16TestShapeTimeContainer `type:"structure"`
TimeArg *time.Time `type:"timestamp"`
TimeCustom *time.Time `type:"timestamp" timestampFormat:"rfc822"`
TimeFormat *time.Time `type:"timestamp" timestampFormat:"unixTimestamp"`
}
// SetStructMember sets the StructMember field's value.
func (s *OutputService16TestShapeOutputService16TestCaseOperation1Output) SetStructMember(v *OutputService16TestShapeTimeContainer) *OutputService16TestShapeOutputService16TestCaseOperation1Output {
s.StructMember = v
return s
}
// SetTimeArg sets the TimeArg field's value.
func (s *OutputService16TestShapeOutputService16TestCaseOperation1Output) SetTimeArg(v time.Time) *OutputService16TestShapeOutputService16TestCaseOperation1Output {
s.TimeArg = &v
return s
}
// SetTimeCustom sets the TimeCustom field's value.
func (s *OutputService16TestShapeOutputService16TestCaseOperation1Output) SetTimeCustom(v time.Time) *OutputService16TestShapeOutputService16TestCaseOperation1Output {
s.TimeCustom = &v
return s
}
// SetTimeFormat sets the TimeFormat field's value.
func (s *OutputService16TestShapeOutputService16TestCaseOperation1Output) SetTimeFormat(v time.Time) *OutputService16TestShapeOutputService16TestCaseOperation1Output {
s.TimeFormat = &v
return s
}
type OutputService16TestShapeTimeContainer struct {
_ struct{} `type:"structure"`
Bar *time.Time `locationName:"bar" type:"timestamp" timestampFormat:"unixTimestamp"`
Foo *time.Time `locationName:"foo" type:"timestamp"`
}
// SetBar sets the Bar field's value.
func (s *OutputService16TestShapeTimeContainer) SetBar(v time.Time) *OutputService16TestShapeTimeContainer {
s.Bar = &v
return s
}
// SetFoo sets the Foo field's value.
func (s *OutputService16TestShapeTimeContainer) SetFoo(v time.Time) *OutputService16TestShapeTimeContainer {
s.Foo = &v
return s
}
// OutputService17ProtocolTest provides the API operation methods for making requests to
// . See this package's package overview docs
// for details on the service.
//
// OutputService17ProtocolTest methods are safe to use concurrently. It is not safe to
// modify mutate any of the struct's properties though.
type OutputService17ProtocolTest struct {
*client.Client
}
// New creates a new instance of the OutputService17ProtocolTest client with a session.
// If additional configuration is needed for the client instance use the optional
// aws.Config parameter to add your extra config.
//
// Example:
// // Create a OutputService17ProtocolTest client from just a session.
// svc := outputservice17protocoltest.New(mySession)
//
// // Create a OutputService17ProtocolTest client with additional configuration
// svc := outputservice17protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
func NewOutputService17ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService17ProtocolTest {
c := p.ClientConfig("outputservice17protocoltest", cfgs...)
return newOutputService17ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName)
}
// newClient creates, initializes and returns a new service client instance.
func newOutputService17ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService17ProtocolTest {
svc := &OutputService17ProtocolTest{
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: "OutputService17ProtocolTest",
ServiceID: "OutputService17ProtocolTest",
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
APIVersion: "",
},
handlers,
),
}
// Handlers
svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler)
svc.Handlers.Build.PushBackNamed(query.BuildHandler)
svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler)
svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler)
svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler)
return svc
}
// newRequest creates a new request for a OutputService17ProtocolTest operation and runs any
// custom request initialization.
func (c *OutputService17ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request {
req := c.NewRequest(op, params, data)
return req
}
const opOutputService17TestCaseOperation1 = "OperationName"
// OutputService17TestCaseOperation1Request generates a "aws/request.Request" representing the
// client's request for the OutputService17TestCaseOperation1 operation. The "output" return
// value will be populated with the request's response once the request completes
// successfully.
//
// Use "Send" method on the returned Request to send the API call to the service.
// the "output" return value is not valid until after Send returns without error.
//
// See OutputService17TestCaseOperation1 for more information on using the OutputService17TestCaseOperation1
// API call, and error handling.
//
// This method is useful when you want to inject custom logic or configuration
// into the SDK's request lifecycle. Such as custom headers, or retry logic.
//
//
// // Example sending a request using the OutputService17TestCaseOperation1Request method.
// req, resp := client.OutputService17TestCaseOperation1Request(params)
//
// err := req.Send()
// if err == nil { // resp is now filled
// fmt.Println(resp)
// }
func (c *OutputService17ProtocolTest) OutputService17TestCaseOperation1Request(input *OutputService17TestShapeOutputService17TestCaseOperation1Input) (req *request.Request, output *OutputService17TestShapeOutputService17TestCaseOperation1Output) {
op := &request.Operation{
Name: opOutputService17TestCaseOperation1,
HTTPPath: "/",
}
if input == nil {
input = &OutputService17TestShapeOutputService17TestCaseOperation1Input{}
}
output = &OutputService17TestShapeOutputService17TestCaseOperation1Output{}
req = c.newRequest(op, input, output)
return
}
// OutputService17TestCaseOperation1 API operation for .
//
// 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
// the error.
//
// See the AWS API reference guide for 's
// API operation OutputService17TestCaseOperation1 for usage and error information.
func (c *OutputService17ProtocolTest) OutputService17TestCaseOperation1(input *OutputService17TestShapeOutputService17TestCaseOperation1Input) (*OutputService17TestShapeOutputService17TestCaseOperation1Output, error) {
req, out := c.OutputService17TestCaseOperation1Request(input)
return out, req.Send()
}
// OutputService17TestCaseOperation1WithContext is the same as OutputService17TestCaseOperation1 with the addition of
// the ability to pass a context and additional request options.
//
// See OutputService17TestCaseOperation1 for details on how to use this API operation.
//
// The context must be non-nil and will be used for request cancellation. If
// the context is nil a panic will occur. In the future the SDK may create
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
// for more information on using Contexts.
func (c *OutputService17ProtocolTest) OutputService17TestCaseOperation1WithContext(ctx aws.Context, input *OutputService17TestShapeOutputService17TestCaseOperation1Input, opts ...request.Option) (*OutputService17TestShapeOutputService17TestCaseOperation1Output, error) {
req, out := c.OutputService17TestCaseOperation1Request(input)
req.SetContext(ctx)
req.ApplyOptions(opts...)
return out, req.Send()
}
type OutputService17TestShapeOutputService17TestCaseOperation1Input struct {
_ struct{} `type:"structure"`
}
type OutputService17TestShapeOutputService17TestCaseOperation1Output struct {
_ struct{} `type:"structure"`
FooEnum *string `type:"string" enum:"OutputService17TestShapeEC2EnumType"`
ListEnums []*string `type:"list"`
}
// SetFooEnum sets the FooEnum field's value.
func (s *OutputService16TestShapeOutputService16TestCaseOperation1Output) SetFooEnum(v string) *OutputService16TestShapeOutputService16TestCaseOperation1Output {
func (s *OutputService17TestShapeOutputService17TestCaseOperation1Output) SetFooEnum(v string) *OutputService17TestShapeOutputService17TestCaseOperation1Output {
s.FooEnum = &v
return s
}
// SetListEnums sets the ListEnums field's value.
func (s *OutputService16TestShapeOutputService16TestCaseOperation1Output) SetListEnums(v []*string) *OutputService16TestShapeOutputService16TestCaseOperation1Output {
func (s *OutputService17TestShapeOutputService17TestCaseOperation1Output) SetListEnums(v []*string) *OutputService17TestShapeOutputService17TestCaseOperation1Output {
s.ListEnums = v
return s
}
const (
// EC2EnumTypeFoo is a OutputService16TestShapeEC2EnumType enum value
// EC2EnumTypeFoo is a OutputService17TestShapeEC2EnumType enum value
EC2EnumTypeFoo = "foo"
// EC2EnumTypeBar is a OutputService16TestShapeEC2EnumType enum value
// EC2EnumTypeBar is a OutputService17TestShapeEC2EnumType enum value
EC2EnumTypeBar = "bar"
)
@@ -2503,8 +2707,8 @@ func TestOutputService1ProtocolTestScalarMembersCase1(t *testing.T) {
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -2534,7 +2738,7 @@ func TestOutputService1ProtocolTestScalarMembersCase1(t *testing.T) {
if e, a := "myname", *out.Str; e != a {
t.Errorf("expect %v, got %v", e, a)
}
if e, a := time.Unix(1.4221728e+09, 0).UTC().String(), out.Timestamp.String(); e != a {
if e, a := time.Unix(1.4221728e+09, 0).UTC().String(), out.Timestamp.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
if e, a := true, *out.TrueBool; e != a {
@@ -2553,8 +2757,8 @@ func TestOutputService2ProtocolTestNotAllMembersInResponseCase1(t *testing.T) {
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -2579,8 +2783,8 @@ func TestOutputService3ProtocolTestBlobCase1(t *testing.T) {
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -2605,8 +2809,8 @@ func TestOutputService4ProtocolTestListsCase1(t *testing.T) {
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -2634,8 +2838,8 @@ func TestOutputService5ProtocolTestListWithCustomMemberNameCase1(t *testing.T) {
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -2663,8 +2867,8 @@ func TestOutputService6ProtocolTestFlattenedListCase1(t *testing.T) {
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -2692,8 +2896,8 @@ func TestOutputService7ProtocolTestFlattenedSingleElementListCase1(t *testing.T)
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -2718,8 +2922,8 @@ func TestOutputService8ProtocolTestListOfStructuresCase1(t *testing.T) {
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -2759,8 +2963,8 @@ func TestOutputService9ProtocolTestFlattenedListOfStructuresCase1(t *testing.T)
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -2800,8 +3004,8 @@ func TestOutputService10ProtocolTestFlattenedListWithLocationNameCase1(t *testin
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -2829,8 +3033,8 @@ func TestOutputService11ProtocolTestNormalMapCase1(t *testing.T) {
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -2858,8 +3062,8 @@ func TestOutputService12ProtocolTestFlattenedMapCase1(t *testing.T) {
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -2887,8 +3091,8 @@ func TestOutputService13ProtocolTestFlattenedMapInShapeDefinitionCase1(t *testin
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -2913,8 +3117,8 @@ func TestOutputService14ProtocolTestNamedMapCase1(t *testing.T) {
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -2942,8 +3146,8 @@ func TestOutputService15ProtocolTestEmptyStringCase1(t *testing.T) {
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
@@ -2958,18 +3162,56 @@ func TestOutputService15ProtocolTestEmptyStringCase1(t *testing.T) {
}
func TestOutputService16ProtocolTestEnumOutputCase1(t *testing.T) {
func TestOutputService16ProtocolTestTimestampMembersCase1(t *testing.T) {
svc := NewOutputService16ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")})
buf := bytes.NewReader([]byte("<OperationNameResponse><FooEnum>foo</FooEnum><ListEnums><member>foo</member><member>bar</member></ListEnums></OperationNameResponse>"))
buf := bytes.NewReader([]byte("<OperationNameResponse><StructMember><foo>2014-04-29T18:30:38Z</foo><bar>1398796238</bar></StructMember><TimeArg>2014-04-29T18:30:38Z</TimeArg><TimeCustom>Tue, 29 Apr 2014 18:30:38 GMT</TimeCustom><TimeFormat>1398796238</TimeFormat><RequestId>requestid</RequestId></OperationNameResponse>"))
req, out := svc.OutputService16TestCaseOperation1Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
query.UnmarshalMeta(req)
query.Unmarshal(req)
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
// assert response
if out == nil {
t.Errorf("expect not to be nil")
}
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.StructMember.Bar.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.StructMember.Foo.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.TimeArg.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.TimeCustom.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
if e, a := time.Unix(1.398796238e+09, 0).UTC().String(), out.TimeFormat.UTC().String(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
}
func TestOutputService17ProtocolTestEnumOutputCase1(t *testing.T) {
svc := NewOutputService17ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")})
buf := bytes.NewReader([]byte("<OperationNameResponse><FooEnum>foo</FooEnum><ListEnums><member>foo</member><member>bar</member></ListEnums></OperationNameResponse>"))
req, out := svc.OutputService17TestCaseOperation1Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
req.Handlers.UnmarshalMeta.Run(req)
req.Handlers.Unmarshal.Run(req)
if req.Error != nil {
t.Errorf("expect not error, got %v", req.Error)
}
+29 -10
View File
@@ -20,14 +20,13 @@ import (
"github.com/aws/aws-sdk-go/private/protocol"
)
// RFC822 returns an RFC822 formatted timestamp for AWS protocols
const RFC822 = "Mon, 2 Jan 2006 15:04:05 GMT"
// Whether the byte value can be sent without escaping in AWS URLs
var noEscape [256]bool
var errValueNotSet = fmt.Errorf("value not set")
var byteSliceType = reflect.TypeOf([]byte{})
func init() {
for i := 0; i < len(noEscape); i++ {
// AWS expects every character except these to be escaped
@@ -97,6 +96,14 @@ func buildLocationElements(r *request.Request, v reflect.Value, buildGETQuery bo
continue
}
// Support the ability to customize values to be marshaled as a
// blob even though they were modeled as a string. Required for S3
// API operations like SSECustomerKey is modeled as stirng but
// required to be base64 encoded in request.
if field.Tag.Get("marshal-as") == "blob" {
m = m.Convert(byteSliceType)
}
var err error
switch field.Tag.Get("location") {
case "headers": // header maps
@@ -140,7 +147,7 @@ func buildBody(r *request.Request, v reflect.Value) {
case string:
r.SetStringBody(reader)
default:
r.Error = awserr.New("SerializationError",
r.Error = awserr.New(request.ErrCodeSerialization,
"failed to encode REST request",
fmt.Errorf("unknown payload type %s", payload.Type()))
}
@@ -155,9 +162,12 @@ func buildHeader(header *http.Header, v reflect.Value, name string, tag reflect.
if err == errValueNotSet {
return nil
} else if err != nil {
return awserr.New("SerializationError", "failed to encode REST request", err)
return awserr.New(request.ErrCodeSerialization, "failed to encode REST request", err)
}
name = strings.TrimSpace(name)
str = strings.TrimSpace(str)
header.Add(name, str)
return nil
@@ -170,11 +180,13 @@ func buildHeaderMap(header *http.Header, v reflect.Value, tag reflect.StructTag)
if err == errValueNotSet {
continue
} else if err != nil {
return awserr.New("SerializationError", "failed to encode REST request", err)
return awserr.New(request.ErrCodeSerialization, "failed to encode REST request", err)
}
keyStr := strings.TrimSpace(key.String())
str = strings.TrimSpace(str)
header.Add(prefix+key.String(), str)
header.Add(prefix+keyStr, str)
}
return nil
}
@@ -184,7 +196,7 @@ func buildURI(u *url.URL, v reflect.Value, name string, tag reflect.StructTag) e
if err == errValueNotSet {
return nil
} else if err != nil {
return awserr.New("SerializationError", "failed to encode REST request", err)
return awserr.New(request.ErrCodeSerialization, "failed to encode REST request", err)
}
u.Path = strings.Replace(u.Path, "{"+name+"}", value, -1)
@@ -217,7 +229,7 @@ func buildQueryString(query url.Values, v reflect.Value, name string, tag reflec
if err == errValueNotSet {
return nil
} else if err != nil {
return awserr.New("SerializationError", "failed to encode REST request", err)
return awserr.New(request.ErrCodeSerialization, "failed to encode REST request", err)
}
query.Set(name, str)
}
@@ -270,7 +282,14 @@ func convertType(v reflect.Value, tag reflect.StructTag) (str string, err error)
case float64:
str = strconv.FormatFloat(value, 'f', -1, 64)
case time.Time:
str = value.UTC().Format(RFC822)
format := tag.Get("timestampFormat")
if len(format) == 0 {
format = protocol.RFC822TimeFormatName
if tag.Get("location") == "querystring" {
format = protocol.ISO8601TimeFormatName
}
}
str = protocol.FormatTime(format, value)
case aws.JSONValue:
if len(value) == 0 {
return "", errValueNotSet
+11 -7
View File
@@ -57,7 +57,7 @@ func unmarshalBody(r *request.Request, v reflect.Value) {
defer r.HTTPResponse.Body.Close()
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.New("SerializationError", "failed to decode REST response", err)
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
} else {
payload.Set(reflect.ValueOf(b))
}
@@ -65,7 +65,7 @@ func unmarshalBody(r *request.Request, v reflect.Value) {
defer r.HTTPResponse.Body.Close()
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.New("SerializationError", "failed to decode REST response", err)
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
} else {
str := string(b)
payload.Set(reflect.ValueOf(&str))
@@ -77,7 +77,7 @@ func unmarshalBody(r *request.Request, v reflect.Value) {
case "io.ReadSeeker":
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.New("SerializationError",
r.Error = awserr.New(request.ErrCodeSerialization,
"failed to read response body", err)
return
}
@@ -85,7 +85,7 @@ func unmarshalBody(r *request.Request, v reflect.Value) {
default:
io.Copy(ioutil.Discard, r.HTTPResponse.Body)
defer r.HTTPResponse.Body.Close()
r.Error = awserr.New("SerializationError",
r.Error = awserr.New(request.ErrCodeSerialization,
"failed to decode REST response",
fmt.Errorf("unknown payload type %s", payload.Type()))
}
@@ -115,14 +115,14 @@ func unmarshalLocationElements(r *request.Request, v reflect.Value) {
case "header":
err := unmarshalHeader(m, r.HTTPResponse.Header.Get(name), field.Tag)
if err != nil {
r.Error = awserr.New("SerializationError", "failed to decode REST response", err)
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
break
}
case "headers":
prefix := field.Tag.Get("locationName")
err := unmarshalHeaderMap(m, r.HTTPResponse.Header, prefix)
if err != nil {
r.Error = awserr.New("SerializationError", "failed to decode REST response", err)
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
break
}
}
@@ -198,7 +198,11 @@ func unmarshalHeader(v reflect.Value, header string, tag reflect.StructTag) erro
}
v.Set(reflect.ValueOf(&f))
case *time.Time:
t, err := time.Parse(RFC822, header)
format := tag.Get("timestampFormat")
if len(format) == 0 {
format = protocol.RFC822TimeFormatName
}
t, err := protocol.ParseTime(format, header)
if err != nil {
return err
}
File diff suppressed because it is too large Load Diff
+11 -15
View File
@@ -6,12 +6,11 @@ package restjson
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/rest-json.json unmarshal_test.go
import (
"encoding/json"
"io/ioutil"
"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/json/jsonutil"
"github.com/aws/aws-sdk-go/private/protocol/jsonrpc"
"github.com/aws/aws-sdk-go/private/protocol/rest"
)
@@ -33,6 +32,9 @@ func Build(r *request.Request) {
rest.Build(r)
if t := rest.PayloadType(r.Params); t == "structure" || t == "" {
if v := r.HTTPRequest.Header.Get("Content-Type"); len(v) == 0 {
r.HTTPRequest.Header.Set("Content-Type", "application/json")
}
jsonrpc.Build(r)
}
}
@@ -54,26 +56,20 @@ func UnmarshalMeta(r *request.Request) {
// UnmarshalError unmarshals a response error for the REST JSON protocol.
func UnmarshalError(r *request.Request) {
defer r.HTTPResponse.Body.Close()
code := r.HTTPResponse.Header.Get("X-Amzn-Errortype")
bodyBytes, err := ioutil.ReadAll(r.HTTPResponse.Body)
var jsonErr jsonErrorResponse
err := jsonutil.UnmarshalJSONError(&jsonErr, r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.New("SerializationError", "failed reading REST JSON error response", err)
return
}
if len(bodyBytes) == 0 {
r.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", r.HTTPResponse.Status, nil),
awserr.New(request.ErrCodeSerialization,
"failed to unmarshal response error", err),
r.HTTPResponse.StatusCode,
"",
r.RequestID,
)
return
}
var jsonErr jsonErrorResponse
if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil {
r.Error = awserr.New("SerializationError", "failed decoding REST JSON error response", err)
return
}
code := r.HTTPResponse.Header.Get("X-Amzn-Errortype")
if code == "" {
code = jsonErr.Code
}
@@ -0,0 +1,79 @@
// +build go1.8
package restjson
import (
"bytes"
"encoding/hex"
"io/ioutil"
"net/http"
"strings"
"testing"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
)
func TestUnmarshalError_SerializationError(t *testing.T) {
cases := map[string]struct {
Request *request.Request
ExpectMsg string
ExpectBytes []byte
}{
"empty body": {
Request: &request.Request{
Data: &struct{}{},
HTTPResponse: &http.Response{
StatusCode: 400,
Header: http.Header{
"X-Amzn-Requestid": []string{"abc123"},
},
Body: ioutil.NopCloser(
bytes.NewReader([]byte{}),
),
},
},
ExpectMsg: "error message missing",
},
"HTML body": {
Request: &request.Request{
Data: &struct{}{},
HTTPResponse: &http.Response{
StatusCode: 400,
Header: http.Header{
"X-Amzn-Requestid": []string{"abc123"},
},
Body: ioutil.NopCloser(
bytes.NewReader([]byte(`<html></html>`)),
),
},
},
ExpectBytes: []byte(`<html></html>`),
ExpectMsg: "failed decoding",
},
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
req := c.Request
UnmarshalError(req)
if req.Error == nil {
t.Fatal("expect error, got none")
}
aerr := req.Error.(awserr.RequestFailure)
if e, a := request.ErrCodeSerialization, aerr.Code(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
uerr := aerr.OrigErr().(awserr.UnmarshalError)
if e, a := c.ExpectMsg, uerr.Message(); !strings.Contains(a, e) {
t.Errorf("Expect %q, in %q", e, a)
}
if e, a := c.ExpectBytes, uerr.Bytes(); !bytes.Equal(e, a) {
t.Errorf("expect:\n%v\nactual:\n%v", hex.Dump(e), hex.Dump(a))
}
})
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+12 -2
View File
@@ -36,7 +36,12 @@ func Build(r *request.Request) {
var buf bytes.Buffer
err := xmlutil.BuildXML(r.Params, xml.NewEncoder(&buf))
if err != nil {
r.Error = awserr.New("SerializationError", "failed to encode rest XML request", err)
r.Error = awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization,
"failed to encode rest XML request", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
return
}
r.SetBufferBody(buf.Bytes())
@@ -50,7 +55,12 @@ func Unmarshal(r *request.Request) {
decoder := xml.NewDecoder(r.HTTPResponse.Body)
err := xmlutil.UnmarshalXML(r.Data, decoder, "")
if err != nil {
r.Error = awserr.New("SerializationError", "failed to decode REST XML response", err)
r.Error = awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization,
"failed to decode REST XML response", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
return
}
} else {
File diff suppressed because it is too large Load Diff
+72
View File
@@ -0,0 +1,72 @@
package protocol
import (
"strconv"
"time"
)
// Names of time formats supported by the SDK
const (
RFC822TimeFormatName = "rfc822"
ISO8601TimeFormatName = "iso8601"
UnixTimeFormatName = "unixTimestamp"
)
// Time formats supported by the SDK
const (
// RFC 7231#section-7.1.1.1 timetamp format. e.g Tue, 29 Apr 2014 18:30:38 GMT
RFC822TimeFormat = "Mon, 2 Jan 2006 15:04:05 GMT"
// RFC3339 a subset of the ISO8601 timestamp format. e.g 2014-04-29T18:30:38Z
ISO8601TimeFormat = "2006-01-02T15:04:05Z"
)
// IsKnownTimestampFormat returns if the timestamp format name
// is know to the SDK's protocols.
func IsKnownTimestampFormat(name string) bool {
switch name {
case RFC822TimeFormatName:
fallthrough
case ISO8601TimeFormatName:
fallthrough
case UnixTimeFormatName:
return true
default:
return false
}
}
// FormatTime returns a string value of the time.
func FormatTime(name string, t time.Time) string {
t = t.UTC()
switch name {
case RFC822TimeFormatName:
return t.Format(RFC822TimeFormat)
case ISO8601TimeFormatName:
return t.Format(ISO8601TimeFormat)
case UnixTimeFormatName:
return strconv.FormatInt(t.Unix(), 10)
default:
panic("unknown timestamp format name, " + name)
}
}
// ParseTime attempts to parse the time given the format. Returns
// the time if it was able to be parsed, and fails otherwise.
func ParseTime(formatName, value string) (time.Time, error) {
switch formatName {
case RFC822TimeFormatName:
return time.Parse(RFC822TimeFormat, value)
case ISO8601TimeFormatName:
return time.Parse(ISO8601TimeFormat, value)
case UnixTimeFormatName:
v, err := strconv.ParseFloat(value, 64)
if err != nil {
return time.Time{}, err
}
return time.Unix(int64(v), 0), nil
default:
panic("unknown timestamp format name, " + formatName)
}
}
+130 -5
View File
@@ -1,13 +1,19 @@
package protocol_test
import (
"io/ioutil"
"net/http"
"strings"
"testing"
"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/stretchr/testify/assert"
"github.com/aws/aws-sdk-go/private/protocol/ec2query"
"github.com/aws/aws-sdk-go/private/protocol/jsonrpc"
"github.com/aws/aws-sdk-go/private/protocol/query"
"github.com/aws/aws-sdk-go/private/protocol/restjson"
"github.com/aws/aws-sdk-go/private/protocol/restxml"
)
type mockCloser struct {
@@ -27,14 +33,133 @@ func TestUnmarshalDrainBody(t *testing.T) {
}}
protocol.UnmarshalDiscardBody(r)
assert.NoError(t, r.Error)
assert.Equal(t, 0, b.Len())
assert.True(t, b.Closed)
if err := r.Error; err != nil {
t.Errorf("expect nil, %v", err)
}
if e, a := 0, b.Len(); e != a {
t.Errorf("expect %v, got %v", e, a)
}
if !b.Closed {
t.Errorf("expect true")
}
}
func TestUnmarshalDrainBodyNoBody(t *testing.T) {
r := &request.Request{HTTPResponse: &http.Response{}}
protocol.UnmarshalDiscardBody(r)
assert.NoError(t, r.Error)
if err := r.Error; err != nil {
t.Errorf("expect nil, %v", err)
}
}
func TestUnmarshalSeriaizationError(t *testing.T) {
type testOutput struct {
_ struct{}
}
cases := []struct {
name string
r request.Request
unmarshalFn func(*request.Request)
expectedError awserr.RequestFailure
}{
{
name: "jsonrpc",
r: request.Request{
Data: &testOutput{},
HTTPResponse: &http.Response{
StatusCode: 502,
Body: ioutil.NopCloser(strings.NewReader("invalid json")),
},
},
unmarshalFn: jsonrpc.Unmarshal,
expectedError: awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization, "", nil),
502,
"",
),
},
{
name: "ec2query",
r: request.Request{
Data: &testOutput{},
HTTPResponse: &http.Response{
StatusCode: 111,
Body: ioutil.NopCloser(strings.NewReader("<<>>>>>>")),
},
},
unmarshalFn: ec2query.Unmarshal,
expectedError: awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization, "", nil),
111,
"",
),
},
{
name: "query",
r: request.Request{
Operation: &request.Operation{
Name: "Foo",
},
Data: &testOutput{},
HTTPResponse: &http.Response{
StatusCode: 1,
Body: ioutil.NopCloser(strings.NewReader("<<>>>>>>")),
},
},
unmarshalFn: query.Unmarshal,
expectedError: awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization, "", nil),
1,
"",
),
},
{
name: "restjson",
r: request.Request{
Data: &testOutput{},
HTTPResponse: &http.Response{
StatusCode: 123,
Body: ioutil.NopCloser(strings.NewReader("invalid json")),
},
},
unmarshalFn: restjson.Unmarshal,
expectedError: awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization, "", nil),
123,
"",
),
},
{
name: "restxml",
r: request.Request{
Data: &testOutput{},
HTTPResponse: &http.Response{
StatusCode: 456,
Body: ioutil.NopCloser(strings.NewReader("<<>>>>>>")),
},
},
unmarshalFn: restxml.Unmarshal,
expectedError: awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization, "", nil),
456,
"",
),
},
}
for _, c := range cases {
c.unmarshalFn(&c.r)
rfErr, ok := c.r.Error.(awserr.RequestFailure)
if !ok {
t.Errorf("%s: expected awserr.RequestFailure, but received %T", c.name, c.r.Error)
}
if e, a := c.expectedError.StatusCode(), rfErr.StatusCode(); e != a {
t.Errorf("%s: expected %v, but received %v", c.name, e, a)
}
}
}
+21 -11
View File
@@ -13,9 +13,13 @@ import (
"github.com/aws/aws-sdk-go/private/protocol"
)
// BuildXML will serialize params into an xml.Encoder.
// Error will be returned if the serialization of any of the params or nested values fails.
// BuildXML will serialize params into an xml.Encoder. Error will be returned
// if the serialization of any of the params or nested values fails.
func BuildXML(params interface{}, e *xml.Encoder) error {
return buildXML(params, e, false)
}
func buildXML(params interface{}, e *xml.Encoder, sorted bool) error {
b := xmlBuilder{encoder: e, namespaces: map[string]string{}}
root := NewXMLElement(xml.Name{})
if err := b.buildValue(reflect.ValueOf(params), root, ""); err != nil {
@@ -23,7 +27,7 @@ func BuildXML(params interface{}, e *xml.Encoder) error {
}
for _, c := range root.Children {
for _, v := range c {
return StructToXML(e, v, false)
return StructToXML(e, v, sorted)
}
}
return nil
@@ -83,15 +87,13 @@ func (b *xmlBuilder) buildValue(value reflect.Value, current *XMLNode, tag refle
}
}
// buildStruct adds a struct and its fields to the current XMLNode. All fields any any nested
// buildStruct adds a struct and its fields to the current XMLNode. All fields and any nested
// types are converted to XMLNodes also.
func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag reflect.StructTag) error {
if !value.IsValid() {
return nil
}
fieldAdded := false
// unwrap payloads
if payload := tag.Get("payload"); payload != "" {
field, _ := value.Type().FieldByName(payload)
@@ -119,6 +121,8 @@ func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag refl
child.Attr = append(child.Attr, ns)
}
var payloadFields, nonPayloadFields int
t := value.Type()
for i := 0; i < value.NumField(); i++ {
member := elemOf(value.Field(i))
@@ -133,8 +137,10 @@ func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag refl
mTag := field.Tag
if mTag.Get("location") != "" { // skip non-body members
nonPayloadFields++
continue
}
payloadFields++
if protocol.CanSetIdempotencyToken(value.Field(i), field) {
token := protocol.GetIdempotencyToken()
@@ -149,11 +155,11 @@ func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag refl
if err := b.buildValue(member, child, mTag); err != nil {
return err
}
fieldAdded = true
}
if fieldAdded { // only append this child if we have one ore more valid members
// Only case where the child shape is not added is if the shape only contains
// non-payload fields, e.g headers/query.
if !(payloadFields == 0 && nonPayloadFields > 0) {
current.AddChild(child)
}
@@ -278,8 +284,12 @@ func (b *xmlBuilder) buildScalar(value reflect.Value, current *XMLNode, tag refl
case float32:
str = strconv.FormatFloat(float64(converted), 'f', -1, 32)
case time.Time:
const ISO8601UTC = "2006-01-02T15:04:05Z"
str = converted.UTC().Format(ISO8601UTC)
format := tag.Get("timestampFormat")
if len(format) == 0 {
format = protocol.ISO8601TimeFormatName
}
str = protocol.FormatTime(format, converted)
default:
return fmt.Errorf("unsupported value for param %s: %v (%s)",
tag.Get("locationName"), value.Interface(), value.Type().Name())
@@ -0,0 +1,170 @@
// +build go1.7
package xmlutil
import (
"bytes"
"encoding/xml"
"testing"
"github.com/aws/aws-sdk-go/aws"
)
type implicitPayload struct {
_ struct{} `type:"structure"`
StrVal *string `type:"string"`
Second *nestedType `type:"structure"`
Third *nestedType `type:"structure"`
}
type namedImplicitPayload struct {
_ struct{} `type:"structure" locationName:"namedPayload"`
StrVal *string `type:"string"`
Second *nestedType `type:"structure"`
Third *nestedType `type:"structure"`
}
type explicitPayload struct {
_ struct{} `type:"structure" payload:"Second"`
Second *nestedType `type:"structure" locationName:"Second"`
}
type useEmptyNested struct {
_ struct{} `type:"structure" locationName:"useEmptyNested"`
StrVal *string `type:"string"`
Empty *emptyType `type:"structure"`
}
type useIgnoreNested struct {
_ struct{} `type:"structure" locationName:"useIgnoreNested"`
StrVal *string `type:"string"`
Ignore *ignoreNested `type:"structure"`
}
type skipNonPayload struct {
_ struct{} `type:"structure" locationName:"skipNonPayload"`
Field *string `type:"string" location:"header"`
}
type namedEmptyPayload struct {
_ struct{} `type:"structure" locationName:"namedEmptyPayload"`
}
type nestedType struct {
_ struct{} `type:"structure"`
IntVal *int64 `type:"integer"`
StrVal *string `type:"string"`
}
type emptyType struct {
_ struct{} `type:"structure"`
}
type ignoreNested struct {
_ struct{} `type:"structure"`
IgnoreMe *string `type:"string" ignore:"true"`
}
func TestBuildXML(t *testing.T) {
cases := map[string]struct {
Input interface{}
Expect string
}{
"explicit payload": {
Input: &explicitPayload{
Second: &nestedType{
IntVal: aws.Int64(1234),
StrVal: aws.String("string value"),
},
},
Expect: `<Second><IntVal>1234</IntVal><StrVal>string value</StrVal></Second>`,
},
"implicit payload": {
Input: &implicitPayload{
StrVal: aws.String("string value"),
Second: &nestedType{
IntVal: aws.Int64(1111),
StrVal: aws.String("second string"),
},
Third: &nestedType{
IntVal: aws.Int64(2222),
StrVal: aws.String("third string"),
},
},
Expect: `<Second><IntVal>1111</IntVal><StrVal>second string</StrVal></Second><StrVal>string value</StrVal><Third><IntVal>2222</IntVal><StrVal>third string</StrVal></Third>`,
},
"named implicit payload": {
Input: &namedImplicitPayload{
StrVal: aws.String("string value"),
Second: &nestedType{
IntVal: aws.Int64(1111),
StrVal: aws.String("second string"),
},
Third: &nestedType{
IntVal: aws.Int64(2222),
StrVal: aws.String("third string"),
},
},
Expect: `<namedPayload><Second><IntVal>1111</IntVal><StrVal>second string</StrVal></Second><StrVal>string value</StrVal><Third><IntVal>2222</IntVal><StrVal>third string</StrVal></Third></namedPayload>`,
},
"empty with fields nested type": {
Input: &namedImplicitPayload{
StrVal: aws.String("string value"),
Second: &nestedType{},
Third: &nestedType{
IntVal: aws.Int64(2222),
StrVal: aws.String("third string"),
},
},
Expect: `<namedPayload><Second></Second><StrVal>string value</StrVal><Third><IntVal>2222</IntVal><StrVal>third string</StrVal></Third></namedPayload>`,
},
"empty no fields nested type": {
Input: &useEmptyNested{
StrVal: aws.String("string value"),
Empty: &emptyType{},
},
Expect: `<useEmptyNested><Empty></Empty><StrVal>string value</StrVal></useEmptyNested>`,
},
"ignored nested field": {
Input: &useIgnoreNested{
StrVal: aws.String("string value"),
Ignore: &ignoreNested{
IgnoreMe: aws.String("abc123"),
},
},
Expect: `<useIgnoreNested><Ignore></Ignore><StrVal>string value</StrVal></useIgnoreNested>`,
},
"skip non payload root": {
Input: &skipNonPayload{
Field: aws.String("value"),
},
Expect: "",
},
"skip empty root": {
Input: &emptyType{},
Expect: "",
},
"named empty payload": {
Input: &namedEmptyPayload{},
Expect: "<namedEmptyPayload></namedEmptyPayload>",
},
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
var w bytes.Buffer
if err := buildXML(c.Input, xml.NewEncoder(&w), true); err != nil {
t.Fatalf("expect no error, %v", err)
}
if e, a := c.Expect, w.String(); e != a {
t.Errorf("expect:\n%s\nactual:\n%s\n", e, a)
}
})
}
}
+35 -4
View File
@@ -1,6 +1,7 @@
package xmlutil
import (
"bytes"
"encoding/base64"
"encoding/xml"
"fmt"
@@ -9,8 +10,28 @@ import (
"strconv"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/private/protocol"
)
// UnmarshalXMLError unmarshals the XML error from the stream into the value
// type specified. The value must be a pointer. If the message fails to
// unmarshal, the message content will be included in the returned error as a
// awserr.UnmarshalError.
func UnmarshalXMLError(v interface{}, stream io.Reader) error {
var errBuf bytes.Buffer
body := io.TeeReader(stream, &errBuf)
err := xml.NewDecoder(body).Decode(v)
if err != nil && err != io.EOF {
return awserr.NewUnmarshalError(err,
"failed to unmarshal error message", errBuf.Bytes())
}
return nil
}
// UnmarshalXML deserializes an xml.Decoder into the container v. V
// needs to match the shape of the XML expected to be decoded.
// If the shape doesn't match unmarshaling will fail.
@@ -52,9 +73,15 @@ func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
if t == "" {
switch rtype.Kind() {
case reflect.Struct:
t = "structure"
// also it can't be a time object
if _, ok := r.Interface().(*time.Time); !ok {
t = "structure"
}
case reflect.Slice:
t = "list"
// also it can't be a byte slice
if _, ok := r.Interface().([]byte); !ok {
t = "list"
}
case reflect.Map:
t = "map"
}
@@ -247,8 +274,12 @@ func parseScalar(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
}
r.Set(reflect.ValueOf(&v))
case *time.Time:
const ISO8601UTC = "2006-01-02T15:04:05Z"
t, err := time.Parse(ISO8601UTC, node.Text)
format := tag.Get("timestampFormat")
if len(format) == 0 {
format = protocol.ISO8601TimeFormatName
}
t, err := protocol.ParseTime(format, node.Text)
if err != nil {
return err
}
@@ -29,6 +29,7 @@ func NewXMLElement(name xml.Name) *XMLNode {
// AddChild adds child to the XMLNode.
func (n *XMLNode) AddChild(child *XMLNode) {
child.parent = n
if _, ok := n.Children[child.Name.Local]; !ok {
n.Children[child.Name.Local] = []*XMLNode{}
}