diff --git a/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsProtocolUtils.java b/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsProtocolUtils.java index aca8be5edbb..fd7d7f7e1b8 100644 --- a/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsProtocolUtils.java +++ b/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsProtocolUtils.java @@ -103,6 +103,89 @@ static void generateHttpProtocolTests(GenerationContext context) { .build()); Set inputSkipTests = new TreeSet<>(SetUtils.of( + // Smithy 1.6 changed unit tests that the SDK codegen don't support or are opinionated. + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.restjson#RestJson")) + .operation(ShapeId.from("aws.protocoltests.restjson#EmptyInputAndEmptyOutput")) + .addTestName("RestJsonEmptyInputAndEmptyOutputWithJson") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.restjson#RestJson")) + .operation(ShapeId.from("aws.protocoltests.restjson#EndpointOperation")) + .addTestName("RestJsonEndpointTrait") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.restjson#RestJson")) + .operation(ShapeId.from("aws.protocoltests.restjson#EndpointWithHostLabelOperation")) + .addTestName("RestJsonEndpointTraitWithHostLabel") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.ec2#AwsEc2")) + .operation(ShapeId.from("aws.protocoltests.ec2#EndpointOperation")) + .addTestName("Ec2QueryEndpointTrait") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.ec2#AwsEc2")) + .operation(ShapeId.from("aws.protocoltests.ec2#EndpointWithHostLabelOperation")) + .addTestName("Ec2QueryEndpointTraitWithHostLabel") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.json#JsonProtocol")) + .operation(ShapeId.from("aws.protocoltests.json#EmptyOperation")) + .addTestName("json_1_1_service_supports_empty_payload_for_no_input_shape") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.json#JsonProtocol")) + .operation(ShapeId.from("aws.protocoltests.json#EndpointOperation")) + .addTestName("AwsJson11EndpointTrait") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.json#JsonProtocol")) + .operation(ShapeId.from("aws.protocoltests.json#EndpointWithHostLabelOperation")) + .addTestName("AwsJson11EndpointTraitWithHostLabel") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.json10#JsonRpc10")) + .operation(ShapeId.from("aws.protocoltests.json10#NoInputAndNoOutput")) + .addTestName("AwsJson10ServiceSupportsNoPayloadForNoInput") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.json10#JsonRpc10")) + .operation(ShapeId.from("aws.protocoltests.json10#EndpointOperation")) + .addTestName("AwsJson10EndpointTrait") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.json10#JsonRpc10")) + .operation(ShapeId.from("aws.protocoltests.json10#EndpointWithHostLabelOperation")) + .addTestName("AwsJson10EndpointTraitWithHostLabel") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.query#AwsQuery")) + .operation(ShapeId.from("aws.protocoltests.query#EndpointOperation")) + .addTestName("AwsQueryEndpointTrait") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.query#AwsQuery")) + .operation(ShapeId.from("aws.protocoltests.query#EndpointWithHostLabelOperation")) + .addTestName("AwsQueryEndpointTraitWithHostLabel") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.restxml#RestXml")) + .operation(ShapeId.from("aws.protocoltests.restxml#EndpointOperation")) + .addTestName("RestXmlEndpointTrait") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.restxml#RestXml")) + .operation(ShapeId.from("aws.protocoltests.restxml#EndpointWithHostLabelHeaderOperation")) + .addTestName("RestXmlEndpointTraitWithHostLabelAndHttpBinding") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.restxml#RestXml")) + .operation(ShapeId.from("aws.protocoltests.restxml#EndpointWithHostLabelOperation")) + .addTestName("RestXmlEndpointTraitWithHostLabel") + .build(), + + // REST-JSON Documents HttpProtocolUnitTestGenerator.SkipTest.builder() .service(ShapeId.from("aws.protocoltests.restjson#RestJson")) diff --git a/internal/protocoltest/awsrestjson/api_op_EmptyInputAndEmptyOutput_test.go b/internal/protocoltest/awsrestjson/api_op_EmptyInputAndEmptyOutput_test.go index 4f384704ca4..417f06e80f4 100644 --- a/internal/protocoltest/awsrestjson/api_op_EmptyInputAndEmptyOutput_test.go +++ b/internal/protocoltest/awsrestjson/api_op_EmptyInputAndEmptyOutput_test.go @@ -34,20 +34,40 @@ func TestClient_EmptyInputAndEmptyOutput_awsRestjson1Serialize(t *testing.T) { BodyMediaType string BodyAssert func(io.Reader) error }{ - // Empty input serializes no payload + // Clients should not serialize a JSON payload when no parameters are given that + // are sent in the body. A service will tolerate clients that omit a payload or + // that send a JSON object. "RestJsonEmptyInputAndEmptyOutput": { Params: &EmptyInputAndEmptyOutputInput{}, ExpectMethod: "POST", ExpectURIPath: "/EmptyInputAndEmptyOutput", ExpectQuery: []smithytesting.QueryItem{}, - BodyMediaType: "application/json", BodyAssert: func(actual io.Reader) error { return smithytesting.CompareReaderEmpty(actual) }, }, + // Similar to RestJsonEmptyInputAndEmptyOutput, but ensures that services + // gracefully handles receiving a JSON object. + "RestJsonEmptyInputAndEmptyOutputWithJson": { + Params: &EmptyInputAndEmptyOutputInput{}, + ExpectMethod: "POST", + ExpectURIPath: "/EmptyInputAndEmptyOutput", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/json"}, + }, + BodyMediaType: "application/json", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareJSONReaderBytes(actual, []byte(`{}`)) + }, + }, } for name, c := range cases { t.Run(name, func(t *testing.T) { + if name == "RestJsonEmptyInputAndEmptyOutputWithJson" { + t.Skip("disabled test aws.protocoltests.restjson#RestJson aws.protocoltests.restjson#EmptyInputAndEmptyOutput") + } + var actualReq *http.Request server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { actualReq = r.Clone(r.Context()) @@ -120,20 +140,24 @@ func TestClient_EmptyInputAndEmptyOutput_awsRestjson1Deserialize(t *testing.T) { Body []byte ExpectResult *EmptyInputAndEmptyOutputOutput }{ - // Empty output serializes no payload + // As of January 2021, server implementations are expected to respond with a JSON + // object regardless of if the output parameters are empty. "RestJsonEmptyInputAndEmptyOutput": { - StatusCode: 200, - BodyMediaType: "application/json", - Body: []byte(``), - ExpectResult: &EmptyInputAndEmptyOutputOutput{}, - }, - // Empty output serializes no payload - "RestJsonEmptyInputAndEmptyJsonObjectOutput": { - StatusCode: 200, + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, BodyMediaType: "application/json", Body: []byte(`{}`), ExpectResult: &EmptyInputAndEmptyOutputOutput{}, }, + // This test ensures that clients can gracefully handle situations where a service + // omits a JSON payload entirely. + "RestJsonEmptyInputAndEmptyOutputJsonObjectOutput": { + StatusCode: 200, + Body: []byte(``), + ExpectResult: &EmptyInputAndEmptyOutputOutput{}, + }, } for name, c := range cases { t.Run(name, func(t *testing.T) { diff --git a/internal/protocoltest/awsrestjson/api_op_EndpointOperation.go b/internal/protocoltest/awsrestjson/api_op_EndpointOperation.go new file mode 100644 index 00000000000..8c006182631 --- /dev/null +++ b/internal/protocoltest/awsrestjson/api_op_EndpointOperation.go @@ -0,0 +1,126 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package awsrestjson + +import ( + "context" + "fmt" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +func (c *Client) EndpointOperation(ctx context.Context, params *EndpointOperationInput, optFns ...func(*Options)) (*EndpointOperationOutput, error) { + if params == nil { + params = &EndpointOperationInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "EndpointOperation", params, optFns, addOperationEndpointOperationMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*EndpointOperationOutput) + out.ResultMetadata = metadata + return out, nil +} + +type EndpointOperationInput struct { +} + +type EndpointOperationOutput struct { + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata +} + +func addOperationEndpointOperationMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsRestjson1_serializeOpEndpointOperation{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsRestjson1_deserializeOpEndpointOperation{}, middleware.After) + if err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = addEndpointPrefix_opEndpointOperationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opEndpointOperation(options.Region), middleware.Before); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + return nil +} + +type endpointPrefix_opEndpointOperationMiddleware struct { +} + +func (*endpointPrefix_opEndpointOperationMiddleware) ID() string { + return "EndpointHostPrefix" +} + +func (m *endpointPrefix_opEndpointOperationMiddleware) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + if smithyhttp.GetHostnameImmutable(ctx) || smithyhttp.IsEndpointHostPrefixDisabled(ctx) { + return next.HandleSerialize(ctx, in) + } + + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) + } + + req.URL.Host = "foo." + req.URL.Host + + return next.HandleSerialize(ctx, in) +} +func addEndpointPrefix_opEndpointOperationMiddleware(stack *middleware.Stack) error { + return stack.Serialize.Insert(&endpointPrefix_opEndpointOperationMiddleware{}, `OperationSerializer`, middleware.After) +} + +func newServiceMetadataMiddleware_opEndpointOperation(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "EndpointOperation", + } +} diff --git a/internal/protocoltest/awsrestjson/api_op_EndpointOperation_test.go b/internal/protocoltest/awsrestjson/api_op_EndpointOperation_test.go new file mode 100644 index 00000000000..84d857b1c48 --- /dev/null +++ b/internal/protocoltest/awsrestjson/api_op_EndpointOperation_test.go @@ -0,0 +1,114 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package awsrestjson + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/smithy-go/middleware" + smithyrand "github.com/aws/smithy-go/rand" + smithytesting "github.com/aws/smithy-go/testing" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +func TestClient_EndpointOperation_awsRestjson1Serialize(t *testing.T) { + cases := map[string]struct { + Params *EndpointOperationInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Operations can prepend to the given host if they define the endpoint trait. + "RestJsonEndpointTrait": { + Params: &EndpointOperationInput{}, + ExpectMethod: "POST", + ExpectURIPath: "/EndpointOperation", + ExpectQuery: []smithytesting.QueryItem{}, + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareReaderEmpty(actual) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if name == "RestJsonEndpointTrait" { + t.Skip("disabled test aws.protocoltests.restjson#RestJson aws.protocoltests.restjson#EndpointOperation") + } + + var actualReq *http.Request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + actualReq = r.Clone(r.Context()) + if len(actualReq.URL.RawPath) == 0 { + actualReq.URL.RawPath = actualReq.URL.Path + } + if v := actualReq.ContentLength; v != 0 { + actualReq.Header.Set("Content-Length", strconv.FormatInt(v, 10)) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, r.Body); err != nil { + t.Errorf("failed to read request body, %v", err) + } + actualReq.Body = ioutil.NopCloser(&buf) + + w.WriteHeader(200) + })) + defer server.Close() + url := server.URL + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = url + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: awshttp.NewBuildableClient(), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + result, err := client.EndpointOperation(context.Background(), c.Params) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} diff --git a/internal/protocoltest/awsrestjson/api_op_EndpointWithHostLabelOperation.go b/internal/protocoltest/awsrestjson/api_op_EndpointWithHostLabelOperation.go new file mode 100644 index 00000000000..85cd368fe16 --- /dev/null +++ b/internal/protocoltest/awsrestjson/api_op_EndpointWithHostLabelOperation.go @@ -0,0 +1,149 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package awsrestjson + +import ( + "context" + "fmt" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + smithy "github.com/aws/smithy-go" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" + "strings" +) + +func (c *Client) EndpointWithHostLabelOperation(ctx context.Context, params *EndpointWithHostLabelOperationInput, optFns ...func(*Options)) (*EndpointWithHostLabelOperationOutput, error) { + if params == nil { + params = &EndpointWithHostLabelOperationInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "EndpointWithHostLabelOperation", params, optFns, addOperationEndpointWithHostLabelOperationMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*EndpointWithHostLabelOperationOutput) + out.ResultMetadata = metadata + return out, nil +} + +type EndpointWithHostLabelOperationInput struct { + + // This member is required. + Label *string +} + +type EndpointWithHostLabelOperationOutput struct { + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata +} + +func addOperationEndpointWithHostLabelOperationMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsRestjson1_serializeOpEndpointWithHostLabelOperation{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsRestjson1_deserializeOpEndpointWithHostLabelOperation{}, middleware.After) + if err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = addEndpointPrefix_opEndpointWithHostLabelOperationMiddleware(stack); err != nil { + return err + } + if err = addOpEndpointWithHostLabelOperationValidationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opEndpointWithHostLabelOperation(options.Region), middleware.Before); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + return nil +} + +type endpointPrefix_opEndpointWithHostLabelOperationMiddleware struct { +} + +func (*endpointPrefix_opEndpointWithHostLabelOperationMiddleware) ID() string { + return "EndpointHostPrefix" +} + +func (m *endpointPrefix_opEndpointWithHostLabelOperationMiddleware) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + if smithyhttp.GetHostnameImmutable(ctx) || smithyhttp.IsEndpointHostPrefixDisabled(ctx) { + return next.HandleSerialize(ctx, in) + } + + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) + } + + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input type %T", in.Parameters) + } + + var prefix strings.Builder + prefix.WriteString("foo.") + if input.Label == nil { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("Label forms part of the endpoint host and so may not be nil")} + } else if !smithyhttp.ValidHostLabel(*input.Label) { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("Label forms part of the endpoint host and so must match \"[a-zA-Z0-9-]{1,63}\", but was \"%s\"", *input.Label)} + } else { + prefix.WriteString(*input.Label) + } + prefix.WriteString(".") + req.URL.Host = prefix.String() + req.URL.Host + + return next.HandleSerialize(ctx, in) +} +func addEndpointPrefix_opEndpointWithHostLabelOperationMiddleware(stack *middleware.Stack) error { + return stack.Serialize.Insert(&endpointPrefix_opEndpointWithHostLabelOperationMiddleware{}, `OperationSerializer`, middleware.After) +} + +func newServiceMetadataMiddleware_opEndpointWithHostLabelOperation(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "EndpointWithHostLabelOperation", + } +} diff --git a/internal/protocoltest/awsrestjson/api_op_EndpointWithHostLabelOperation_test.go b/internal/protocoltest/awsrestjson/api_op_EndpointWithHostLabelOperation_test.go new file mode 100644 index 00000000000..5274d201e62 --- /dev/null +++ b/internal/protocoltest/awsrestjson/api_op_EndpointWithHostLabelOperation_test.go @@ -0,0 +1,120 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package awsrestjson + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/ptr" + smithyrand "github.com/aws/smithy-go/rand" + smithytesting "github.com/aws/smithy-go/testing" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +func TestClient_EndpointWithHostLabelOperation_awsRestjson1Serialize(t *testing.T) { + cases := map[string]struct { + Params *EndpointWithHostLabelOperationInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Operations can prepend to the given host if they define the endpoint trait, and + // can use the host label trait to define further customization based on user + // input. + "RestJsonEndpointTraitWithHostLabel": { + Params: &EndpointWithHostLabelOperationInput{ + Label: ptr.String("bar"), + }, + ExpectMethod: "POST", + ExpectURIPath: "/EndpointWithHostLabelOperation", + ExpectQuery: []smithytesting.QueryItem{}, + BodyMediaType: "application/json", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareJSONReaderBytes(actual, []byte(`{"label": "bar"}`)) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if name == "RestJsonEndpointTraitWithHostLabel" { + t.Skip("disabled test aws.protocoltests.restjson#RestJson aws.protocoltests.restjson#EndpointWithHostLabelOperation") + } + + var actualReq *http.Request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + actualReq = r.Clone(r.Context()) + if len(actualReq.URL.RawPath) == 0 { + actualReq.URL.RawPath = actualReq.URL.Path + } + if v := actualReq.ContentLength; v != 0 { + actualReq.Header.Set("Content-Length", strconv.FormatInt(v, 10)) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, r.Body); err != nil { + t.Errorf("failed to read request body, %v", err) + } + actualReq.Body = ioutil.NopCloser(&buf) + + w.WriteHeader(200) + })) + defer server.Close() + url := server.URL + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = url + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: awshttp.NewBuildableClient(), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + result, err := client.EndpointWithHostLabelOperation(context.Background(), c.Params) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} diff --git a/internal/protocoltest/awsrestjson/api_op_GreetingWithErrors_test.go b/internal/protocoltest/awsrestjson/api_op_GreetingWithErrors_test.go index 935d8bf6e70..d388c4a0394 100644 --- a/internal/protocoltest/awsrestjson/api_op_GreetingWithErrors_test.go +++ b/internal/protocoltest/awsrestjson/api_op_GreetingWithErrors_test.go @@ -27,18 +27,28 @@ func TestClient_GreetingWithErrors_awsRestjson1Deserialize(t *testing.T) { Body []byte ExpectResult *GreetingWithErrorsOutput }{ - // Ensures that operations with errors successfully know how to deserialize the - // successful response + // Ensures that operations with errors successfully know how to deserialize a + // successful response. As of January 2021, server implementations are expected to + // respond with a JSON object regardless of if the output parameters are empty. "RestJsonGreetingWithErrors": { StatusCode: 200, Header: http.Header{ - "Content-Type": []string{"application/json"}, - "X-Greeting": []string{"Hello"}, + "X-Greeting": []string{"Hello"}, }, BodyMediaType: "application/json", - Body: []byte(`{ - "greeting": "Hello" - }`), + Body: []byte(`{}`), + ExpectResult: &GreetingWithErrorsOutput{ + Greeting: ptr.String("Hello"), + }, + }, + // This test is similar to RestJsonGreetingWithErrors, but it ensures that clients + // can gracefully deal with a server omitting a response payload. + "RestJsonGreetingWithErrorsNoPayload": { + StatusCode: 200, + Header: http.Header{ + "X-Greeting": []string{"Hello"}, + }, + Body: []byte(``), ExpectResult: &GreetingWithErrorsOutput{ Greeting: ptr.String("Hello"), }, diff --git a/internal/protocoltest/awsrestjson/api_op_HttpPayloadTraits_test.go b/internal/protocoltest/awsrestjson/api_op_HttpPayloadTraits_test.go index e2cfdad1828..3f078a73e32 100644 --- a/internal/protocoltest/awsrestjson/api_op_HttpPayloadTraits_test.go +++ b/internal/protocoltest/awsrestjson/api_op_HttpPayloadTraits_test.go @@ -45,7 +45,8 @@ func TestClient_HttpPayloadTraits_awsRestjson1Serialize(t *testing.T) { ExpectURIPath: "/HttpPayloadTraits", ExpectQuery: []smithytesting.QueryItem{}, ExpectHeader: http.Header{ - "X-Foo": []string{"Foo"}, + "Content-Type": []string{"application/octet-stream"}, + "X-Foo": []string{"Foo"}, }, RequireHeader: []string{ "Content-Length", diff --git a/internal/protocoltest/awsrestjson/api_op_HttpResponseCode_test.go b/internal/protocoltest/awsrestjson/api_op_HttpResponseCode_test.go index 8ae6db74aa7..f000e33ce2a 100644 --- a/internal/protocoltest/awsrestjson/api_op_HttpResponseCode_test.go +++ b/internal/protocoltest/awsrestjson/api_op_HttpResponseCode_test.go @@ -25,14 +25,26 @@ func TestClient_HttpResponseCode_awsRestjson1Deserialize(t *testing.T) { Body []byte ExpectResult *HttpResponseCodeOutput }{ - // Binds the http response code to an output structure. + // Binds the http response code to an output structure. Note that even though all + // members are bound outside of the payload, an empty JSON object is serialized in + // the response. However, clients should be able to handle an empty JSON object or + // an empty payload without failing to deserialize a response. "RestJsonHttpResponseCode": { StatusCode: 201, Header: http.Header{ "Content-Type": []string{"application/json"}, }, - BodyMediaType: "json", - Body: []byte(``), + BodyMediaType: "application/json", + Body: []byte(`{}`), + ExpectResult: &HttpResponseCodeOutput{ + Status: ptr.Int32(201), + }, + }, + // This test ensures that clients gracefully handle cases where the service + // responds with no payload rather than an empty JSON object. + "RestJsonHttpResponseCodeWithNoPayload": { + StatusCode: 201, + Body: []byte(``), ExpectResult: &HttpResponseCodeOutput{ Status: ptr.Int32(201), }, diff --git a/internal/protocoltest/awsrestjson/api_op_IgnoreQueryParamsInResponse_test.go b/internal/protocoltest/awsrestjson/api_op_IgnoreQueryParamsInResponse_test.go index 3d47de55794..24ac3b6eaa6 100644 --- a/internal/protocoltest/awsrestjson/api_op_IgnoreQueryParamsInResponse_test.go +++ b/internal/protocoltest/awsrestjson/api_op_IgnoreQueryParamsInResponse_test.go @@ -24,16 +24,26 @@ func TestClient_IgnoreQueryParamsInResponse_awsRestjson1Deserialize(t *testing.T Body []byte ExpectResult *IgnoreQueryParamsInResponseOutput }{ - // Query parameters must be ignored when serializing the output of an operation + // Query parameters must be ignored when serializing the output of an operation. As + // of January 2021, server implementations are expected to respond with a JSON + // object regardless of if the output parameters are empty. "RestJsonIgnoreQueryParamsInResponse": { StatusCode: 200, Header: http.Header{ "Content-Type": []string{"application/json"}, }, - BodyMediaType: "json", - Body: []byte(``), + BodyMediaType: "application/json", + Body: []byte(`{}`), ExpectResult: &IgnoreQueryParamsInResponseOutput{}, }, + // This test is similar to RestJsonIgnoreQueryParamsInResponse, but it ensures that + // clients gracefully handle responses from the server that do not serialize an + // empty JSON object. + "RestJsonIgnoreQueryParamsInResponseNoPayload": { + StatusCode: 200, + Body: []byte(``), + ExpectResult: &IgnoreQueryParamsInResponseOutput{}, + }, } for name, c := range cases { t.Run(name, func(t *testing.T) { diff --git a/internal/protocoltest/awsrestjson/api_op_NoInputAndNoOutput_test.go b/internal/protocoltest/awsrestjson/api_op_NoInputAndNoOutput_test.go index fe08e8a4310..28023cece49 100644 --- a/internal/protocoltest/awsrestjson/api_op_NoInputAndNoOutput_test.go +++ b/internal/protocoltest/awsrestjson/api_op_NoInputAndNoOutput_test.go @@ -34,12 +34,16 @@ func TestClient_NoInputAndNoOutput_awsRestjson1Serialize(t *testing.T) { BodyMediaType string BodyAssert func(io.Reader) error }{ - // No input serializes no payload + // No input serializes no payload. When clients do not need to serialize any data + // in the payload, they should omit a payload altogether. "RestJsonNoInputAndNoOutput": { Params: &NoInputAndNoOutputInput{}, ExpectMethod: "POST", ExpectURIPath: "/NoInputAndNoOutput", ExpectQuery: []smithytesting.QueryItem{}, + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareReaderEmpty(actual) + }, }, } for name, c := range cases { @@ -116,9 +120,11 @@ func TestClient_NoInputAndNoOutput_awsRestjson1Deserialize(t *testing.T) { Body []byte ExpectResult *NoInputAndNoOutputOutput }{ - // No output serializes no payload + // When an operation does not define output, the service will respond with an empty + // payload, and may optionally include the content-type header. "RestJsonNoInputAndNoOutput": { StatusCode: 200, + Body: []byte(``), ExpectResult: &NoInputAndNoOutputOutput{}, }, } diff --git a/internal/protocoltest/awsrestjson/api_op_NoInputAndOutput_test.go b/internal/protocoltest/awsrestjson/api_op_NoInputAndOutput_test.go index 585e2863a01..8746dd8a0da 100644 --- a/internal/protocoltest/awsrestjson/api_op_NoInputAndOutput_test.go +++ b/internal/protocoltest/awsrestjson/api_op_NoInputAndOutput_test.go @@ -34,12 +34,16 @@ func TestClient_NoInputAndOutput_awsRestjson1Serialize(t *testing.T) { BodyMediaType string BodyAssert func(io.Reader) error }{ - // No input serializes no payload + // No input serializes no payload. When clients do not need to serialize any data + // in the payload, they should omit a payload altogether. "RestJsonNoInputAndOutput": { Params: &NoInputAndOutputInput{}, ExpectMethod: "POST", ExpectURIPath: "/NoInputAndOutputOutput", ExpectQuery: []smithytesting.QueryItem{}, + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareReaderEmpty(actual) + }, }, } for name, c := range cases { @@ -116,9 +120,22 @@ func TestClient_NoInputAndOutput_awsRestjson1Deserialize(t *testing.T) { Body []byte ExpectResult *NoInputAndOutputOutput }{ - // Empty output serializes no payload - "RestJsonNoInputAndOutput": { + // Operations that define output and do not bind anything to the payload return a + // JSON object in the response. + "RestJsonNoInputAndOutputWithJson": { + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + BodyMediaType: "application/json", + Body: []byte(`{}`), + ExpectResult: &NoInputAndOutputOutput{}, + }, + // This test is similar to RestJsonNoInputAndOutputWithJson, but it ensures that + // clients can gracefully handle responses that omit a JSON payload. + "RestJsonNoInputAndOutputNoPayload": { StatusCode: 200, + Body: []byte(``), ExpectResult: &NoInputAndOutputOutput{}, }, } diff --git a/internal/protocoltest/awsrestjson/deserializers.go b/internal/protocoltest/awsrestjson/deserializers.go index 946db25dd1d..c52c101f83d 100644 --- a/internal/protocoltest/awsrestjson/deserializers.go +++ b/internal/protocoltest/awsrestjson/deserializers.go @@ -361,6 +361,178 @@ func awsRestjson1_deserializeOpErrorEmptyInputAndEmptyOutput(response *smithyhtt } } +type awsRestjson1_deserializeOpEndpointOperation struct { +} + +func (*awsRestjson1_deserializeOpEndpointOperation) ID() string { + return "OperationDeserializer" +} + +func (m *awsRestjson1_deserializeOpEndpointOperation) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsRestjson1_deserializeOpErrorEndpointOperation(response, &metadata) + } + output := &EndpointOperationOutput{} + out.Result = output + + if _, err = io.Copy(ioutil.Discard, response.Body); err != nil { + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to discard response body, %w", err), + } + } + + return out, metadata, err +} + +func awsRestjson1_deserializeOpErrorEndpointOperation(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + code := response.Header.Get("X-Amzn-ErrorType") + if len(code) != 0 { + errorCode = restjson.SanitizeErrorCode(code) + } + + var buff [1024]byte + ringBuffer := smithyio.NewRingBuffer(buff[:]) + + body := io.TeeReader(errorBody, ringBuffer) + decoder := json.NewDecoder(body) + decoder.UseNumber() + code, message, err := restjson.GetErrorInfo(decoder) + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + err = &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + return err + } + + errorBody.Seek(0, io.SeekStart) + if len(code) != 0 { + errorCode = restjson.SanitizeErrorCode(code) + } + if len(message) != 0 { + errorMessage = message + } + + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + +type awsRestjson1_deserializeOpEndpointWithHostLabelOperation struct { +} + +func (*awsRestjson1_deserializeOpEndpointWithHostLabelOperation) ID() string { + return "OperationDeserializer" +} + +func (m *awsRestjson1_deserializeOpEndpointWithHostLabelOperation) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsRestjson1_deserializeOpErrorEndpointWithHostLabelOperation(response, &metadata) + } + output := &EndpointWithHostLabelOperationOutput{} + out.Result = output + + if _, err = io.Copy(ioutil.Discard, response.Body); err != nil { + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to discard response body, %w", err), + } + } + + return out, metadata, err +} + +func awsRestjson1_deserializeOpErrorEndpointWithHostLabelOperation(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + code := response.Header.Get("X-Amzn-ErrorType") + if len(code) != 0 { + errorCode = restjson.SanitizeErrorCode(code) + } + + var buff [1024]byte + ringBuffer := smithyio.NewRingBuffer(buff[:]) + + body := io.TeeReader(errorBody, ringBuffer) + decoder := json.NewDecoder(body) + decoder.UseNumber() + code, message, err := restjson.GetErrorInfo(decoder) + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + err = &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + return err + } + + errorBody.Seek(0, io.SeekStart) + if len(code) != 0 { + errorCode = restjson.SanitizeErrorCode(code) + } + if len(message) != 0 { + errorMessage = message + } + + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + type awsRestjson1_deserializeOpGreetingWithErrors struct { } diff --git a/internal/protocoltest/awsrestjson/go.mod b/internal/protocoltest/awsrestjson/go.mod index 1b0a08a33f5..28c63e43b94 100644 --- a/internal/protocoltest/awsrestjson/go.mod +++ b/internal/protocoltest/awsrestjson/go.mod @@ -1,6 +1,6 @@ module github.com/aws/aws-sdk-go-v2/internal/protocoltest/awsrestjson -go 1.15 +go 1.16 require ( github.com/aws/aws-sdk-go-v2 v1.2.0 diff --git a/internal/protocoltest/awsrestjson/serializers.go b/internal/protocoltest/awsrestjson/serializers.go index 1f09ebfd2f1..3a9c46f587b 100644 --- a/internal/protocoltest/awsrestjson/serializers.go +++ b/internal/protocoltest/awsrestjson/serializers.go @@ -336,6 +336,129 @@ func awsRestjson1_serializeOpHttpBindingsEmptyInputAndEmptyOutputInput(v *EmptyI return nil } +type awsRestjson1_serializeOpEndpointOperation struct { +} + +func (*awsRestjson1_serializeOpEndpointOperation) ID() string { + return "OperationSerializer" +} + +func (m *awsRestjson1_serializeOpEndpointOperation) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*EndpointOperationInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + opPath, opQuery := httpbinding.SplitURI("/EndpointOperation") + request.URL.Path = opPath + if len(request.URL.RawQuery) > 0 { + request.URL.RawQuery = "&" + opQuery + } else { + request.URL.RawQuery = opQuery + } + + request.Method = "POST" + restEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = restEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} +func awsRestjson1_serializeOpHttpBindingsEndpointOperationInput(v *EndpointOperationInput, encoder *httpbinding.Encoder) error { + if v == nil { + return fmt.Errorf("unsupported serialization of nil %T", v) + } + + return nil +} + +type awsRestjson1_serializeOpEndpointWithHostLabelOperation struct { +} + +func (*awsRestjson1_serializeOpEndpointWithHostLabelOperation) ID() string { + return "OperationSerializer" +} + +func (m *awsRestjson1_serializeOpEndpointWithHostLabelOperation) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + opPath, opQuery := httpbinding.SplitURI("/EndpointWithHostLabelOperation") + request.URL.Path = opPath + if len(request.URL.RawQuery) > 0 { + request.URL.RawQuery = "&" + opQuery + } else { + request.URL.RawQuery = opQuery + } + + request.Method = "POST" + restEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + restEncoder.SetHeader("Content-Type").String("application/json") + + jsonEncoder := smithyjson.NewEncoder() + if err := awsRestjson1_serializeOpDocumentEndpointWithHostLabelOperationInput(input, jsonEncoder.Value); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request, err = request.SetStream(bytes.NewReader(jsonEncoder.Bytes())); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = restEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} +func awsRestjson1_serializeOpHttpBindingsEndpointWithHostLabelOperationInput(v *EndpointWithHostLabelOperationInput, encoder *httpbinding.Encoder) error { + if v == nil { + return fmt.Errorf("unsupported serialization of nil %T", v) + } + + return nil +} + +func awsRestjson1_serializeOpDocumentEndpointWithHostLabelOperationInput(v *EndpointWithHostLabelOperationInput, value smithyjson.Value) error { + object := value.Object() + defer object.Close() + + if v.Label != nil { + ok := object.Key("label") + ok.String(*v.Label) + } + + return nil +} + type awsRestjson1_serializeOpGreetingWithErrors struct { } diff --git a/internal/protocoltest/awsrestjson/validators.go b/internal/protocoltest/awsrestjson/validators.go index 58a0434181f..533846c06c4 100644 --- a/internal/protocoltest/awsrestjson/validators.go +++ b/internal/protocoltest/awsrestjson/validators.go @@ -29,6 +29,26 @@ func (m *validateOpConstantQueryString) HandleInitialize(ctx context.Context, in return next.HandleInitialize(ctx, in) } +type validateOpEndpointWithHostLabelOperation struct { +} + +func (*validateOpEndpointWithHostLabelOperation) ID() string { + return "OperationInputValidation" +} + +func (m *validateOpEndpointWithHostLabelOperation) HandleInitialize(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) ( + out middleware.InitializeOutput, metadata middleware.Metadata, err error, +) { + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input parameters type %T", in.Parameters) + } + if err := validateOpEndpointWithHostLabelOperationInput(input); err != nil { + return out, metadata, err + } + return next.HandleInitialize(ctx, in) +} + type validateOpHttpRequestWithGreedyLabelInPath struct { } @@ -93,6 +113,10 @@ func addOpConstantQueryStringValidationMiddleware(stack *middleware.Stack) error return stack.Initialize.Add(&validateOpConstantQueryString{}, middleware.After) } +func addOpEndpointWithHostLabelOperationValidationMiddleware(stack *middleware.Stack) error { + return stack.Initialize.Add(&validateOpEndpointWithHostLabelOperation{}, middleware.After) +} + func addOpHttpRequestWithGreedyLabelInPathValidationMiddleware(stack *middleware.Stack) error { return stack.Initialize.Add(&validateOpHttpRequestWithGreedyLabelInPath{}, middleware.After) } @@ -120,6 +144,21 @@ func validateOpConstantQueryStringInput(v *ConstantQueryStringInput) error { } } +func validateOpEndpointWithHostLabelOperationInput(v *EndpointWithHostLabelOperationInput) error { + if v == nil { + return nil + } + invalidParams := smithy.InvalidParamsError{Context: "EndpointWithHostLabelOperationInput"} + if v.Label == nil { + invalidParams.Add(smithy.NewErrParamRequired("Label")) + } + if invalidParams.Len() > 0 { + return invalidParams + } else { + return nil + } +} + func validateOpHttpRequestWithGreedyLabelInPathInput(v *HttpRequestWithGreedyLabelInPathInput) error { if v == nil { return nil diff --git a/internal/protocoltest/ec2query/api_op_EndpointOperation.go b/internal/protocoltest/ec2query/api_op_EndpointOperation.go new file mode 100644 index 00000000000..38536348923 --- /dev/null +++ b/internal/protocoltest/ec2query/api_op_EndpointOperation.go @@ -0,0 +1,126 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package ec2query + +import ( + "context" + "fmt" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +func (c *Client) EndpointOperation(ctx context.Context, params *EndpointOperationInput, optFns ...func(*Options)) (*EndpointOperationOutput, error) { + if params == nil { + params = &EndpointOperationInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "EndpointOperation", params, optFns, addOperationEndpointOperationMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*EndpointOperationOutput) + out.ResultMetadata = metadata + return out, nil +} + +type EndpointOperationInput struct { +} + +type EndpointOperationOutput struct { + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata +} + +func addOperationEndpointOperationMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsEc2query_serializeOpEndpointOperation{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsEc2query_deserializeOpEndpointOperation{}, middleware.After) + if err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = addEndpointPrefix_opEndpointOperationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opEndpointOperation(options.Region), middleware.Before); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + return nil +} + +type endpointPrefix_opEndpointOperationMiddleware struct { +} + +func (*endpointPrefix_opEndpointOperationMiddleware) ID() string { + return "EndpointHostPrefix" +} + +func (m *endpointPrefix_opEndpointOperationMiddleware) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + if smithyhttp.GetHostnameImmutable(ctx) || smithyhttp.IsEndpointHostPrefixDisabled(ctx) { + return next.HandleSerialize(ctx, in) + } + + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) + } + + req.URL.Host = "foo." + req.URL.Host + + return next.HandleSerialize(ctx, in) +} +func addEndpointPrefix_opEndpointOperationMiddleware(stack *middleware.Stack) error { + return stack.Serialize.Insert(&endpointPrefix_opEndpointOperationMiddleware{}, `OperationSerializer`, middleware.After) +} + +func newServiceMetadataMiddleware_opEndpointOperation(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "EndpointOperation", + } +} diff --git a/internal/protocoltest/ec2query/api_op_EndpointOperation_test.go b/internal/protocoltest/ec2query/api_op_EndpointOperation_test.go new file mode 100644 index 00000000000..e894126d5ac --- /dev/null +++ b/internal/protocoltest/ec2query/api_op_EndpointOperation_test.go @@ -0,0 +1,119 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package ec2query + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/smithy-go/middleware" + smithyrand "github.com/aws/smithy-go/rand" + smithytesting "github.com/aws/smithy-go/testing" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +func TestClient_EndpointOperation_awsEc2querySerialize(t *testing.T) { + cases := map[string]struct { + Params *EndpointOperationInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Operations can prepend to the given host if they define the endpoint trait. + "Ec2QueryEndpointTrait": { + Params: &EndpointOperationInput{}, + ExpectMethod: "POST", + ExpectURIPath: "/", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/x-www-form-urlencoded"}, + }, + BodyMediaType: "application/x-www-form-urlencoded", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareURLFormReaderBytes(actual, []byte(`Action=EndpointOperation + &Version=2020-01-08`)) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if name == "Ec2QueryEndpointTrait" { + t.Skip("disabled test aws.protocoltests.ec2#AwsEc2 aws.protocoltests.ec2#EndpointOperation") + } + + var actualReq *http.Request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + actualReq = r.Clone(r.Context()) + if len(actualReq.URL.RawPath) == 0 { + actualReq.URL.RawPath = actualReq.URL.Path + } + if v := actualReq.ContentLength; v != 0 { + actualReq.Header.Set("Content-Length", strconv.FormatInt(v, 10)) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, r.Body); err != nil { + t.Errorf("failed to read request body, %v", err) + } + actualReq.Body = ioutil.NopCloser(&buf) + + w.WriteHeader(200) + })) + defer server.Close() + url := server.URL + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = url + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: awshttp.NewBuildableClient(), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + result, err := client.EndpointOperation(context.Background(), c.Params) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} diff --git a/internal/protocoltest/ec2query/api_op_EndpointWithHostLabelOperation.go b/internal/protocoltest/ec2query/api_op_EndpointWithHostLabelOperation.go new file mode 100644 index 00000000000..ffa7c36736e --- /dev/null +++ b/internal/protocoltest/ec2query/api_op_EndpointWithHostLabelOperation.go @@ -0,0 +1,149 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package ec2query + +import ( + "context" + "fmt" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + smithy "github.com/aws/smithy-go" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" + "strings" +) + +func (c *Client) EndpointWithHostLabelOperation(ctx context.Context, params *EndpointWithHostLabelOperationInput, optFns ...func(*Options)) (*EndpointWithHostLabelOperationOutput, error) { + if params == nil { + params = &EndpointWithHostLabelOperationInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "EndpointWithHostLabelOperation", params, optFns, addOperationEndpointWithHostLabelOperationMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*EndpointWithHostLabelOperationOutput) + out.ResultMetadata = metadata + return out, nil +} + +type EndpointWithHostLabelOperationInput struct { + + // This member is required. + Label *string +} + +type EndpointWithHostLabelOperationOutput struct { + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata +} + +func addOperationEndpointWithHostLabelOperationMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsEc2query_serializeOpEndpointWithHostLabelOperation{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsEc2query_deserializeOpEndpointWithHostLabelOperation{}, middleware.After) + if err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = addEndpointPrefix_opEndpointWithHostLabelOperationMiddleware(stack); err != nil { + return err + } + if err = addOpEndpointWithHostLabelOperationValidationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opEndpointWithHostLabelOperation(options.Region), middleware.Before); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + return nil +} + +type endpointPrefix_opEndpointWithHostLabelOperationMiddleware struct { +} + +func (*endpointPrefix_opEndpointWithHostLabelOperationMiddleware) ID() string { + return "EndpointHostPrefix" +} + +func (m *endpointPrefix_opEndpointWithHostLabelOperationMiddleware) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + if smithyhttp.GetHostnameImmutable(ctx) || smithyhttp.IsEndpointHostPrefixDisabled(ctx) { + return next.HandleSerialize(ctx, in) + } + + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) + } + + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input type %T", in.Parameters) + } + + var prefix strings.Builder + prefix.WriteString("foo.") + if input.Label == nil { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("Label forms part of the endpoint host and so may not be nil")} + } else if !smithyhttp.ValidHostLabel(*input.Label) { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("Label forms part of the endpoint host and so must match \"[a-zA-Z0-9-]{1,63}\", but was \"%s\"", *input.Label)} + } else { + prefix.WriteString(*input.Label) + } + prefix.WriteString(".") + req.URL.Host = prefix.String() + req.URL.Host + + return next.HandleSerialize(ctx, in) +} +func addEndpointPrefix_opEndpointWithHostLabelOperationMiddleware(stack *middleware.Stack) error { + return stack.Serialize.Insert(&endpointPrefix_opEndpointWithHostLabelOperationMiddleware{}, `OperationSerializer`, middleware.After) +} + +func newServiceMetadataMiddleware_opEndpointWithHostLabelOperation(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "EndpointWithHostLabelOperation", + } +} diff --git a/internal/protocoltest/ec2query/api_op_EndpointWithHostLabelOperation_test.go b/internal/protocoltest/ec2query/api_op_EndpointWithHostLabelOperation_test.go new file mode 100644 index 00000000000..01dcc555da0 --- /dev/null +++ b/internal/protocoltest/ec2query/api_op_EndpointWithHostLabelOperation_test.go @@ -0,0 +1,125 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package ec2query + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/ptr" + smithyrand "github.com/aws/smithy-go/rand" + smithytesting "github.com/aws/smithy-go/testing" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +func TestClient_EndpointWithHostLabelOperation_awsEc2querySerialize(t *testing.T) { + cases := map[string]struct { + Params *EndpointWithHostLabelOperationInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Operations can prepend to the given host if they define the endpoint trait, and + // can use the host label trait to define further customization based on user + // input. + "Ec2QueryEndpointTraitWithHostLabel": { + Params: &EndpointWithHostLabelOperationInput{ + Label: ptr.String("bar"), + }, + ExpectMethod: "POST", + ExpectURIPath: "/", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/x-www-form-urlencoded"}, + }, + BodyMediaType: "application/x-www-form-urlencoded", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareURLFormReaderBytes(actual, []byte(`Action=EndpointWithHostLabelOperation + &Version=2020-01-08 + &Label=bar`)) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if name == "Ec2QueryEndpointTraitWithHostLabel" { + t.Skip("disabled test aws.protocoltests.ec2#AwsEc2 aws.protocoltests.ec2#EndpointWithHostLabelOperation") + } + + var actualReq *http.Request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + actualReq = r.Clone(r.Context()) + if len(actualReq.URL.RawPath) == 0 { + actualReq.URL.RawPath = actualReq.URL.Path + } + if v := actualReq.ContentLength; v != 0 { + actualReq.Header.Set("Content-Length", strconv.FormatInt(v, 10)) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, r.Body); err != nil { + t.Errorf("failed to read request body, %v", err) + } + actualReq.Body = ioutil.NopCloser(&buf) + + w.WriteHeader(200) + })) + defer server.Close() + url := server.URL + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = url + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: awshttp.NewBuildableClient(), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + result, err := client.EndpointWithHostLabelOperation(context.Background(), c.Params) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} diff --git a/internal/protocoltest/ec2query/deserializers.go b/internal/protocoltest/ec2query/deserializers.go index cef93b01448..f9932f4f93b 100644 --- a/internal/protocoltest/ec2query/deserializers.go +++ b/internal/protocoltest/ec2query/deserializers.go @@ -116,6 +116,142 @@ func awsEc2query_deserializeOpErrorEmptyInputAndEmptyOutput(response *smithyhttp } } +type awsEc2query_deserializeOpEndpointOperation struct { +} + +func (*awsEc2query_deserializeOpEndpointOperation) ID() string { + return "OperationDeserializer" +} + +func (m *awsEc2query_deserializeOpEndpointOperation) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsEc2query_deserializeOpErrorEndpointOperation(response, &metadata) + } + output := &EndpointOperationOutput{} + out.Result = output + + if _, err = io.Copy(ioutil.Discard, response.Body); err != nil { + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to discard response body, %w", err), + } + } + + return out, metadata, err +} + +func awsEc2query_deserializeOpErrorEndpointOperation(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + errorComponents, err := ec2query.GetErrorResponseComponents(errorBody) + if err != nil { + return err + } + awsmiddleware.SetRequestIDMetadata(metadata, errorComponents.RequestID) + if len(errorComponents.Code) != 0 { + errorCode = errorComponents.Code + } + if len(errorComponents.Message) != 0 { + errorMessage = errorComponents.Message + } + errorBody.Seek(0, io.SeekStart) + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + +type awsEc2query_deserializeOpEndpointWithHostLabelOperation struct { +} + +func (*awsEc2query_deserializeOpEndpointWithHostLabelOperation) ID() string { + return "OperationDeserializer" +} + +func (m *awsEc2query_deserializeOpEndpointWithHostLabelOperation) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsEc2query_deserializeOpErrorEndpointWithHostLabelOperation(response, &metadata) + } + output := &EndpointWithHostLabelOperationOutput{} + out.Result = output + + if _, err = io.Copy(ioutil.Discard, response.Body); err != nil { + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to discard response body, %w", err), + } + } + + return out, metadata, err +} + +func awsEc2query_deserializeOpErrorEndpointWithHostLabelOperation(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + errorComponents, err := ec2query.GetErrorResponseComponents(errorBody) + if err != nil { + return err + } + awsmiddleware.SetRequestIDMetadata(metadata, errorComponents.RequestID) + if len(errorComponents.Code) != 0 { + errorCode = errorComponents.Code + } + if len(errorComponents.Message) != 0 { + errorMessage = errorComponents.Message + } + errorBody.Seek(0, io.SeekStart) + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + type awsEc2query_deserializeOpGreetingWithErrors struct { } diff --git a/internal/protocoltest/ec2query/go.mod b/internal/protocoltest/ec2query/go.mod index a536c3ec4da..e81edf9eb2a 100644 --- a/internal/protocoltest/ec2query/go.mod +++ b/internal/protocoltest/ec2query/go.mod @@ -1,6 +1,6 @@ module github.com/aws/aws-sdk-go-v2/internal/protocoltest/ec2query -go 1.15 +go 1.16 require ( github.com/aws/aws-sdk-go-v2 v1.2.0 diff --git a/internal/protocoltest/ec2query/serializers.go b/internal/protocoltest/ec2query/serializers.go index 81c4db5f7bd..5af5464e8aa 100644 --- a/internal/protocoltest/ec2query/serializers.go +++ b/internal/protocoltest/ec2query/serializers.go @@ -67,6 +67,114 @@ func (m *awsEc2query_serializeOpEmptyInputAndEmptyOutput) HandleSerialize(ctx co return next.HandleSerialize(ctx, in) } +type awsEc2query_serializeOpEndpointOperation struct { +} + +func (*awsEc2query_serializeOpEndpointOperation) ID() string { + return "OperationSerializer" +} + +func (m *awsEc2query_serializeOpEndpointOperation) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*EndpointOperationInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + request.Request.URL.Path = "/" + request.Request.Method = "POST" + httpBindingEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + httpBindingEncoder.SetHeader("Content-Type").String("application/x-www-form-urlencoded") + + bodyWriter := bytes.NewBuffer(nil) + bodyEncoder := query.NewEncoder(bodyWriter) + body := bodyEncoder.Object() + body.Key("Action").String("EndpointOperation") + body.Key("Version").String("2020-01-08") + + err = bodyEncoder.Encode() + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request, err = request.SetStream(bytes.NewReader(bodyWriter.Bytes())); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = httpBindingEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} + +type awsEc2query_serializeOpEndpointWithHostLabelOperation struct { +} + +func (*awsEc2query_serializeOpEndpointWithHostLabelOperation) ID() string { + return "OperationSerializer" +} + +func (m *awsEc2query_serializeOpEndpointWithHostLabelOperation) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + request.Request.URL.Path = "/" + request.Request.Method = "POST" + httpBindingEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + httpBindingEncoder.SetHeader("Content-Type").String("application/x-www-form-urlencoded") + + bodyWriter := bytes.NewBuffer(nil) + bodyEncoder := query.NewEncoder(bodyWriter) + body := bodyEncoder.Object() + body.Key("Action").String("EndpointWithHostLabelOperation") + body.Key("Version").String("2020-01-08") + + if err := awsEc2query_serializeOpDocumentEndpointWithHostLabelOperationInput(input, bodyEncoder.Value); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + err = bodyEncoder.Encode() + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request, err = request.SetStream(bytes.NewReader(bodyWriter.Bytes())); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = httpBindingEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} + type awsEc2query_serializeOpGreetingWithErrors struct { } @@ -1054,6 +1162,18 @@ func awsEc2query_serializeOpDocumentEmptyInputAndEmptyOutputInput(v *EmptyInputA return nil } +func awsEc2query_serializeOpDocumentEndpointWithHostLabelOperationInput(v *EndpointWithHostLabelOperationInput, value query.Value) error { + object := value.Object() + _ = object + + if v.Label != nil { + objectKey := object.Key("Label") + objectKey.String(*v.Label) + } + + return nil +} + func awsEc2query_serializeOpDocumentNestedStructuresInput(v *NestedStructuresInput, value query.Value) error { object := value.Object() _ = object diff --git a/internal/protocoltest/ec2query/validators.go b/internal/protocoltest/ec2query/validators.go index b93f77dd5ef..b9acbc34035 100644 --- a/internal/protocoltest/ec2query/validators.go +++ b/internal/protocoltest/ec2query/validators.go @@ -1,3 +1,49 @@ // Code generated by smithy-go-codegen DO NOT EDIT. package ec2query + +import ( + "context" + "fmt" + smithy "github.com/aws/smithy-go" + "github.com/aws/smithy-go/middleware" +) + +type validateOpEndpointWithHostLabelOperation struct { +} + +func (*validateOpEndpointWithHostLabelOperation) ID() string { + return "OperationInputValidation" +} + +func (m *validateOpEndpointWithHostLabelOperation) HandleInitialize(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) ( + out middleware.InitializeOutput, metadata middleware.Metadata, err error, +) { + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input parameters type %T", in.Parameters) + } + if err := validateOpEndpointWithHostLabelOperationInput(input); err != nil { + return out, metadata, err + } + return next.HandleInitialize(ctx, in) +} + +func addOpEndpointWithHostLabelOperationValidationMiddleware(stack *middleware.Stack) error { + return stack.Initialize.Add(&validateOpEndpointWithHostLabelOperation{}, middleware.After) +} + +func validateOpEndpointWithHostLabelOperationInput(v *EndpointWithHostLabelOperationInput) error { + if v == nil { + return nil + } + invalidParams := smithy.InvalidParamsError{Context: "EndpointWithHostLabelOperationInput"} + if v.Label == nil { + invalidParams.Add(smithy.NewErrParamRequired("Label")) + } + if invalidParams.Len() > 0 { + return invalidParams + } else { + return nil + } +} diff --git a/internal/protocoltest/jsonrpc/api_op_EmptyOperation_test.go b/internal/protocoltest/jsonrpc/api_op_EmptyOperation_test.go index 75579e64d07..3a623a056ba 100644 --- a/internal/protocoltest/jsonrpc/api_op_EmptyOperation_test.go +++ b/internal/protocoltest/jsonrpc/api_op_EmptyOperation_test.go @@ -51,9 +51,46 @@ func TestClient_EmptyOperation_awsAwsjson11Serialize(t *testing.T) { "X-Amz-Target": []string{"JsonProtocol.EmptyOperation"}, }, }, + // Clients must always send an empty JSON object payload for operations with no + // input (that is, {}). While AWS service implementations support requests with no + // payload or requests that send {}, always sending {} from the client is preferred + // for forward compatibility in case input is ever added to an operation. + "json_1_1_client_sends_empty_payload_for_no_input_shape": { + Params: &EmptyOperationInput{}, + ExpectMethod: "POST", + ExpectURIPath: "/", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/x-amz-json-1.1"}, + }, + BodyMediaType: "application/json", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareJSONReaderBytes(actual, []byte(`{}`)) + }, + }, + // Service implementations must support no payload or an empty object payload for + // operations that define no input. However, despite the lack of a payload, a + // Content-Type header is still required in order for the service to properly + // detect the protocol. + "json_1_1_service_supports_empty_payload_for_no_input_shape": { + Params: &EmptyOperationInput{}, + ExpectMethod: "POST", + ExpectURIPath: "/", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/x-amz-json-1.1"}, + }, + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareReaderEmpty(actual) + }, + }, } for name, c := range cases { t.Run(name, func(t *testing.T) { + if name == "json_1_1_service_supports_empty_payload_for_no_input_shape" { + t.Skip("disabled test aws.protocoltests.json#JsonProtocol aws.protocoltests.json#EmptyOperation") + } + var actualReq *http.Request server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { actualReq = r.Clone(r.Context()) @@ -125,7 +162,9 @@ func TestClient_EmptyOperation_awsAwsjson11Deserialize(t *testing.T) { Body []byte ExpectResult *EmptyOperationOutput }{ - // Handles empty output shapes + // When no output is defined, the service is expected to return an empty payload, + // however, client must ignore a JSON payload if one is returned. This ensures that + // if output is added later, then it will not break the client. "handles_empty_output_shape": { StatusCode: 200, Header: http.Header{ @@ -135,6 +174,32 @@ func TestClient_EmptyOperation_awsAwsjson11Deserialize(t *testing.T) { Body: []byte(`{}`), ExpectResult: &EmptyOperationOutput{}, }, + // This client-only test builds on handles_empty_output_shape, by including + // unexpected fields in the JSON. A client needs to ignore JSON output that is + // empty or that contains JSON object data. + "handles_unexpected_json_output": { + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/x-amz-json-1.1"}, + }, + BodyMediaType: "application/json", + Body: []byte(`{ + "foo": true + }`), + ExpectResult: &EmptyOperationOutput{}, + }, + // When no output is defined, the service is expected to return an empty payload. + // Despite the lack of a payload, the service is expected to always send a + // Content-Type header. Clients must handle cases where a service returns a JSON + // object and where a service returns no JSON at all. + "json_1_1_service_responds_with_no_payload": { + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/x-amz-json-1.1"}, + }, + Body: []byte(``), + ExpectResult: &EmptyOperationOutput{}, + }, } for name, c := range cases { t.Run(name, func(t *testing.T) { diff --git a/internal/protocoltest/jsonrpc/api_op_EndpointOperation.go b/internal/protocoltest/jsonrpc/api_op_EndpointOperation.go new file mode 100644 index 00000000000..797f6264841 --- /dev/null +++ b/internal/protocoltest/jsonrpc/api_op_EndpointOperation.go @@ -0,0 +1,134 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package jsonrpc + +import ( + "context" + "fmt" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +func (c *Client) EndpointOperation(ctx context.Context, params *EndpointOperationInput, optFns ...func(*Options)) (*EndpointOperationOutput, error) { + if params == nil { + params = &EndpointOperationInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "EndpointOperation", params, optFns, addOperationEndpointOperationMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*EndpointOperationOutput) + out.ResultMetadata = metadata + return out, nil +} + +type EndpointOperationInput struct { +} + +type EndpointOperationOutput struct { + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata +} + +func addOperationEndpointOperationMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsAwsjson11_serializeOpEndpointOperation{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsAwsjson11_deserializeOpEndpointOperation{}, middleware.After) + if err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = v4.AddComputePayloadSHA256Middleware(stack); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = addHTTPSignerV4Middleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = addEndpointPrefix_opEndpointOperationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opEndpointOperation(options.Region), middleware.Before); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + return nil +} + +type endpointPrefix_opEndpointOperationMiddleware struct { +} + +func (*endpointPrefix_opEndpointOperationMiddleware) ID() string { + return "EndpointHostPrefix" +} + +func (m *endpointPrefix_opEndpointOperationMiddleware) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + if smithyhttp.GetHostnameImmutable(ctx) || smithyhttp.IsEndpointHostPrefixDisabled(ctx) { + return next.HandleSerialize(ctx, in) + } + + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) + } + + req.URL.Host = "foo." + req.URL.Host + + return next.HandleSerialize(ctx, in) +} +func addEndpointPrefix_opEndpointOperationMiddleware(stack *middleware.Stack) error { + return stack.Serialize.Insert(&endpointPrefix_opEndpointOperationMiddleware{}, `OperationSerializer`, middleware.After) +} + +func newServiceMetadataMiddleware_opEndpointOperation(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + SigningName: "foo", + OperationName: "EndpointOperation", + } +} diff --git a/internal/protocoltest/jsonrpc/api_op_EndpointOperation_test.go b/internal/protocoltest/jsonrpc/api_op_EndpointOperation_test.go new file mode 100644 index 00000000000..cc3804bc0be --- /dev/null +++ b/internal/protocoltest/jsonrpc/api_op_EndpointOperation_test.go @@ -0,0 +1,112 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package jsonrpc + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/smithy-go/middleware" + smithytesting "github.com/aws/smithy-go/testing" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +func TestClient_EndpointOperation_awsAwsjson11Serialize(t *testing.T) { + cases := map[string]struct { + Params *EndpointOperationInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Operations can prepend to the given host if they define the endpoint trait. + "AwsJson11EndpointTrait": { + Params: &EndpointOperationInput{}, + ExpectMethod: "POST", + ExpectURIPath: "/", + ExpectQuery: []smithytesting.QueryItem{}, + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareReaderBytes(actual, []byte(`{}`)) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if name == "AwsJson11EndpointTrait" { + t.Skip("disabled test aws.protocoltests.json#JsonProtocol aws.protocoltests.json#EndpointOperation") + } + + var actualReq *http.Request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + actualReq = r.Clone(r.Context()) + if len(actualReq.URL.RawPath) == 0 { + actualReq.URL.RawPath = actualReq.URL.Path + } + if v := actualReq.ContentLength; v != 0 { + actualReq.Header.Set("Content-Length", strconv.FormatInt(v, 10)) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, r.Body); err != nil { + t.Errorf("failed to read request body, %v", err) + } + actualReq.Body = ioutil.NopCloser(&buf) + + w.WriteHeader(200) + })) + defer server.Close() + url := server.URL + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = url + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: awshttp.NewBuildableClient(), + Region: "us-west-2", + }) + result, err := client.EndpointOperation(context.Background(), c.Params) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} diff --git a/internal/protocoltest/jsonrpc/api_op_EndpointWithHostLabelOperation.go b/internal/protocoltest/jsonrpc/api_op_EndpointWithHostLabelOperation.go new file mode 100644 index 00000000000..1ad5ffaf7c3 --- /dev/null +++ b/internal/protocoltest/jsonrpc/api_op_EndpointWithHostLabelOperation.go @@ -0,0 +1,157 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package jsonrpc + +import ( + "context" + "fmt" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + smithy "github.com/aws/smithy-go" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" + "strings" +) + +func (c *Client) EndpointWithHostLabelOperation(ctx context.Context, params *EndpointWithHostLabelOperationInput, optFns ...func(*Options)) (*EndpointWithHostLabelOperationOutput, error) { + if params == nil { + params = &EndpointWithHostLabelOperationInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "EndpointWithHostLabelOperation", params, optFns, addOperationEndpointWithHostLabelOperationMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*EndpointWithHostLabelOperationOutput) + out.ResultMetadata = metadata + return out, nil +} + +type EndpointWithHostLabelOperationInput struct { + + // This member is required. + Label *string +} + +type EndpointWithHostLabelOperationOutput struct { + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata +} + +func addOperationEndpointWithHostLabelOperationMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsAwsjson11_serializeOpEndpointWithHostLabelOperation{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsAwsjson11_deserializeOpEndpointWithHostLabelOperation{}, middleware.After) + if err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = v4.AddComputePayloadSHA256Middleware(stack); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = addHTTPSignerV4Middleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = addEndpointPrefix_opEndpointWithHostLabelOperationMiddleware(stack); err != nil { + return err + } + if err = addOpEndpointWithHostLabelOperationValidationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opEndpointWithHostLabelOperation(options.Region), middleware.Before); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + return nil +} + +type endpointPrefix_opEndpointWithHostLabelOperationMiddleware struct { +} + +func (*endpointPrefix_opEndpointWithHostLabelOperationMiddleware) ID() string { + return "EndpointHostPrefix" +} + +func (m *endpointPrefix_opEndpointWithHostLabelOperationMiddleware) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + if smithyhttp.GetHostnameImmutable(ctx) || smithyhttp.IsEndpointHostPrefixDisabled(ctx) { + return next.HandleSerialize(ctx, in) + } + + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) + } + + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input type %T", in.Parameters) + } + + var prefix strings.Builder + prefix.WriteString("foo.") + if input.Label == nil { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("Label forms part of the endpoint host and so may not be nil")} + } else if !smithyhttp.ValidHostLabel(*input.Label) { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("Label forms part of the endpoint host and so must match \"[a-zA-Z0-9-]{1,63}\", but was \"%s\"", *input.Label)} + } else { + prefix.WriteString(*input.Label) + } + prefix.WriteString(".") + req.URL.Host = prefix.String() + req.URL.Host + + return next.HandleSerialize(ctx, in) +} +func addEndpointPrefix_opEndpointWithHostLabelOperationMiddleware(stack *middleware.Stack) error { + return stack.Serialize.Insert(&endpointPrefix_opEndpointWithHostLabelOperationMiddleware{}, `OperationSerializer`, middleware.After) +} + +func newServiceMetadataMiddleware_opEndpointWithHostLabelOperation(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + SigningName: "foo", + OperationName: "EndpointWithHostLabelOperation", + } +} diff --git a/internal/protocoltest/jsonrpc/api_op_EndpointWithHostLabelOperation_test.go b/internal/protocoltest/jsonrpc/api_op_EndpointWithHostLabelOperation_test.go new file mode 100644 index 00000000000..0567544660f --- /dev/null +++ b/internal/protocoltest/jsonrpc/api_op_EndpointWithHostLabelOperation_test.go @@ -0,0 +1,118 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package jsonrpc + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/ptr" + smithytesting "github.com/aws/smithy-go/testing" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +func TestClient_EndpointWithHostLabelOperation_awsAwsjson11Serialize(t *testing.T) { + cases := map[string]struct { + Params *EndpointWithHostLabelOperationInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Operations can prepend to the given host if they define the endpoint trait, and + // can use the host label trait to define further customization based on user + // input. + "AwsJson11EndpointTraitWithHostLabel": { + Params: &EndpointWithHostLabelOperationInput{ + Label: ptr.String("bar"), + }, + ExpectMethod: "POST", + ExpectURIPath: "/", + ExpectQuery: []smithytesting.QueryItem{}, + BodyMediaType: "application/json", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareJSONReaderBytes(actual, []byte(`{"label": "bar"}`)) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if name == "AwsJson11EndpointTraitWithHostLabel" { + t.Skip("disabled test aws.protocoltests.json#JsonProtocol aws.protocoltests.json#EndpointWithHostLabelOperation") + } + + var actualReq *http.Request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + actualReq = r.Clone(r.Context()) + if len(actualReq.URL.RawPath) == 0 { + actualReq.URL.RawPath = actualReq.URL.Path + } + if v := actualReq.ContentLength; v != 0 { + actualReq.Header.Set("Content-Length", strconv.FormatInt(v, 10)) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, r.Body); err != nil { + t.Errorf("failed to read request body, %v", err) + } + actualReq.Body = ioutil.NopCloser(&buf) + + w.WriteHeader(200) + })) + defer server.Close() + url := server.URL + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = url + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: awshttp.NewBuildableClient(), + Region: "us-west-2", + }) + result, err := client.EndpointWithHostLabelOperation(context.Background(), c.Params) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} diff --git a/internal/protocoltest/jsonrpc/deserializers.go b/internal/protocoltest/jsonrpc/deserializers.go index f46c165044b..97b91c90725 100644 --- a/internal/protocoltest/jsonrpc/deserializers.go +++ b/internal/protocoltest/jsonrpc/deserializers.go @@ -108,6 +108,178 @@ func awsAwsjson11_deserializeOpErrorEmptyOperation(response *smithyhttp.Response } } +type awsAwsjson11_deserializeOpEndpointOperation struct { +} + +func (*awsAwsjson11_deserializeOpEndpointOperation) ID() string { + return "OperationDeserializer" +} + +func (m *awsAwsjson11_deserializeOpEndpointOperation) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsAwsjson11_deserializeOpErrorEndpointOperation(response, &metadata) + } + output := &EndpointOperationOutput{} + out.Result = output + + if _, err = io.Copy(ioutil.Discard, response.Body); err != nil { + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to discard response body, %w", err), + } + } + + return out, metadata, err +} + +func awsAwsjson11_deserializeOpErrorEndpointOperation(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + code := response.Header.Get("X-Amzn-ErrorType") + if len(code) != 0 { + errorCode = restjson.SanitizeErrorCode(code) + } + + var buff [1024]byte + ringBuffer := smithyio.NewRingBuffer(buff[:]) + + body := io.TeeReader(errorBody, ringBuffer) + decoder := json.NewDecoder(body) + decoder.UseNumber() + code, message, err := restjson.GetErrorInfo(decoder) + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + err = &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + return err + } + + errorBody.Seek(0, io.SeekStart) + if len(code) != 0 { + errorCode = restjson.SanitizeErrorCode(code) + } + if len(message) != 0 { + errorMessage = message + } + + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + +type awsAwsjson11_deserializeOpEndpointWithHostLabelOperation struct { +} + +func (*awsAwsjson11_deserializeOpEndpointWithHostLabelOperation) ID() string { + return "OperationDeserializer" +} + +func (m *awsAwsjson11_deserializeOpEndpointWithHostLabelOperation) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsAwsjson11_deserializeOpErrorEndpointWithHostLabelOperation(response, &metadata) + } + output := &EndpointWithHostLabelOperationOutput{} + out.Result = output + + if _, err = io.Copy(ioutil.Discard, response.Body); err != nil { + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to discard response body, %w", err), + } + } + + return out, metadata, err +} + +func awsAwsjson11_deserializeOpErrorEndpointWithHostLabelOperation(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + code := response.Header.Get("X-Amzn-ErrorType") + if len(code) != 0 { + errorCode = restjson.SanitizeErrorCode(code) + } + + var buff [1024]byte + ringBuffer := smithyio.NewRingBuffer(buff[:]) + + body := io.TeeReader(errorBody, ringBuffer) + decoder := json.NewDecoder(body) + decoder.UseNumber() + code, message, err := restjson.GetErrorInfo(decoder) + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + err = &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + return err + } + + errorBody.Seek(0, io.SeekStart) + if len(code) != 0 { + errorCode = restjson.SanitizeErrorCode(code) + } + if len(message) != 0 { + errorMessage = message + } + + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + type awsAwsjson11_deserializeOpGreetingWithErrors struct { } diff --git a/internal/protocoltest/jsonrpc/go.mod b/internal/protocoltest/jsonrpc/go.mod index f7f949e813d..036b779e221 100644 --- a/internal/protocoltest/jsonrpc/go.mod +++ b/internal/protocoltest/jsonrpc/go.mod @@ -1,6 +1,6 @@ module github.com/aws/aws-sdk-go-v2/internal/protocoltest/jsonrpc -go 1.15 +go 1.16 require ( github.com/aws/aws-sdk-go-v2 v1.2.0 diff --git a/internal/protocoltest/jsonrpc/serializers.go b/internal/protocoltest/jsonrpc/serializers.go index a06d29eaff8..6c24dfd587e 100644 --- a/internal/protocoltest/jsonrpc/serializers.go +++ b/internal/protocoltest/jsonrpc/serializers.go @@ -58,6 +58,95 @@ func (m *awsAwsjson11_serializeOpEmptyOperation) HandleSerialize(ctx context.Con return next.HandleSerialize(ctx, in) } +type awsAwsjson11_serializeOpEndpointOperation struct { +} + +func (*awsAwsjson11_serializeOpEndpointOperation) ID() string { + return "OperationSerializer" +} + +func (m *awsAwsjson11_serializeOpEndpointOperation) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*EndpointOperationInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + request.Request.URL.Path = "/" + request.Request.Method = "POST" + httpBindingEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + httpBindingEncoder.SetHeader("Content-Type").String("application/x-amz-json-1.1") + httpBindingEncoder.SetHeader("X-Amz-Target").String("JsonProtocol.EndpointOperation") + + if request, err = request.SetStream(strings.NewReader(`{}`)); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = httpBindingEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} + +type awsAwsjson11_serializeOpEndpointWithHostLabelOperation struct { +} + +func (*awsAwsjson11_serializeOpEndpointWithHostLabelOperation) ID() string { + return "OperationSerializer" +} + +func (m *awsAwsjson11_serializeOpEndpointWithHostLabelOperation) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + request.Request.URL.Path = "/" + request.Request.Method = "POST" + httpBindingEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + httpBindingEncoder.SetHeader("Content-Type").String("application/x-amz-json-1.1") + httpBindingEncoder.SetHeader("X-Amz-Target").String("JsonProtocol.EndpointWithHostLabelOperation") + + jsonEncoder := smithyjson.NewEncoder() + if err := awsAwsjson11_serializeOpDocumentEndpointWithHostLabelOperationInput(input, jsonEncoder.Value); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request, err = request.SetStream(bytes.NewReader(jsonEncoder.Bytes())); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = httpBindingEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} + type awsAwsjson11_serializeOpGreetingWithErrors struct { } @@ -873,6 +962,18 @@ func awsAwsjson11_serializeDocumentStringMap(v map[string]string, value smithyjs return nil } +func awsAwsjson11_serializeOpDocumentEndpointWithHostLabelOperationInput(v *EndpointWithHostLabelOperationInput, value smithyjson.Value) error { + object := value.Object() + defer object.Close() + + if v.Label != nil { + ok := object.Key("label") + ok.String(*v.Label) + } + + return nil +} + func awsAwsjson11_serializeOpDocumentJsonEnumsInput(v *JsonEnumsInput, value smithyjson.Value) error { object := value.Object() defer object.Close() diff --git a/internal/protocoltest/jsonrpc/validators.go b/internal/protocoltest/jsonrpc/validators.go index 22061ee9d9a..ebf155e5dfc 100644 --- a/internal/protocoltest/jsonrpc/validators.go +++ b/internal/protocoltest/jsonrpc/validators.go @@ -1,3 +1,49 @@ // Code generated by smithy-go-codegen DO NOT EDIT. package jsonrpc + +import ( + "context" + "fmt" + smithy "github.com/aws/smithy-go" + "github.com/aws/smithy-go/middleware" +) + +type validateOpEndpointWithHostLabelOperation struct { +} + +func (*validateOpEndpointWithHostLabelOperation) ID() string { + return "OperationInputValidation" +} + +func (m *validateOpEndpointWithHostLabelOperation) HandleInitialize(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) ( + out middleware.InitializeOutput, metadata middleware.Metadata, err error, +) { + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input parameters type %T", in.Parameters) + } + if err := validateOpEndpointWithHostLabelOperationInput(input); err != nil { + return out, metadata, err + } + return next.HandleInitialize(ctx, in) +} + +func addOpEndpointWithHostLabelOperationValidationMiddleware(stack *middleware.Stack) error { + return stack.Initialize.Add(&validateOpEndpointWithHostLabelOperation{}, middleware.After) +} + +func validateOpEndpointWithHostLabelOperationInput(v *EndpointWithHostLabelOperationInput) error { + if v == nil { + return nil + } + invalidParams := smithy.InvalidParamsError{Context: "EndpointWithHostLabelOperationInput"} + if v.Label == nil { + invalidParams.Add(smithy.NewErrParamRequired("Label")) + } + if invalidParams.Len() > 0 { + return invalidParams + } else { + return nil + } +} diff --git a/internal/protocoltest/jsonrpc10/api_op_EmptyInputAndEmptyOutput_test.go b/internal/protocoltest/jsonrpc10/api_op_EmptyInputAndEmptyOutput_test.go index ea21919d7df..67ca3d9463c 100644 --- a/internal/protocoltest/jsonrpc10/api_op_EmptyInputAndEmptyOutput_test.go +++ b/internal/protocoltest/jsonrpc10/api_op_EmptyInputAndEmptyOutput_test.go @@ -33,7 +33,7 @@ func TestClient_EmptyInputAndEmptyOutput_awsAwsjson10Serialize(t *testing.T) { BodyMediaType string BodyAssert func(io.Reader) error }{ - // Empty input serializes no payload + // Clients must always send an empty object if input is modeled. "AwsJson10EmptyInputAndEmptyOutput": { Params: &EmptyInputAndEmptyOutputInput{}, ExpectMethod: "POST", @@ -45,7 +45,7 @@ func TestClient_EmptyInputAndEmptyOutput_awsAwsjson10Serialize(t *testing.T) { }, BodyMediaType: "application/json", BodyAssert: func(actual io.Reader) error { - return smithytesting.CompareReaderEmpty(actual) + return smithytesting.CompareJSONReaderBytes(actual, []byte(`{}`)) }, }, } @@ -126,18 +126,8 @@ func TestClient_EmptyInputAndEmptyOutput_awsAwsjson10Deserialize(t *testing.T) { Body []byte ExpectResult *EmptyInputAndEmptyOutputOutput }{ - // Empty output serializes no payload - "AwsJson10EmptyInputAndEmptyOutput": { - StatusCode: 200, - Header: http.Header{ - "Content-Type": []string{"application/x-amz-json-1.0"}, - }, - BodyMediaType: "application/json", - Body: []byte(``), - ExpectResult: &EmptyInputAndEmptyOutputOutput{}, - }, - // Empty output serializes no payload - "AwsJson10EmptyInputAndEmptyJsonObjectOutput": { + // A service will always return a JSON object for operations with modeled output. + "AwsJson10EmptyInputAndEmptyOutputSendJsonObject": { StatusCode: 200, Header: http.Header{ "Content-Type": []string{"application/x-amz-json-1.0"}, diff --git a/internal/protocoltest/jsonrpc10/api_op_EndpointOperation.go b/internal/protocoltest/jsonrpc10/api_op_EndpointOperation.go new file mode 100644 index 00000000000..d259d584981 --- /dev/null +++ b/internal/protocoltest/jsonrpc10/api_op_EndpointOperation.go @@ -0,0 +1,126 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package jsonrpc10 + +import ( + "context" + "fmt" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +func (c *Client) EndpointOperation(ctx context.Context, params *EndpointOperationInput, optFns ...func(*Options)) (*EndpointOperationOutput, error) { + if params == nil { + params = &EndpointOperationInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "EndpointOperation", params, optFns, addOperationEndpointOperationMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*EndpointOperationOutput) + out.ResultMetadata = metadata + return out, nil +} + +type EndpointOperationInput struct { +} + +type EndpointOperationOutput struct { + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata +} + +func addOperationEndpointOperationMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsAwsjson10_serializeOpEndpointOperation{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsAwsjson10_deserializeOpEndpointOperation{}, middleware.After) + if err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = addEndpointPrefix_opEndpointOperationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opEndpointOperation(options.Region), middleware.Before); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + return nil +} + +type endpointPrefix_opEndpointOperationMiddleware struct { +} + +func (*endpointPrefix_opEndpointOperationMiddleware) ID() string { + return "EndpointHostPrefix" +} + +func (m *endpointPrefix_opEndpointOperationMiddleware) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + if smithyhttp.GetHostnameImmutable(ctx) || smithyhttp.IsEndpointHostPrefixDisabled(ctx) { + return next.HandleSerialize(ctx, in) + } + + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) + } + + req.URL.Host = "foo." + req.URL.Host + + return next.HandleSerialize(ctx, in) +} +func addEndpointPrefix_opEndpointOperationMiddleware(stack *middleware.Stack) error { + return stack.Serialize.Insert(&endpointPrefix_opEndpointOperationMiddleware{}, `OperationSerializer`, middleware.After) +} + +func newServiceMetadataMiddleware_opEndpointOperation(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "EndpointOperation", + } +} diff --git a/internal/protocoltest/jsonrpc10/api_op_EndpointOperation_test.go b/internal/protocoltest/jsonrpc10/api_op_EndpointOperation_test.go new file mode 100644 index 00000000000..183d5b203a9 --- /dev/null +++ b/internal/protocoltest/jsonrpc10/api_op_EndpointOperation_test.go @@ -0,0 +1,112 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package jsonrpc10 + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/smithy-go/middleware" + smithytesting "github.com/aws/smithy-go/testing" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +func TestClient_EndpointOperation_awsAwsjson10Serialize(t *testing.T) { + cases := map[string]struct { + Params *EndpointOperationInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Operations can prepend to the given host if they define the endpoint trait. + "AwsJson10EndpointTrait": { + Params: &EndpointOperationInput{}, + ExpectMethod: "POST", + ExpectURIPath: "/", + ExpectQuery: []smithytesting.QueryItem{}, + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareReaderBytes(actual, []byte(`{}`)) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if name == "AwsJson10EndpointTrait" { + t.Skip("disabled test aws.protocoltests.json10#JsonRpc10 aws.protocoltests.json10#EndpointOperation") + } + + var actualReq *http.Request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + actualReq = r.Clone(r.Context()) + if len(actualReq.URL.RawPath) == 0 { + actualReq.URL.RawPath = actualReq.URL.Path + } + if v := actualReq.ContentLength; v != 0 { + actualReq.Header.Set("Content-Length", strconv.FormatInt(v, 10)) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, r.Body); err != nil { + t.Errorf("failed to read request body, %v", err) + } + actualReq.Body = ioutil.NopCloser(&buf) + + w.WriteHeader(200) + })) + defer server.Close() + url := server.URL + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = url + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: awshttp.NewBuildableClient(), + Region: "us-west-2", + }) + result, err := client.EndpointOperation(context.Background(), c.Params) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} diff --git a/internal/protocoltest/jsonrpc10/api_op_EndpointWithHostLabelOperation.go b/internal/protocoltest/jsonrpc10/api_op_EndpointWithHostLabelOperation.go new file mode 100644 index 00000000000..2e23cf6d771 --- /dev/null +++ b/internal/protocoltest/jsonrpc10/api_op_EndpointWithHostLabelOperation.go @@ -0,0 +1,149 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package jsonrpc10 + +import ( + "context" + "fmt" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + smithy "github.com/aws/smithy-go" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" + "strings" +) + +func (c *Client) EndpointWithHostLabelOperation(ctx context.Context, params *EndpointWithHostLabelOperationInput, optFns ...func(*Options)) (*EndpointWithHostLabelOperationOutput, error) { + if params == nil { + params = &EndpointWithHostLabelOperationInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "EndpointWithHostLabelOperation", params, optFns, addOperationEndpointWithHostLabelOperationMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*EndpointWithHostLabelOperationOutput) + out.ResultMetadata = metadata + return out, nil +} + +type EndpointWithHostLabelOperationInput struct { + + // This member is required. + Label *string +} + +type EndpointWithHostLabelOperationOutput struct { + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata +} + +func addOperationEndpointWithHostLabelOperationMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsAwsjson10_serializeOpEndpointWithHostLabelOperation{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsAwsjson10_deserializeOpEndpointWithHostLabelOperation{}, middleware.After) + if err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = addEndpointPrefix_opEndpointWithHostLabelOperationMiddleware(stack); err != nil { + return err + } + if err = addOpEndpointWithHostLabelOperationValidationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opEndpointWithHostLabelOperation(options.Region), middleware.Before); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + return nil +} + +type endpointPrefix_opEndpointWithHostLabelOperationMiddleware struct { +} + +func (*endpointPrefix_opEndpointWithHostLabelOperationMiddleware) ID() string { + return "EndpointHostPrefix" +} + +func (m *endpointPrefix_opEndpointWithHostLabelOperationMiddleware) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + if smithyhttp.GetHostnameImmutable(ctx) || smithyhttp.IsEndpointHostPrefixDisabled(ctx) { + return next.HandleSerialize(ctx, in) + } + + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) + } + + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input type %T", in.Parameters) + } + + var prefix strings.Builder + prefix.WriteString("foo.") + if input.Label == nil { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("Label forms part of the endpoint host and so may not be nil")} + } else if !smithyhttp.ValidHostLabel(*input.Label) { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("Label forms part of the endpoint host and so must match \"[a-zA-Z0-9-]{1,63}\", but was \"%s\"", *input.Label)} + } else { + prefix.WriteString(*input.Label) + } + prefix.WriteString(".") + req.URL.Host = prefix.String() + req.URL.Host + + return next.HandleSerialize(ctx, in) +} +func addEndpointPrefix_opEndpointWithHostLabelOperationMiddleware(stack *middleware.Stack) error { + return stack.Serialize.Insert(&endpointPrefix_opEndpointWithHostLabelOperationMiddleware{}, `OperationSerializer`, middleware.After) +} + +func newServiceMetadataMiddleware_opEndpointWithHostLabelOperation(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "EndpointWithHostLabelOperation", + } +} diff --git a/internal/protocoltest/jsonrpc10/api_op_EndpointWithHostLabelOperation_test.go b/internal/protocoltest/jsonrpc10/api_op_EndpointWithHostLabelOperation_test.go new file mode 100644 index 00000000000..16dbd46827d --- /dev/null +++ b/internal/protocoltest/jsonrpc10/api_op_EndpointWithHostLabelOperation_test.go @@ -0,0 +1,118 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package jsonrpc10 + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/ptr" + smithytesting "github.com/aws/smithy-go/testing" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +func TestClient_EndpointWithHostLabelOperation_awsAwsjson10Serialize(t *testing.T) { + cases := map[string]struct { + Params *EndpointWithHostLabelOperationInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Operations can prepend to the given host if they define the endpoint trait, and + // can use the host label trait to define further customization based on user + // input. + "AwsJson10EndpointTraitWithHostLabel": { + Params: &EndpointWithHostLabelOperationInput{ + Label: ptr.String("bar"), + }, + ExpectMethod: "POST", + ExpectURIPath: "/", + ExpectQuery: []smithytesting.QueryItem{}, + BodyMediaType: "application/json", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareJSONReaderBytes(actual, []byte(`{"label": "bar"}`)) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if name == "AwsJson10EndpointTraitWithHostLabel" { + t.Skip("disabled test aws.protocoltests.json10#JsonRpc10 aws.protocoltests.json10#EndpointWithHostLabelOperation") + } + + var actualReq *http.Request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + actualReq = r.Clone(r.Context()) + if len(actualReq.URL.RawPath) == 0 { + actualReq.URL.RawPath = actualReq.URL.Path + } + if v := actualReq.ContentLength; v != 0 { + actualReq.Header.Set("Content-Length", strconv.FormatInt(v, 10)) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, r.Body); err != nil { + t.Errorf("failed to read request body, %v", err) + } + actualReq.Body = ioutil.NopCloser(&buf) + + w.WriteHeader(200) + })) + defer server.Close() + url := server.URL + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = url + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: awshttp.NewBuildableClient(), + Region: "us-west-2", + }) + result, err := client.EndpointWithHostLabelOperation(context.Background(), c.Params) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} diff --git a/internal/protocoltest/jsonrpc10/api_op_NoInputAndNoOutput_test.go b/internal/protocoltest/jsonrpc10/api_op_NoInputAndNoOutput_test.go index b656f63b340..276ad38f358 100644 --- a/internal/protocoltest/jsonrpc10/api_op_NoInputAndNoOutput_test.go +++ b/internal/protocoltest/jsonrpc10/api_op_NoInputAndNoOutput_test.go @@ -33,8 +33,11 @@ func TestClient_NoInputAndNoOutput_awsAwsjson10Serialize(t *testing.T) { BodyMediaType string BodyAssert func(io.Reader) error }{ - // No input serializes no payload - "AwsJson10NoInputAndNoOutput": { + // Clients must always send an empty JSON object payload for operations with no + // input (that is, {}). While AWS service implementations support requests with no + // payload or requests that send {}, always sending {} from the client is preferred + // for forward compatibility in case input is ever added to an operation. + "AwsJson10MustAlwaysSendEmptyJsonPayload": { Params: &NoInputAndNoOutputInput{}, ExpectMethod: "POST", ExpectURIPath: "/", @@ -43,10 +46,35 @@ func TestClient_NoInputAndNoOutput_awsAwsjson10Serialize(t *testing.T) { "Content-Type": []string{"application/x-amz-json-1.0"}, "X-Amz-Target": []string{"JsonRpc10.NoInputAndNoOutput"}, }, + BodyMediaType: "application/json", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareJSONReaderBytes(actual, []byte(`{}`)) + }, + }, + // Service implementations must support no payload or an empty object payload for + // operations that define no input. However, despite the lack of a payload, a + // Content-Type header is still required in order for the service to properly + // detect the protocol. + "AwsJson10ServiceSupportsNoPayloadForNoInput": { + Params: &NoInputAndNoOutputInput{}, + ExpectMethod: "POST", + ExpectURIPath: "/", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/x-amz-json-1.0"}, + "X-Amz-Target": []string{"JsonRpc10.NoInputAndNoOutput"}, + }, + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareReaderEmpty(actual) + }, }, } for name, c := range cases { t.Run(name, func(t *testing.T) { + if name == "AwsJson10ServiceSupportsNoPayloadForNoInput" { + t.Skip("disabled test aws.protocoltests.json10#JsonRpc10 aws.protocoltests.json10#NoInputAndNoOutput") + } + var actualReq *http.Request server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { actualReq = r.Clone(r.Context()) @@ -118,12 +146,42 @@ func TestClient_NoInputAndNoOutput_awsAwsjson10Deserialize(t *testing.T) { Body []byte ExpectResult *NoInputAndNoOutputOutput }{ - // No output serializes no payload - "AwsJson10NoInputAndNoOutput": { + // When no output is defined, the service is expected to return an empty payload, + // however, client must ignore a JSON payload if one is returned. This ensures that + // if output is added later, then it will not break the client. + "AwsJson10HandlesEmptyOutputShape": { + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/x-amz-json-1.0"}, + }, + BodyMediaType: "application/json", + Body: []byte(`{}`), + ExpectResult: &NoInputAndNoOutputOutput{}, + }, + // This client-only test builds on handles_empty_output_shape, by including + // unexpected fields in the JSON. A client needs to ignore JSON output that is + // empty or that contains JSON object data. + "AwsJson10HandlesUnexpectedJsonOutput": { + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/x-amz-json-1.0"}, + }, + BodyMediaType: "application/json", + Body: []byte(`{ + "foo": true + }`), + ExpectResult: &NoInputAndNoOutputOutput{}, + }, + // When no output is defined, the service is expected to return an empty payload. + // Despite the lack of a payload, the service is expected to always send a + // Content-Type header. Clients must handle cases where a service returns a JSON + // object and where a service returns no JSON at all. + "AwsJson10ServiceRespondsWithNoPayload": { StatusCode: 200, Header: http.Header{ "Content-Type": []string{"application/x-amz-json-1.0"}, }, + Body: []byte(``), ExpectResult: &NoInputAndNoOutputOutput{}, }, } diff --git a/internal/protocoltest/jsonrpc10/api_op_NoInputAndOutput_test.go b/internal/protocoltest/jsonrpc10/api_op_NoInputAndOutput_test.go index 74e68dd6f80..83ed6994419 100644 --- a/internal/protocoltest/jsonrpc10/api_op_NoInputAndOutput_test.go +++ b/internal/protocoltest/jsonrpc10/api_op_NoInputAndOutput_test.go @@ -33,7 +33,7 @@ func TestClient_NoInputAndOutput_awsAwsjson10Serialize(t *testing.T) { BodyMediaType string BodyAssert func(io.Reader) error }{ - // No input serializes no payload + // A client should always send and empty JSON object payload. "AwsJson10NoInputAndOutput": { Params: &NoInputAndOutputInput{}, ExpectMethod: "POST", @@ -43,6 +43,10 @@ func TestClient_NoInputAndOutput_awsAwsjson10Serialize(t *testing.T) { "Content-Type": []string{"application/x-amz-json-1.0"}, "X-Amz-Target": []string{"JsonRpc10.NoInputAndOutput"}, }, + BodyMediaType: "application/json", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareJSONReaderBytes(actual, []byte(`{}`)) + }, }, } for name, c := range cases { @@ -118,13 +122,15 @@ func TestClient_NoInputAndOutput_awsAwsjson10Deserialize(t *testing.T) { Body []byte ExpectResult *NoInputAndOutputOutput }{ - // Empty output serializes no payload + // Empty output always serializes an empty object payload. "AwsJson10NoInputAndOutput": { StatusCode: 200, Header: http.Header{ "Content-Type": []string{"application/x-amz-json-1.0"}, }, - ExpectResult: &NoInputAndOutputOutput{}, + BodyMediaType: "application/json", + Body: []byte(`{}`), + ExpectResult: &NoInputAndOutputOutput{}, }, } for name, c := range cases { diff --git a/internal/protocoltest/jsonrpc10/deserializers.go b/internal/protocoltest/jsonrpc10/deserializers.go index ea7a0a80887..cf43684f46e 100644 --- a/internal/protocoltest/jsonrpc10/deserializers.go +++ b/internal/protocoltest/jsonrpc10/deserializers.go @@ -130,6 +130,178 @@ func awsAwsjson10_deserializeOpErrorEmptyInputAndEmptyOutput(response *smithyhtt } } +type awsAwsjson10_deserializeOpEndpointOperation struct { +} + +func (*awsAwsjson10_deserializeOpEndpointOperation) ID() string { + return "OperationDeserializer" +} + +func (m *awsAwsjson10_deserializeOpEndpointOperation) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsAwsjson10_deserializeOpErrorEndpointOperation(response, &metadata) + } + output := &EndpointOperationOutput{} + out.Result = output + + if _, err = io.Copy(ioutil.Discard, response.Body); err != nil { + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to discard response body, %w", err), + } + } + + return out, metadata, err +} + +func awsAwsjson10_deserializeOpErrorEndpointOperation(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + code := response.Header.Get("X-Amzn-ErrorType") + if len(code) != 0 { + errorCode = restjson.SanitizeErrorCode(code) + } + + var buff [1024]byte + ringBuffer := smithyio.NewRingBuffer(buff[:]) + + body := io.TeeReader(errorBody, ringBuffer) + decoder := json.NewDecoder(body) + decoder.UseNumber() + code, message, err := restjson.GetErrorInfo(decoder) + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + err = &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + return err + } + + errorBody.Seek(0, io.SeekStart) + if len(code) != 0 { + errorCode = restjson.SanitizeErrorCode(code) + } + if len(message) != 0 { + errorMessage = message + } + + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + +type awsAwsjson10_deserializeOpEndpointWithHostLabelOperation struct { +} + +func (*awsAwsjson10_deserializeOpEndpointWithHostLabelOperation) ID() string { + return "OperationDeserializer" +} + +func (m *awsAwsjson10_deserializeOpEndpointWithHostLabelOperation) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsAwsjson10_deserializeOpErrorEndpointWithHostLabelOperation(response, &metadata) + } + output := &EndpointWithHostLabelOperationOutput{} + out.Result = output + + if _, err = io.Copy(ioutil.Discard, response.Body); err != nil { + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to discard response body, %w", err), + } + } + + return out, metadata, err +} + +func awsAwsjson10_deserializeOpErrorEndpointWithHostLabelOperation(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + code := response.Header.Get("X-Amzn-ErrorType") + if len(code) != 0 { + errorCode = restjson.SanitizeErrorCode(code) + } + + var buff [1024]byte + ringBuffer := smithyio.NewRingBuffer(buff[:]) + + body := io.TeeReader(errorBody, ringBuffer) + decoder := json.NewDecoder(body) + decoder.UseNumber() + code, message, err := restjson.GetErrorInfo(decoder) + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + err = &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + return err + } + + errorBody.Seek(0, io.SeekStart) + if len(code) != 0 { + errorCode = restjson.SanitizeErrorCode(code) + } + if len(message) != 0 { + errorMessage = message + } + + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + type awsAwsjson10_deserializeOpGreetingWithErrors struct { } diff --git a/internal/protocoltest/jsonrpc10/go.mod b/internal/protocoltest/jsonrpc10/go.mod index 026224fd5cc..667377f5099 100644 --- a/internal/protocoltest/jsonrpc10/go.mod +++ b/internal/protocoltest/jsonrpc10/go.mod @@ -1,6 +1,6 @@ module github.com/aws/aws-sdk-go-v2/internal/protocoltest/jsonrpc10 -go 1.15 +go 1.16 require ( github.com/aws/aws-sdk-go-v2 v1.2.0 diff --git a/internal/protocoltest/jsonrpc10/serializers.go b/internal/protocoltest/jsonrpc10/serializers.go index c3b7c9fea65..eb24fd7dd97 100644 --- a/internal/protocoltest/jsonrpc10/serializers.go +++ b/internal/protocoltest/jsonrpc10/serializers.go @@ -63,6 +63,95 @@ func (m *awsAwsjson10_serializeOpEmptyInputAndEmptyOutput) HandleSerialize(ctx c return next.HandleSerialize(ctx, in) } +type awsAwsjson10_serializeOpEndpointOperation struct { +} + +func (*awsAwsjson10_serializeOpEndpointOperation) ID() string { + return "OperationSerializer" +} + +func (m *awsAwsjson10_serializeOpEndpointOperation) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*EndpointOperationInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + request.Request.URL.Path = "/" + request.Request.Method = "POST" + httpBindingEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + httpBindingEncoder.SetHeader("Content-Type").String("application/x-amz-json-1.0") + httpBindingEncoder.SetHeader("X-Amz-Target").String("JsonRpc10.EndpointOperation") + + if request, err = request.SetStream(strings.NewReader(`{}`)); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = httpBindingEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} + +type awsAwsjson10_serializeOpEndpointWithHostLabelOperation struct { +} + +func (*awsAwsjson10_serializeOpEndpointWithHostLabelOperation) ID() string { + return "OperationSerializer" +} + +func (m *awsAwsjson10_serializeOpEndpointWithHostLabelOperation) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + request.Request.URL.Path = "/" + request.Request.Method = "POST" + httpBindingEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + httpBindingEncoder.SetHeader("Content-Type").String("application/x-amz-json-1.0") + httpBindingEncoder.SetHeader("X-Amz-Target").String("JsonRpc10.EndpointWithHostLabelOperation") + + jsonEncoder := smithyjson.NewEncoder() + if err := awsAwsjson10_serializeOpDocumentEndpointWithHostLabelOperationInput(input, jsonEncoder.Value); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request, err = request.SetStream(bytes.NewReader(jsonEncoder.Bytes())); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = httpBindingEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} + type awsAwsjson10_serializeOpGreetingWithErrors struct { } @@ -330,6 +419,18 @@ func awsAwsjson10_serializeOpDocumentEmptyInputAndEmptyOutputInput(v *EmptyInput return nil } +func awsAwsjson10_serializeOpDocumentEndpointWithHostLabelOperationInput(v *EndpointWithHostLabelOperationInput, value smithyjson.Value) error { + object := value.Object() + defer object.Close() + + if v.Label != nil { + ok := object.Key("label") + ok.String(*v.Label) + } + + return nil +} + func awsAwsjson10_serializeOpDocumentJsonUnionsInput(v *JsonUnionsInput, value smithyjson.Value) error { object := value.Object() defer object.Close() diff --git a/internal/protocoltest/jsonrpc10/validators.go b/internal/protocoltest/jsonrpc10/validators.go index a2014efaade..c76ebbf67e7 100644 --- a/internal/protocoltest/jsonrpc10/validators.go +++ b/internal/protocoltest/jsonrpc10/validators.go @@ -1,3 +1,49 @@ // Code generated by smithy-go-codegen DO NOT EDIT. package jsonrpc10 + +import ( + "context" + "fmt" + smithy "github.com/aws/smithy-go" + "github.com/aws/smithy-go/middleware" +) + +type validateOpEndpointWithHostLabelOperation struct { +} + +func (*validateOpEndpointWithHostLabelOperation) ID() string { + return "OperationInputValidation" +} + +func (m *validateOpEndpointWithHostLabelOperation) HandleInitialize(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) ( + out middleware.InitializeOutput, metadata middleware.Metadata, err error, +) { + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input parameters type %T", in.Parameters) + } + if err := validateOpEndpointWithHostLabelOperationInput(input); err != nil { + return out, metadata, err + } + return next.HandleInitialize(ctx, in) +} + +func addOpEndpointWithHostLabelOperationValidationMiddleware(stack *middleware.Stack) error { + return stack.Initialize.Add(&validateOpEndpointWithHostLabelOperation{}, middleware.After) +} + +func validateOpEndpointWithHostLabelOperationInput(v *EndpointWithHostLabelOperationInput) error { + if v == nil { + return nil + } + invalidParams := smithy.InvalidParamsError{Context: "EndpointWithHostLabelOperationInput"} + if v.Label == nil { + invalidParams.Add(smithy.NewErrParamRequired("Label")) + } + if invalidParams.Len() > 0 { + return invalidParams + } else { + return nil + } +} diff --git a/internal/protocoltest/query/api_op_EndpointOperation.go b/internal/protocoltest/query/api_op_EndpointOperation.go new file mode 100644 index 00000000000..ecf62e8dd75 --- /dev/null +++ b/internal/protocoltest/query/api_op_EndpointOperation.go @@ -0,0 +1,126 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package query + +import ( + "context" + "fmt" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +func (c *Client) EndpointOperation(ctx context.Context, params *EndpointOperationInput, optFns ...func(*Options)) (*EndpointOperationOutput, error) { + if params == nil { + params = &EndpointOperationInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "EndpointOperation", params, optFns, addOperationEndpointOperationMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*EndpointOperationOutput) + out.ResultMetadata = metadata + return out, nil +} + +type EndpointOperationInput struct { +} + +type EndpointOperationOutput struct { + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata +} + +func addOperationEndpointOperationMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsAwsquery_serializeOpEndpointOperation{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsAwsquery_deserializeOpEndpointOperation{}, middleware.After) + if err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = addEndpointPrefix_opEndpointOperationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opEndpointOperation(options.Region), middleware.Before); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + return nil +} + +type endpointPrefix_opEndpointOperationMiddleware struct { +} + +func (*endpointPrefix_opEndpointOperationMiddleware) ID() string { + return "EndpointHostPrefix" +} + +func (m *endpointPrefix_opEndpointOperationMiddleware) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + if smithyhttp.GetHostnameImmutable(ctx) || smithyhttp.IsEndpointHostPrefixDisabled(ctx) { + return next.HandleSerialize(ctx, in) + } + + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) + } + + req.URL.Host = "foo." + req.URL.Host + + return next.HandleSerialize(ctx, in) +} +func addEndpointPrefix_opEndpointOperationMiddleware(stack *middleware.Stack) error { + return stack.Serialize.Insert(&endpointPrefix_opEndpointOperationMiddleware{}, `OperationSerializer`, middleware.After) +} + +func newServiceMetadataMiddleware_opEndpointOperation(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "EndpointOperation", + } +} diff --git a/internal/protocoltest/query/api_op_EndpointOperation_test.go b/internal/protocoltest/query/api_op_EndpointOperation_test.go new file mode 100644 index 00000000000..46b0e42480c --- /dev/null +++ b/internal/protocoltest/query/api_op_EndpointOperation_test.go @@ -0,0 +1,119 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package query + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/smithy-go/middleware" + smithyrand "github.com/aws/smithy-go/rand" + smithytesting "github.com/aws/smithy-go/testing" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +func TestClient_EndpointOperation_awsAwsquerySerialize(t *testing.T) { + cases := map[string]struct { + Params *EndpointOperationInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Operations can prepend to the given host if they define the endpoint trait. + "AwsQueryEndpointTrait": { + Params: &EndpointOperationInput{}, + ExpectMethod: "POST", + ExpectURIPath: "/", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/x-www-form-urlencoded"}, + }, + BodyMediaType: "application/x-www-form-urlencoded", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareURLFormReaderBytes(actual, []byte(`Action=EndpointOperation + &Version=2020-01-08`)) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if name == "AwsQueryEndpointTrait" { + t.Skip("disabled test aws.protocoltests.query#AwsQuery aws.protocoltests.query#EndpointOperation") + } + + var actualReq *http.Request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + actualReq = r.Clone(r.Context()) + if len(actualReq.URL.RawPath) == 0 { + actualReq.URL.RawPath = actualReq.URL.Path + } + if v := actualReq.ContentLength; v != 0 { + actualReq.Header.Set("Content-Length", strconv.FormatInt(v, 10)) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, r.Body); err != nil { + t.Errorf("failed to read request body, %v", err) + } + actualReq.Body = ioutil.NopCloser(&buf) + + w.WriteHeader(200) + })) + defer server.Close() + url := server.URL + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = url + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: awshttp.NewBuildableClient(), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + result, err := client.EndpointOperation(context.Background(), c.Params) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} diff --git a/internal/protocoltest/query/api_op_EndpointWithHostLabelOperation.go b/internal/protocoltest/query/api_op_EndpointWithHostLabelOperation.go new file mode 100644 index 00000000000..55c2415a591 --- /dev/null +++ b/internal/protocoltest/query/api_op_EndpointWithHostLabelOperation.go @@ -0,0 +1,149 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package query + +import ( + "context" + "fmt" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + smithy "github.com/aws/smithy-go" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" + "strings" +) + +func (c *Client) EndpointWithHostLabelOperation(ctx context.Context, params *EndpointWithHostLabelOperationInput, optFns ...func(*Options)) (*EndpointWithHostLabelOperationOutput, error) { + if params == nil { + params = &EndpointWithHostLabelOperationInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "EndpointWithHostLabelOperation", params, optFns, addOperationEndpointWithHostLabelOperationMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*EndpointWithHostLabelOperationOutput) + out.ResultMetadata = metadata + return out, nil +} + +type EndpointWithHostLabelOperationInput struct { + + // This member is required. + Label *string +} + +type EndpointWithHostLabelOperationOutput struct { + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata +} + +func addOperationEndpointWithHostLabelOperationMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsAwsquery_serializeOpEndpointWithHostLabelOperation{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsAwsquery_deserializeOpEndpointWithHostLabelOperation{}, middleware.After) + if err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = addEndpointPrefix_opEndpointWithHostLabelOperationMiddleware(stack); err != nil { + return err + } + if err = addOpEndpointWithHostLabelOperationValidationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opEndpointWithHostLabelOperation(options.Region), middleware.Before); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + return nil +} + +type endpointPrefix_opEndpointWithHostLabelOperationMiddleware struct { +} + +func (*endpointPrefix_opEndpointWithHostLabelOperationMiddleware) ID() string { + return "EndpointHostPrefix" +} + +func (m *endpointPrefix_opEndpointWithHostLabelOperationMiddleware) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + if smithyhttp.GetHostnameImmutable(ctx) || smithyhttp.IsEndpointHostPrefixDisabled(ctx) { + return next.HandleSerialize(ctx, in) + } + + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) + } + + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input type %T", in.Parameters) + } + + var prefix strings.Builder + prefix.WriteString("foo.") + if input.Label == nil { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("Label forms part of the endpoint host and so may not be nil")} + } else if !smithyhttp.ValidHostLabel(*input.Label) { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("Label forms part of the endpoint host and so must match \"[a-zA-Z0-9-]{1,63}\", but was \"%s\"", *input.Label)} + } else { + prefix.WriteString(*input.Label) + } + prefix.WriteString(".") + req.URL.Host = prefix.String() + req.URL.Host + + return next.HandleSerialize(ctx, in) +} +func addEndpointPrefix_opEndpointWithHostLabelOperationMiddleware(stack *middleware.Stack) error { + return stack.Serialize.Insert(&endpointPrefix_opEndpointWithHostLabelOperationMiddleware{}, `OperationSerializer`, middleware.After) +} + +func newServiceMetadataMiddleware_opEndpointWithHostLabelOperation(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "EndpointWithHostLabelOperation", + } +} diff --git a/internal/protocoltest/query/api_op_EndpointWithHostLabelOperation_test.go b/internal/protocoltest/query/api_op_EndpointWithHostLabelOperation_test.go new file mode 100644 index 00000000000..d44392c09ee --- /dev/null +++ b/internal/protocoltest/query/api_op_EndpointWithHostLabelOperation_test.go @@ -0,0 +1,125 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package query + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/ptr" + smithyrand "github.com/aws/smithy-go/rand" + smithytesting "github.com/aws/smithy-go/testing" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +func TestClient_EndpointWithHostLabelOperation_awsAwsquerySerialize(t *testing.T) { + cases := map[string]struct { + Params *EndpointWithHostLabelOperationInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Operations can prepend to the given host if they define the endpoint trait, and + // can use the host label trait to define further customization based on user + // input. + "AwsQueryEndpointTraitWithHostLabel": { + Params: &EndpointWithHostLabelOperationInput{ + Label: ptr.String("bar"), + }, + ExpectMethod: "POST", + ExpectURIPath: "/", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/x-www-form-urlencoded"}, + }, + BodyMediaType: "application/x-www-form-urlencoded", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareURLFormReaderBytes(actual, []byte(`Action=EndpointWithHostLabelOperation + &Version=2020-01-08 + &label=bar`)) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if name == "AwsQueryEndpointTraitWithHostLabel" { + t.Skip("disabled test aws.protocoltests.query#AwsQuery aws.protocoltests.query#EndpointWithHostLabelOperation") + } + + var actualReq *http.Request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + actualReq = r.Clone(r.Context()) + if len(actualReq.URL.RawPath) == 0 { + actualReq.URL.RawPath = actualReq.URL.Path + } + if v := actualReq.ContentLength; v != 0 { + actualReq.Header.Set("Content-Length", strconv.FormatInt(v, 10)) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, r.Body); err != nil { + t.Errorf("failed to read request body, %v", err) + } + actualReq.Body = ioutil.NopCloser(&buf) + + w.WriteHeader(200) + })) + defer server.Close() + url := server.URL + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = url + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: awshttp.NewBuildableClient(), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + result, err := client.EndpointWithHostLabelOperation(context.Background(), c.Params) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} diff --git a/internal/protocoltest/query/deserializers.go b/internal/protocoltest/query/deserializers.go index 10e2089918d..d1cf273a966 100644 --- a/internal/protocoltest/query/deserializers.go +++ b/internal/protocoltest/query/deserializers.go @@ -130,6 +130,146 @@ func awsAwsquery_deserializeOpErrorEmptyInputAndEmptyOutput(response *smithyhttp } } +type awsAwsquery_deserializeOpEndpointOperation struct { +} + +func (*awsAwsquery_deserializeOpEndpointOperation) ID() string { + return "OperationDeserializer" +} + +func (m *awsAwsquery_deserializeOpEndpointOperation) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsAwsquery_deserializeOpErrorEndpointOperation(response, &metadata) + } + output := &EndpointOperationOutput{} + out.Result = output + + if _, err = io.Copy(ioutil.Discard, response.Body); err != nil { + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to discard response body, %w", err), + } + } + + return out, metadata, err +} + +func awsAwsquery_deserializeOpErrorEndpointOperation(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + errorComponents, err := awsxml.GetErrorResponseComponents(errorBody, false) + if err != nil { + return err + } + if reqID := errorComponents.RequestID; len(reqID) != 0 { + awsmiddleware.SetRequestIDMetadata(metadata, reqID) + } + if len(errorComponents.Code) != 0 { + errorCode = errorComponents.Code + } + if len(errorComponents.Message) != 0 { + errorMessage = errorComponents.Message + } + errorBody.Seek(0, io.SeekStart) + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + +type awsAwsquery_deserializeOpEndpointWithHostLabelOperation struct { +} + +func (*awsAwsquery_deserializeOpEndpointWithHostLabelOperation) ID() string { + return "OperationDeserializer" +} + +func (m *awsAwsquery_deserializeOpEndpointWithHostLabelOperation) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsAwsquery_deserializeOpErrorEndpointWithHostLabelOperation(response, &metadata) + } + output := &EndpointWithHostLabelOperationOutput{} + out.Result = output + + if _, err = io.Copy(ioutil.Discard, response.Body); err != nil { + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to discard response body, %w", err), + } + } + + return out, metadata, err +} + +func awsAwsquery_deserializeOpErrorEndpointWithHostLabelOperation(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + errorComponents, err := awsxml.GetErrorResponseComponents(errorBody, false) + if err != nil { + return err + } + if reqID := errorComponents.RequestID; len(reqID) != 0 { + awsmiddleware.SetRequestIDMetadata(metadata, reqID) + } + if len(errorComponents.Code) != 0 { + errorCode = errorComponents.Code + } + if len(errorComponents.Message) != 0 { + errorMessage = errorComponents.Message + } + errorBody.Seek(0, io.SeekStart) + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + type awsAwsquery_deserializeOpFlattenedXmlMap struct { } diff --git a/internal/protocoltest/query/go.mod b/internal/protocoltest/query/go.mod index cc8d9ff8a7d..712e2b03e08 100644 --- a/internal/protocoltest/query/go.mod +++ b/internal/protocoltest/query/go.mod @@ -1,6 +1,6 @@ module github.com/aws/aws-sdk-go-v2/internal/protocoltest/query -go 1.15 +go 1.16 require ( github.com/aws/aws-sdk-go-v2 v1.2.0 diff --git a/internal/protocoltest/query/serializers.go b/internal/protocoltest/query/serializers.go index 64956341da4..3bc1bf74eaf 100644 --- a/internal/protocoltest/query/serializers.go +++ b/internal/protocoltest/query/serializers.go @@ -68,6 +68,114 @@ func (m *awsAwsquery_serializeOpEmptyInputAndEmptyOutput) HandleSerialize(ctx co return next.HandleSerialize(ctx, in) } +type awsAwsquery_serializeOpEndpointOperation struct { +} + +func (*awsAwsquery_serializeOpEndpointOperation) ID() string { + return "OperationSerializer" +} + +func (m *awsAwsquery_serializeOpEndpointOperation) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*EndpointOperationInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + request.Request.URL.Path = "/" + request.Request.Method = "POST" + httpBindingEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + httpBindingEncoder.SetHeader("Content-Type").String("application/x-www-form-urlencoded") + + bodyWriter := bytes.NewBuffer(nil) + bodyEncoder := query.NewEncoder(bodyWriter) + body := bodyEncoder.Object() + body.Key("Action").String("EndpointOperation") + body.Key("Version").String("2020-01-08") + + err = bodyEncoder.Encode() + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request, err = request.SetStream(bytes.NewReader(bodyWriter.Bytes())); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = httpBindingEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} + +type awsAwsquery_serializeOpEndpointWithHostLabelOperation struct { +} + +func (*awsAwsquery_serializeOpEndpointWithHostLabelOperation) ID() string { + return "OperationSerializer" +} + +func (m *awsAwsquery_serializeOpEndpointWithHostLabelOperation) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + request.Request.URL.Path = "/" + request.Request.Method = "POST" + httpBindingEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + httpBindingEncoder.SetHeader("Content-Type").String("application/x-www-form-urlencoded") + + bodyWriter := bytes.NewBuffer(nil) + bodyEncoder := query.NewEncoder(bodyWriter) + body := bodyEncoder.Object() + body.Key("Action").String("EndpointWithHostLabelOperation") + body.Key("Version").String("2020-01-08") + + if err := awsAwsquery_serializeOpDocumentEndpointWithHostLabelOperationInput(input, bodyEncoder.Value); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + err = bodyEncoder.Encode() + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request, err = request.SetStream(bytes.NewReader(bodyWriter.Bytes())); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = httpBindingEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} + type awsAwsquery_serializeOpFlattenedXmlMap struct { } @@ -1559,6 +1667,18 @@ func awsAwsquery_serializeOpDocumentEmptyInputAndEmptyOutputInput(v *EmptyInputA return nil } +func awsAwsquery_serializeOpDocumentEndpointWithHostLabelOperationInput(v *EndpointWithHostLabelOperationInput, value query.Value) error { + object := value.Object() + _ = object + + if v.Label != nil { + objectKey := object.Key("label") + objectKey.String(*v.Label) + } + + return nil +} + func awsAwsquery_serializeOpDocumentNestedStructuresInput(v *NestedStructuresInput, value query.Value) error { object := value.Object() _ = object diff --git a/internal/protocoltest/query/validators.go b/internal/protocoltest/query/validators.go index c847d040a6f..7517a43f239 100644 --- a/internal/protocoltest/query/validators.go +++ b/internal/protocoltest/query/validators.go @@ -1,3 +1,49 @@ // Code generated by smithy-go-codegen DO NOT EDIT. package query + +import ( + "context" + "fmt" + smithy "github.com/aws/smithy-go" + "github.com/aws/smithy-go/middleware" +) + +type validateOpEndpointWithHostLabelOperation struct { +} + +func (*validateOpEndpointWithHostLabelOperation) ID() string { + return "OperationInputValidation" +} + +func (m *validateOpEndpointWithHostLabelOperation) HandleInitialize(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) ( + out middleware.InitializeOutput, metadata middleware.Metadata, err error, +) { + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input parameters type %T", in.Parameters) + } + if err := validateOpEndpointWithHostLabelOperationInput(input); err != nil { + return out, metadata, err + } + return next.HandleInitialize(ctx, in) +} + +func addOpEndpointWithHostLabelOperationValidationMiddleware(stack *middleware.Stack) error { + return stack.Initialize.Add(&validateOpEndpointWithHostLabelOperation{}, middleware.After) +} + +func validateOpEndpointWithHostLabelOperationInput(v *EndpointWithHostLabelOperationInput) error { + if v == nil { + return nil + } + invalidParams := smithy.InvalidParamsError{Context: "EndpointWithHostLabelOperationInput"} + if v.Label == nil { + invalidParams.Add(smithy.NewErrParamRequired("Label")) + } + if invalidParams.Len() > 0 { + return invalidParams + } else { + return nil + } +} diff --git a/internal/protocoltest/restxml/api_op_EndpointOperation.go b/internal/protocoltest/restxml/api_op_EndpointOperation.go new file mode 100644 index 00000000000..7b17f7e4527 --- /dev/null +++ b/internal/protocoltest/restxml/api_op_EndpointOperation.go @@ -0,0 +1,126 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package restxml + +import ( + "context" + "fmt" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +func (c *Client) EndpointOperation(ctx context.Context, params *EndpointOperationInput, optFns ...func(*Options)) (*EndpointOperationOutput, error) { + if params == nil { + params = &EndpointOperationInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "EndpointOperation", params, optFns, addOperationEndpointOperationMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*EndpointOperationOutput) + out.ResultMetadata = metadata + return out, nil +} + +type EndpointOperationInput struct { +} + +type EndpointOperationOutput struct { + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata +} + +func addOperationEndpointOperationMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsRestxml_serializeOpEndpointOperation{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsRestxml_deserializeOpEndpointOperation{}, middleware.After) + if err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = addEndpointPrefix_opEndpointOperationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opEndpointOperation(options.Region), middleware.Before); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + return nil +} + +type endpointPrefix_opEndpointOperationMiddleware struct { +} + +func (*endpointPrefix_opEndpointOperationMiddleware) ID() string { + return "EndpointHostPrefix" +} + +func (m *endpointPrefix_opEndpointOperationMiddleware) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + if smithyhttp.GetHostnameImmutable(ctx) || smithyhttp.IsEndpointHostPrefixDisabled(ctx) { + return next.HandleSerialize(ctx, in) + } + + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) + } + + req.URL.Host = "foo." + req.URL.Host + + return next.HandleSerialize(ctx, in) +} +func addEndpointPrefix_opEndpointOperationMiddleware(stack *middleware.Stack) error { + return stack.Serialize.Insert(&endpointPrefix_opEndpointOperationMiddleware{}, `OperationSerializer`, middleware.After) +} + +func newServiceMetadataMiddleware_opEndpointOperation(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "EndpointOperation", + } +} diff --git a/internal/protocoltest/restxml/api_op_EndpointOperation_test.go b/internal/protocoltest/restxml/api_op_EndpointOperation_test.go new file mode 100644 index 00000000000..0a18372753d --- /dev/null +++ b/internal/protocoltest/restxml/api_op_EndpointOperation_test.go @@ -0,0 +1,114 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package restxml + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/smithy-go/middleware" + smithyrand "github.com/aws/smithy-go/rand" + smithytesting "github.com/aws/smithy-go/testing" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +func TestClient_EndpointOperation_awsRestxmlSerialize(t *testing.T) { + cases := map[string]struct { + Params *EndpointOperationInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Operations can prepend to the given host if they define the endpoint trait. + "RestXmlEndpointTrait": { + Params: &EndpointOperationInput{}, + ExpectMethod: "POST", + ExpectURIPath: "/EndpointOperation", + ExpectQuery: []smithytesting.QueryItem{}, + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareReaderEmpty(actual) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if name == "RestXmlEndpointTrait" { + t.Skip("disabled test aws.protocoltests.restxml#RestXml aws.protocoltests.restxml#EndpointOperation") + } + + var actualReq *http.Request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + actualReq = r.Clone(r.Context()) + if len(actualReq.URL.RawPath) == 0 { + actualReq.URL.RawPath = actualReq.URL.Path + } + if v := actualReq.ContentLength; v != 0 { + actualReq.Header.Set("Content-Length", strconv.FormatInt(v, 10)) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, r.Body); err != nil { + t.Errorf("failed to read request body, %v", err) + } + actualReq.Body = ioutil.NopCloser(&buf) + + w.WriteHeader(200) + })) + defer server.Close() + url := server.URL + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = url + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: awshttp.NewBuildableClient(), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + result, err := client.EndpointOperation(context.Background(), c.Params) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} diff --git a/internal/protocoltest/restxml/api_op_EndpointWithHostLabelHeaderOperation.go b/internal/protocoltest/restxml/api_op_EndpointWithHostLabelHeaderOperation.go new file mode 100644 index 00000000000..4d14c196733 --- /dev/null +++ b/internal/protocoltest/restxml/api_op_EndpointWithHostLabelHeaderOperation.go @@ -0,0 +1,148 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package restxml + +import ( + "context" + "fmt" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + smithy "github.com/aws/smithy-go" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" + "strings" +) + +func (c *Client) EndpointWithHostLabelHeaderOperation(ctx context.Context, params *EndpointWithHostLabelHeaderOperationInput, optFns ...func(*Options)) (*EndpointWithHostLabelHeaderOperationOutput, error) { + if params == nil { + params = &EndpointWithHostLabelHeaderOperationInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "EndpointWithHostLabelHeaderOperation", params, optFns, addOperationEndpointWithHostLabelHeaderOperationMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*EndpointWithHostLabelHeaderOperationOutput) + out.ResultMetadata = metadata + return out, nil +} + +type EndpointWithHostLabelHeaderOperationInput struct { + + // This member is required. + AccountId *string +} + +type EndpointWithHostLabelHeaderOperationOutput struct { + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata +} + +func addOperationEndpointWithHostLabelHeaderOperationMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsRestxml_serializeOpEndpointWithHostLabelHeaderOperation{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsRestxml_deserializeOpEndpointWithHostLabelHeaderOperation{}, middleware.After) + if err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = addEndpointPrefix_opEndpointWithHostLabelHeaderOperationMiddleware(stack); err != nil { + return err + } + if err = addOpEndpointWithHostLabelHeaderOperationValidationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opEndpointWithHostLabelHeaderOperation(options.Region), middleware.Before); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + return nil +} + +type endpointPrefix_opEndpointWithHostLabelHeaderOperationMiddleware struct { +} + +func (*endpointPrefix_opEndpointWithHostLabelHeaderOperationMiddleware) ID() string { + return "EndpointHostPrefix" +} + +func (m *endpointPrefix_opEndpointWithHostLabelHeaderOperationMiddleware) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + if smithyhttp.GetHostnameImmutable(ctx) || smithyhttp.IsEndpointHostPrefixDisabled(ctx) { + return next.HandleSerialize(ctx, in) + } + + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) + } + + input, ok := in.Parameters.(*EndpointWithHostLabelHeaderOperationInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input type %T", in.Parameters) + } + + var prefix strings.Builder + if input.AccountId == nil { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("AccountId forms part of the endpoint host and so may not be nil")} + } else if !smithyhttp.ValidHostLabel(*input.AccountId) { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("AccountId forms part of the endpoint host and so must match \"[a-zA-Z0-9-]{1,63}\", but was \"%s\"", *input.AccountId)} + } else { + prefix.WriteString(*input.AccountId) + } + prefix.WriteString(".") + req.URL.Host = prefix.String() + req.URL.Host + + return next.HandleSerialize(ctx, in) +} +func addEndpointPrefix_opEndpointWithHostLabelHeaderOperationMiddleware(stack *middleware.Stack) error { + return stack.Serialize.Insert(&endpointPrefix_opEndpointWithHostLabelHeaderOperationMiddleware{}, `OperationSerializer`, middleware.After) +} + +func newServiceMetadataMiddleware_opEndpointWithHostLabelHeaderOperation(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "EndpointWithHostLabelHeaderOperation", + } +} diff --git a/internal/protocoltest/restxml/api_op_EndpointWithHostLabelHeaderOperation_test.go b/internal/protocoltest/restxml/api_op_EndpointWithHostLabelHeaderOperation_test.go new file mode 100644 index 00000000000..213cb2d6f5f --- /dev/null +++ b/internal/protocoltest/restxml/api_op_EndpointWithHostLabelHeaderOperation_test.go @@ -0,0 +1,124 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package restxml + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/ptr" + smithyrand "github.com/aws/smithy-go/rand" + smithytesting "github.com/aws/smithy-go/testing" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +func TestClient_EndpointWithHostLabelHeaderOperation_awsRestxmlSerialize(t *testing.T) { + cases := map[string]struct { + Params *EndpointWithHostLabelHeaderOperationInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Operations can prepend to the given host if they define the endpoint trait, and + // can use the host label trait to define further customization based on user + // input. The label must also be serialized in into any other location it is bound + // to, such as the body or in this case an http header. + "RestXmlEndpointTraitWithHostLabelAndHttpBinding": { + Params: &EndpointWithHostLabelHeaderOperationInput{ + AccountId: ptr.String("bar"), + }, + ExpectMethod: "POST", + ExpectURIPath: "/EndpointWithHostLabelHeaderOperation", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "X-Amz-Account-Id": []string{"bar"}, + }, + BodyMediaType: "application/xml", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareReaderEmpty(actual) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if name == "RestXmlEndpointTraitWithHostLabelAndHttpBinding" { + t.Skip("disabled test aws.protocoltests.restxml#RestXml aws.protocoltests.restxml#EndpointWithHostLabelHeaderOperation") + } + + var actualReq *http.Request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + actualReq = r.Clone(r.Context()) + if len(actualReq.URL.RawPath) == 0 { + actualReq.URL.RawPath = actualReq.URL.Path + } + if v := actualReq.ContentLength; v != 0 { + actualReq.Header.Set("Content-Length", strconv.FormatInt(v, 10)) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, r.Body); err != nil { + t.Errorf("failed to read request body, %v", err) + } + actualReq.Body = ioutil.NopCloser(&buf) + + w.WriteHeader(200) + })) + defer server.Close() + url := server.URL + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = url + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: awshttp.NewBuildableClient(), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + result, err := client.EndpointWithHostLabelHeaderOperation(context.Background(), c.Params) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} diff --git a/internal/protocoltest/restxml/api_op_EndpointWithHostLabelOperation.go b/internal/protocoltest/restxml/api_op_EndpointWithHostLabelOperation.go new file mode 100644 index 00000000000..8670ae97cd6 --- /dev/null +++ b/internal/protocoltest/restxml/api_op_EndpointWithHostLabelOperation.go @@ -0,0 +1,149 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package restxml + +import ( + "context" + "fmt" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + smithy "github.com/aws/smithy-go" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" + "strings" +) + +func (c *Client) EndpointWithHostLabelOperation(ctx context.Context, params *EndpointWithHostLabelOperationInput, optFns ...func(*Options)) (*EndpointWithHostLabelOperationOutput, error) { + if params == nil { + params = &EndpointWithHostLabelOperationInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "EndpointWithHostLabelOperation", params, optFns, addOperationEndpointWithHostLabelOperationMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*EndpointWithHostLabelOperationOutput) + out.ResultMetadata = metadata + return out, nil +} + +type EndpointWithHostLabelOperationInput struct { + + // This member is required. + Label *string +} + +type EndpointWithHostLabelOperationOutput struct { + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata +} + +func addOperationEndpointWithHostLabelOperationMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsRestxml_serializeOpEndpointWithHostLabelOperation{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsRestxml_deserializeOpEndpointWithHostLabelOperation{}, middleware.After) + if err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = addEndpointPrefix_opEndpointWithHostLabelOperationMiddleware(stack); err != nil { + return err + } + if err = addOpEndpointWithHostLabelOperationValidationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opEndpointWithHostLabelOperation(options.Region), middleware.Before); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + return nil +} + +type endpointPrefix_opEndpointWithHostLabelOperationMiddleware struct { +} + +func (*endpointPrefix_opEndpointWithHostLabelOperationMiddleware) ID() string { + return "EndpointHostPrefix" +} + +func (m *endpointPrefix_opEndpointWithHostLabelOperationMiddleware) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + if smithyhttp.GetHostnameImmutable(ctx) || smithyhttp.IsEndpointHostPrefixDisabled(ctx) { + return next.HandleSerialize(ctx, in) + } + + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) + } + + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input type %T", in.Parameters) + } + + var prefix strings.Builder + prefix.WriteString("foo.") + if input.Label == nil { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("Label forms part of the endpoint host and so may not be nil")} + } else if !smithyhttp.ValidHostLabel(*input.Label) { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("Label forms part of the endpoint host and so must match \"[a-zA-Z0-9-]{1,63}\", but was \"%s\"", *input.Label)} + } else { + prefix.WriteString(*input.Label) + } + prefix.WriteString(".") + req.URL.Host = prefix.String() + req.URL.Host + + return next.HandleSerialize(ctx, in) +} +func addEndpointPrefix_opEndpointWithHostLabelOperationMiddleware(stack *middleware.Stack) error { + return stack.Serialize.Insert(&endpointPrefix_opEndpointWithHostLabelOperationMiddleware{}, `OperationSerializer`, middleware.After) +} + +func newServiceMetadataMiddleware_opEndpointWithHostLabelOperation(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "EndpointWithHostLabelOperation", + } +} diff --git a/internal/protocoltest/restxml/api_op_EndpointWithHostLabelOperation_test.go b/internal/protocoltest/restxml/api_op_EndpointWithHostLabelOperation_test.go new file mode 100644 index 00000000000..db2ac31983d --- /dev/null +++ b/internal/protocoltest/restxml/api_op_EndpointWithHostLabelOperation_test.go @@ -0,0 +1,123 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package restxml + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/ptr" + smithyrand "github.com/aws/smithy-go/rand" + smithytesting "github.com/aws/smithy-go/testing" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +func TestClient_EndpointWithHostLabelOperation_awsRestxmlSerialize(t *testing.T) { + cases := map[string]struct { + Params *EndpointWithHostLabelOperationInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Operations can prepend to the given host if they define the endpoint trait, and + // can use the host label trait to define further customization based on user + // input. + "RestXmlEndpointTraitWithHostLabel": { + Params: &EndpointWithHostLabelOperationInput{ + Label: ptr.String("bar"), + }, + ExpectMethod: "POST", + ExpectURIPath: "/EndpointWithHostLabelOperation", + ExpectQuery: []smithytesting.QueryItem{}, + BodyMediaType: "application/xml", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareXMLReaderBytes(actual, []byte(` + + + `)) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if name == "RestXmlEndpointTraitWithHostLabel" { + t.Skip("disabled test aws.protocoltests.restxml#RestXml aws.protocoltests.restxml#EndpointWithHostLabelOperation") + } + + var actualReq *http.Request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + actualReq = r.Clone(r.Context()) + if len(actualReq.URL.RawPath) == 0 { + actualReq.URL.RawPath = actualReq.URL.Path + } + if v := actualReq.ContentLength; v != 0 { + actualReq.Header.Set("Content-Length", strconv.FormatInt(v, 10)) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, r.Body); err != nil { + t.Errorf("failed to read request body, %v", err) + } + actualReq.Body = ioutil.NopCloser(&buf) + + w.WriteHeader(200) + })) + defer server.Close() + url := server.URL + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = url + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: awshttp.NewBuildableClient(), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + result, err := client.EndpointWithHostLabelOperation(context.Background(), c.Params) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} diff --git a/internal/protocoltest/restxml/api_op_IgnoreQueryParamsInResponse_test.go b/internal/protocoltest/restxml/api_op_IgnoreQueryParamsInResponse_test.go index 7dd6991d78a..6ef0683f4a6 100644 --- a/internal/protocoltest/restxml/api_op_IgnoreQueryParamsInResponse_test.go +++ b/internal/protocoltest/restxml/api_op_IgnoreQueryParamsInResponse_test.go @@ -31,7 +31,7 @@ func TestClient_IgnoreQueryParamsInResponse_awsRestxmlDeserialize(t *testing.T) Header: http.Header{ "Content-Type": []string{"application/xml"}, }, - BodyMediaType: "xml", + BodyMediaType: "application/xml", Body: []byte(`bam`), ExpectResult: &IgnoreQueryParamsInResponseOutput{ Baz: ptr.String("bam"), diff --git a/internal/protocoltest/restxml/api_op_XmlUnions.go b/internal/protocoltest/restxml/api_op_XmlUnions.go new file mode 100644 index 00000000000..018717e84a2 --- /dev/null +++ b/internal/protocoltest/restxml/api_op_XmlUnions.go @@ -0,0 +1,99 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package restxml + +import ( + "context" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/aws-sdk-go-v2/internal/protocoltest/restxml/types" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +func (c *Client) XmlUnions(ctx context.Context, params *XmlUnionsInput, optFns ...func(*Options)) (*XmlUnionsOutput, error) { + if params == nil { + params = &XmlUnionsInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "XmlUnions", params, optFns, addOperationXmlUnionsMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*XmlUnionsOutput) + out.ResultMetadata = metadata + return out, nil +} + +type XmlUnionsInput struct { + UnionValue types.XmlUnionShape +} + +type XmlUnionsOutput struct { + UnionValue types.XmlUnionShape + + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata +} + +func addOperationXmlUnionsMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsRestxml_serializeOpXmlUnions{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsRestxml_deserializeOpXmlUnions{}, middleware.After) + if err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opXmlUnions(options.Region), middleware.Before); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + return nil +} + +func newServiceMetadataMiddleware_opXmlUnions(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "XmlUnions", + } +} diff --git a/internal/protocoltest/restxml/api_op_XmlUnions_test.go b/internal/protocoltest/restxml/api_op_XmlUnions_test.go new file mode 100644 index 00000000000..6b51366e90b --- /dev/null +++ b/internal/protocoltest/restxml/api_op_XmlUnions_test.go @@ -0,0 +1,362 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package restxml + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/aws-sdk-go-v2/internal/protocoltest/restxml/types" + "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/ptr" + smithyrand "github.com/aws/smithy-go/rand" + smithytesting "github.com/aws/smithy-go/testing" + smithyhttp "github.com/aws/smithy-go/transport/http" + "github.com/google/go-cmp/cmp/cmpopts" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +func TestClient_XmlUnions_awsRestxmlSerialize(t *testing.T) { + cases := map[string]struct { + Params *XmlUnionsInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Serializes union struct member + "XmlUnionsWithStructMember": { + Params: &XmlUnionsInput{ + UnionValue: &types.XmlUnionShapeMemberStructValue{Value: types.XmlNestedUnionStruct{ + StringValue: ptr.String("string"), + BooleanValue: ptr.Bool(true), + ByteValue: ptr.Int8(1), + ShortValue: ptr.Int16(2), + IntegerValue: ptr.Int32(3), + LongValue: ptr.Int64(4), + FloatValue: ptr.Float32(5.5), + DoubleValue: ptr.Float64(6.5), + }}, + }, + ExpectMethod: "PUT", + ExpectURIPath: "/XmlUnions", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/xml"}, + }, + BodyMediaType: "application/xml", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareXMLReaderBytes(actual, []byte(` + + + string + true + 1 + 2 + 3 + 4 + 5.5 + 6.5 + + + + `)) + }, + }, + // serialize union string member + "XmlUnionsWithStringMember": { + Params: &XmlUnionsInput{ + UnionValue: &types.XmlUnionShapeMemberStringValue{Value: "some string"}, + }, + ExpectMethod: "PUT", + ExpectURIPath: "/XmlUnions", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/xml"}, + }, + BodyMediaType: "application/xml", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareXMLReaderBytes(actual, []byte(` + + some string + + + `)) + }, + }, + // Serializes union boolean member + "XmlUnionsWithBooleanMember": { + Params: &XmlUnionsInput{ + UnionValue: &types.XmlUnionShapeMemberBooleanValue{Value: true}, + }, + ExpectMethod: "PUT", + ExpectURIPath: "/XmlUnions", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/xml"}, + }, + BodyMediaType: "application/xml", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareXMLReaderBytes(actual, []byte(` + + true + + + `)) + }, + }, + // Serializes union union member + "XmlUnionsWithUnionMember": { + Params: &XmlUnionsInput{ + UnionValue: &types.XmlUnionShapeMemberUnionValue{Value: &types.XmlUnionShapeMemberBooleanValue{Value: true}}, + }, + ExpectMethod: "PUT", + ExpectURIPath: "/XmlUnions", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/xml"}, + }, + BodyMediaType: "application/xml", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareXMLReaderBytes(actual, []byte(` + + + true + + + + `)) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + var actualReq *http.Request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + actualReq = r.Clone(r.Context()) + if len(actualReq.URL.RawPath) == 0 { + actualReq.URL.RawPath = actualReq.URL.Path + } + if v := actualReq.ContentLength; v != 0 { + actualReq.Header.Set("Content-Length", strconv.FormatInt(v, 10)) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, r.Body); err != nil { + t.Errorf("failed to read request body, %v", err) + } + actualReq.Body = ioutil.NopCloser(&buf) + + w.WriteHeader(200) + })) + defer server.Close() + url := server.URL + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = url + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: awshttp.NewBuildableClient(), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + result, err := client.XmlUnions(context.Background(), c.Params) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} + +func TestClient_XmlUnions_awsRestxmlDeserialize(t *testing.T) { + cases := map[string]struct { + StatusCode int + Header http.Header + BodyMediaType string + Body []byte + ExpectResult *XmlUnionsOutput + }{ + // Serializes union struct member + "XmlUnionsWithStructMember": { + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/xml"}, + }, + BodyMediaType: "application/xml", + Body: []byte(` + + + string + true + 1 + 2 + 3 + 4 + 5.5 + 6.5 + + + + `), + ExpectResult: &XmlUnionsOutput{ + UnionValue: &types.XmlUnionShapeMemberStructValue{Value: types.XmlNestedUnionStruct{ + StringValue: ptr.String("string"), + BooleanValue: ptr.Bool(true), + ByteValue: ptr.Int8(1), + ShortValue: ptr.Int16(2), + IntegerValue: ptr.Int32(3), + LongValue: ptr.Int64(4), + FloatValue: ptr.Float32(5.5), + DoubleValue: ptr.Float64(6.5), + }}, + }, + }, + // Serializes union string member + "XmlUnionsWithStringMember": { + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/xml"}, + }, + BodyMediaType: "application/xml", + Body: []byte(` + + some string + + + `), + ExpectResult: &XmlUnionsOutput{ + UnionValue: &types.XmlUnionShapeMemberStringValue{Value: "some string"}, + }, + }, + // Serializes union boolean member + "XmlUnionsWithBooleanMember": { + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/xml"}, + }, + BodyMediaType: "application/xml", + Body: []byte(` + + true + + + `), + ExpectResult: &XmlUnionsOutput{ + UnionValue: &types.XmlUnionShapeMemberBooleanValue{Value: true}, + }, + }, + // Serializes union union member + "XmlUnionsWithUnionMember": { + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/xml"}, + }, + BodyMediaType: "application/xml", + Body: []byte(` + + + true + + + + `), + ExpectResult: &XmlUnionsOutput{ + UnionValue: &types.XmlUnionShapeMemberUnionValue{Value: &types.XmlUnionShapeMemberBooleanValue{Value: true}}, + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + url := "http://localhost:8888/" + client := New(Options{ + HTTPClient: smithyhttp.ClientDoFunc(func(r *http.Request) (*http.Response, error) { + headers := http.Header{} + for k, vs := range c.Header { + for _, v := range vs { + headers.Add(k, v) + } + } + if len(c.BodyMediaType) != 0 && len(headers.Values("Content-Type")) == 0 { + headers.Set("Content-Type", c.BodyMediaType) + } + response := &http.Response{ + StatusCode: c.StatusCode, + Header: headers, + Request: r, + } + if len(c.Body) != 0 { + response.ContentLength = int64(len(c.Body)) + response.Body = ioutil.NopCloser(bytes.NewReader(c.Body)) + } else { + + response.Body = http.NoBody + } + return response, nil + }), + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = url + e.SigningRegion = "us-west-2" + return e, err + }), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + var params XmlUnionsInput + result, err := client.XmlUnions(context.Background(), ¶ms) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if err := smithytesting.CompareValues(c.ExpectResult, result, cmpopts.IgnoreUnexported(middleware.Metadata{})); err != nil { + t.Errorf("expect c.ExpectResult value match:\n%v", err) + } + }) + } +} diff --git a/internal/protocoltest/restxml/deserializers.go b/internal/protocoltest/restxml/deserializers.go index ee315308b71..2dfb0a6e0df 100644 --- a/internal/protocoltest/restxml/deserializers.go +++ b/internal/protocoltest/restxml/deserializers.go @@ -299,6 +299,216 @@ func awsRestxml_deserializeOpErrorEmptyInputAndEmptyOutput(response *smithyhttp. } } +type awsRestxml_deserializeOpEndpointOperation struct { +} + +func (*awsRestxml_deserializeOpEndpointOperation) ID() string { + return "OperationDeserializer" +} + +func (m *awsRestxml_deserializeOpEndpointOperation) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsRestxml_deserializeOpErrorEndpointOperation(response, &metadata) + } + output := &EndpointOperationOutput{} + out.Result = output + + if _, err = io.Copy(ioutil.Discard, response.Body); err != nil { + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to discard response body, %w", err), + } + } + + return out, metadata, err +} + +func awsRestxml_deserializeOpErrorEndpointOperation(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + errorComponents, err := awsxml.GetErrorResponseComponents(errorBody, false) + if err != nil { + return err + } + if reqID := errorComponents.RequestID; len(reqID) != 0 { + awsmiddleware.SetRequestIDMetadata(metadata, reqID) + } + if len(errorComponents.Code) != 0 { + errorCode = errorComponents.Code + } + if len(errorComponents.Message) != 0 { + errorMessage = errorComponents.Message + } + errorBody.Seek(0, io.SeekStart) + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + +type awsRestxml_deserializeOpEndpointWithHostLabelHeaderOperation struct { +} + +func (*awsRestxml_deserializeOpEndpointWithHostLabelHeaderOperation) ID() string { + return "OperationDeserializer" +} + +func (m *awsRestxml_deserializeOpEndpointWithHostLabelHeaderOperation) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsRestxml_deserializeOpErrorEndpointWithHostLabelHeaderOperation(response, &metadata) + } + output := &EndpointWithHostLabelHeaderOperationOutput{} + out.Result = output + + if _, err = io.Copy(ioutil.Discard, response.Body); err != nil { + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to discard response body, %w", err), + } + } + + return out, metadata, err +} + +func awsRestxml_deserializeOpErrorEndpointWithHostLabelHeaderOperation(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + errorComponents, err := awsxml.GetErrorResponseComponents(errorBody, false) + if err != nil { + return err + } + if reqID := errorComponents.RequestID; len(reqID) != 0 { + awsmiddleware.SetRequestIDMetadata(metadata, reqID) + } + if len(errorComponents.Code) != 0 { + errorCode = errorComponents.Code + } + if len(errorComponents.Message) != 0 { + errorMessage = errorComponents.Message + } + errorBody.Seek(0, io.SeekStart) + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + +type awsRestxml_deserializeOpEndpointWithHostLabelOperation struct { +} + +func (*awsRestxml_deserializeOpEndpointWithHostLabelOperation) ID() string { + return "OperationDeserializer" +} + +func (m *awsRestxml_deserializeOpEndpointWithHostLabelOperation) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsRestxml_deserializeOpErrorEndpointWithHostLabelOperation(response, &metadata) + } + output := &EndpointWithHostLabelOperationOutput{} + out.Result = output + + if _, err = io.Copy(ioutil.Discard, response.Body); err != nil { + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to discard response body, %w", err), + } + } + + return out, metadata, err +} + +func awsRestxml_deserializeOpErrorEndpointWithHostLabelOperation(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + errorComponents, err := awsxml.GetErrorResponseComponents(errorBody, false) + if err != nil { + return err + } + if reqID := errorComponents.RequestID; len(reqID) != 0 { + awsmiddleware.SetRequestIDMetadata(metadata, reqID) + } + if len(errorComponents.Code) != 0 { + errorCode = errorComponents.Code + } + if len(errorComponents.Message) != 0 { + errorMessage = errorComponents.Message + } + errorBody.Seek(0, io.SeekStart) + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + type awsRestxml_deserializeOpFlattenedXmlMap struct { } @@ -5414,77 +5624,211 @@ func awsRestxml_deserializeOpDocumentXmlTimestampsOutput(v **XmlTimestampsOutput return nil } -func awsRestxml_deserializeOpHttpBindingsComplexError(v *types.ComplexError, response *smithyhttp.Response) error { - if v == nil { - return fmt.Errorf("unsupported deserialization for nil %T", v) +type awsRestxml_deserializeOpXmlUnions struct { +} + +func (*awsRestxml_deserializeOpXmlUnions) ID() string { + return "OperationDeserializer" +} + +func (m *awsRestxml_deserializeOpXmlUnions) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err } - if headerValues := response.Header.Values("X-Header"); len(headerValues) != 0 { - headerValues[0] = strings.TrimSpace(headerValues[0]) - v.Header = ptr.String(headerValues[0]) + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} } - return nil -} -func awsRestxml_deserializeErrorComplexError(response *smithyhttp.Response, errorBody *bytes.Reader) error { - output := &types.ComplexError{} - if err := awsRestxml_deserializeOpHttpBindingsComplexError(output, response); err != nil { - return &smithy.DeserializationError{Err: fmt.Errorf("failed to decode response error with invalid HTTP bindings, %w", err)} + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsRestxml_deserializeOpErrorXmlUnions(response, &metadata) } + output := &XmlUnionsOutput{} + out.Result = output + var buff [1024]byte ringBuffer := smithyio.NewRingBuffer(buff[:]) - body := io.TeeReader(errorBody, ringBuffer) + body := io.TeeReader(response.Body, ringBuffer) rootDecoder := xml.NewDecoder(body) t, err := smithyxml.FetchRootElement(rootDecoder) if err == io.EOF { - return output + return out, metadata, nil } if err != nil { var snapshot bytes.Buffer io.Copy(&snapshot, ringBuffer) - return &smithy.DeserializationError{ + return out, metadata, &smithy.DeserializationError{ Err: fmt.Errorf("failed to decode response body, %w", err), Snapshot: snapshot.Bytes(), } } decoder := smithyxml.WrapNodeDecoder(rootDecoder, t) - t, err = decoder.GetElement("Error") - if err != nil { - var snapshot bytes.Buffer - io.Copy(&snapshot, ringBuffer) - return &smithy.DeserializationError{ - Err: fmt.Errorf("failed to decode response body, %w", err), - Snapshot: snapshot.Bytes(), - } - } - - decoder = smithyxml.WrapNodeDecoder(decoder.Decoder, t) - err = awsRestxml_deserializeDocumentComplexError(&output, decoder) + err = awsRestxml_deserializeOpDocumentXmlUnionsOutput(&output, decoder) if err != nil { var snapshot bytes.Buffer io.Copy(&snapshot, ringBuffer) - return &smithy.DeserializationError{ + return out, metadata, &smithy.DeserializationError{ Err: fmt.Errorf("failed to decode response body, %w", err), Snapshot: snapshot.Bytes(), } } - return output + return out, metadata, err } -func awsRestxml_deserializeErrorInvalidGreeting(response *smithyhttp.Response, errorBody *bytes.Reader) error { - output := &types.InvalidGreeting{} - var buff [1024]byte - ringBuffer := smithyio.NewRingBuffer(buff[:]) - body := io.TeeReader(errorBody, ringBuffer) - rootDecoder := xml.NewDecoder(body) - t, err := smithyxml.FetchRootElement(rootDecoder) - if err == io.EOF { - return output +func awsRestxml_deserializeOpErrorXmlUnions(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} } - if err != nil { - var snapshot bytes.Buffer + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + errorComponents, err := awsxml.GetErrorResponseComponents(errorBody, false) + if err != nil { + return err + } + if reqID := errorComponents.RequestID; len(reqID) != 0 { + awsmiddleware.SetRequestIDMetadata(metadata, reqID) + } + if len(errorComponents.Code) != 0 { + errorCode = errorComponents.Code + } + if len(errorComponents.Message) != 0 { + errorMessage = errorComponents.Message + } + errorBody.Seek(0, io.SeekStart) + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + +func awsRestxml_deserializeOpDocumentXmlUnionsOutput(v **XmlUnionsOutput, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var sv *XmlUnionsOutput + if *v == nil { + sv = &XmlUnionsOutput{} + } else { + sv = *v + } + + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + originalDecoder := decoder + decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) + switch { + case strings.EqualFold("unionValue", t.Name.Local): + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + if err := awsRestxml_deserializeDocumentXmlUnionShape(&sv.UnionValue, nodeDecoder); err != nil { + return err + } + + default: + // Do nothing and ignore the unexpected tag element + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + decoder = originalDecoder + } + *v = sv + return nil +} + +func awsRestxml_deserializeOpHttpBindingsComplexError(v *types.ComplexError, response *smithyhttp.Response) error { + if v == nil { + return fmt.Errorf("unsupported deserialization for nil %T", v) + } + + if headerValues := response.Header.Values("X-Header"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.Header = ptr.String(headerValues[0]) + } + + return nil +} +func awsRestxml_deserializeErrorComplexError(response *smithyhttp.Response, errorBody *bytes.Reader) error { + output := &types.ComplexError{} + if err := awsRestxml_deserializeOpHttpBindingsComplexError(output, response); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to decode response error with invalid HTTP bindings, %w", err)} + } + var buff [1024]byte + ringBuffer := smithyio.NewRingBuffer(buff[:]) + body := io.TeeReader(errorBody, ringBuffer) + rootDecoder := xml.NewDecoder(body) + t, err := smithyxml.FetchRootElement(rootDecoder) + if err == io.EOF { + return output + } + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + return &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + } + + decoder := smithyxml.WrapNodeDecoder(rootDecoder, t) + t, err = decoder.GetElement("Error") + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + return &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + } + + decoder = smithyxml.WrapNodeDecoder(decoder.Decoder, t) + err = awsRestxml_deserializeDocumentComplexError(&output, decoder) + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + return &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + } + + return output +} + +func awsRestxml_deserializeErrorInvalidGreeting(response *smithyhttp.Response, errorBody *bytes.Reader) error { + output := &types.InvalidGreeting{} + var buff [1024]byte + ringBuffer := smithyio.NewRingBuffer(buff[:]) + body := io.TeeReader(errorBody, ringBuffer) + rootDecoder := xml.NewDecoder(body) + t, err := smithyxml.FetchRootElement(rootDecoder) + if err == io.EOF { + return output + } + if err != nil { + var snapshot bytes.Buffer io.Copy(&snapshot, ringBuffer) return &smithy.DeserializationError{ Err: fmt.Errorf("failed to decode response body, %w", err), @@ -6955,6 +7299,381 @@ func awsRestxml_deserializeDocumentXmlNamespaceNested(v **types.XmlNamespaceNest return nil } +func awsRestxml_deserializeDocumentXmlNestedUnionStruct(v **types.XmlNestedUnionStruct, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var sv *types.XmlNestedUnionStruct + if *v == nil { + sv = &types.XmlNestedUnionStruct{} + } else { + sv = *v + } + + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + originalDecoder := decoder + decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) + switch { + case strings.EqualFold("booleanValue", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv, err := strconv.ParseBool(string(val)) + if err != nil { + return fmt.Errorf("expected Boolean to be of type *bool, got %T instead", val) + } + sv.BooleanValue = ptr.Bool(xtv) + } + + case strings.EqualFold("byteValue", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + i64, err := strconv.ParseInt(xtv, 10, 64) + if err != nil { + return err + } + sv.ByteValue = ptr.Int8(int8(i64)) + } + + case strings.EqualFold("doubleValue", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + f64, err := strconv.ParseFloat(xtv, 64) + if err != nil { + return err + } + sv.DoubleValue = ptr.Float64(f64) + } + + case strings.EqualFold("floatValue", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + f64, err := strconv.ParseFloat(xtv, 64) + if err != nil { + return err + } + sv.FloatValue = ptr.Float32(float32(f64)) + } + + case strings.EqualFold("integerValue", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + i64, err := strconv.ParseInt(xtv, 10, 64) + if err != nil { + return err + } + sv.IntegerValue = ptr.Int32(int32(i64)) + } + + case strings.EqualFold("longValue", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + i64, err := strconv.ParseInt(xtv, 10, 64) + if err != nil { + return err + } + sv.LongValue = ptr.Int64(i64) + } + + case strings.EqualFold("shortValue", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + i64, err := strconv.ParseInt(xtv, 10, 64) + if err != nil { + return err + } + sv.ShortValue = ptr.Int16(int16(i64)) + } + + case strings.EqualFold("stringValue", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.StringValue = ptr.String(xtv) + } + + default: + // Do nothing and ignore the unexpected tag element + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + decoder = originalDecoder + } + *v = sv + return nil +} + +func awsRestxml_deserializeDocumentXmlUnionShape(v *types.XmlUnionShape, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var uv types.XmlUnionShape + var memberFound bool + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + if memberFound { + if err = decoder.Decoder.Skip(); err != nil { + return err + } + } + originalDecoder := decoder + decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) + switch { + case strings.EqualFold("booleanValue", t.Name.Local): + var mv bool + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv, err := strconv.ParseBool(string(val)) + if err != nil { + return fmt.Errorf("expected Boolean to be of type *bool, got %T instead", val) + } + mv = xtv + } + uv = &types.XmlUnionShapeMemberBooleanValue{Value: mv} + memberFound = true + + case strings.EqualFold("byteValue", t.Name.Local): + var mv int8 + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + i64, err := strconv.ParseInt(xtv, 10, 64) + if err != nil { + return err + } + mv = int8(i64) + } + uv = &types.XmlUnionShapeMemberByteValue{Value: mv} + memberFound = true + + case strings.EqualFold("doubleValue", t.Name.Local): + var mv float64 + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + f64, err := strconv.ParseFloat(xtv, 64) + if err != nil { + return err + } + mv = f64 + } + uv = &types.XmlUnionShapeMemberDoubleValue{Value: mv} + memberFound = true + + case strings.EqualFold("floatValue", t.Name.Local): + var mv float32 + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + f64, err := strconv.ParseFloat(xtv, 64) + if err != nil { + return err + } + mv = float32(f64) + } + uv = &types.XmlUnionShapeMemberFloatValue{Value: mv} + memberFound = true + + case strings.EqualFold("integerValue", t.Name.Local): + var mv int32 + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + i64, err := strconv.ParseInt(xtv, 10, 64) + if err != nil { + return err + } + mv = int32(i64) + } + uv = &types.XmlUnionShapeMemberIntegerValue{Value: mv} + memberFound = true + + case strings.EqualFold("longValue", t.Name.Local): + var mv int64 + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + i64, err := strconv.ParseInt(xtv, 10, 64) + if err != nil { + return err + } + mv = i64 + } + uv = &types.XmlUnionShapeMemberLongValue{Value: mv} + memberFound = true + + case strings.EqualFold("shortValue", t.Name.Local): + var mv int16 + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + i64, err := strconv.ParseInt(xtv, 10, 64) + if err != nil { + return err + } + mv = int16(i64) + } + uv = &types.XmlUnionShapeMemberShortValue{Value: mv} + memberFound = true + + case strings.EqualFold("stringValue", t.Name.Local): + var mv string + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + mv = xtv + } + uv = &types.XmlUnionShapeMemberStringValue{Value: mv} + memberFound = true + + case strings.EqualFold("structValue", t.Name.Local): + var mv types.XmlNestedUnionStruct + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + destAddr := &mv + if err := awsRestxml_deserializeDocumentXmlNestedUnionStruct(&destAddr, nodeDecoder); err != nil { + return err + } + mv = *destAddr + uv = &types.XmlUnionShapeMemberStructValue{Value: mv} + memberFound = true + + case strings.EqualFold("unionValue", t.Name.Local): + var mv types.XmlUnionShape + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + if err := awsRestxml_deserializeDocumentXmlUnionShape(&mv, nodeDecoder); err != nil { + return err + } + uv = &types.XmlUnionShapeMemberUnionValue{Value: mv} + memberFound = true + + default: + uv = &types.UnknownUnionMember{Tag: t.Name.Local} + memberFound = true + + } + decoder = originalDecoder + } + *v = uv + return nil +} + func awsRestxml_deserializeDocumentBooleanList(v *[]bool, decoder smithyxml.NodeDecoder) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) diff --git a/internal/protocoltest/restxml/go.mod b/internal/protocoltest/restxml/go.mod index 72f10983616..16667fa6c02 100644 --- a/internal/protocoltest/restxml/go.mod +++ b/internal/protocoltest/restxml/go.mod @@ -1,6 +1,6 @@ module github.com/aws/aws-sdk-go-v2/internal/protocoltest/restxml -go 1.15 +go 1.16 require ( github.com/aws/aws-sdk-go-v2 v1.2.0 diff --git a/internal/protocoltest/restxml/serializers.go b/internal/protocoltest/restxml/serializers.go index bb895c81715..b8d92b4ceaf 100644 --- a/internal/protocoltest/restxml/serializers.go +++ b/internal/protocoltest/restxml/serializers.go @@ -334,6 +334,198 @@ func awsRestxml_serializeOpHttpBindingsEmptyInputAndEmptyOutputInput(v *EmptyInp return nil } +type awsRestxml_serializeOpEndpointOperation struct { +} + +func (*awsRestxml_serializeOpEndpointOperation) ID() string { + return "OperationSerializer" +} + +func (m *awsRestxml_serializeOpEndpointOperation) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*EndpointOperationInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + opPath, opQuery := httpbinding.SplitURI("/EndpointOperation") + request.URL.Path = opPath + if len(request.URL.RawQuery) > 0 { + request.URL.RawQuery = "&" + opQuery + } else { + request.URL.RawQuery = opQuery + } + + request.Method = "POST" + restEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = restEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} +func awsRestxml_serializeOpHttpBindingsEndpointOperationInput(v *EndpointOperationInput, encoder *httpbinding.Encoder) error { + if v == nil { + return fmt.Errorf("unsupported serialization of nil %T", v) + } + + return nil +} + +type awsRestxml_serializeOpEndpointWithHostLabelHeaderOperation struct { +} + +func (*awsRestxml_serializeOpEndpointWithHostLabelHeaderOperation) ID() string { + return "OperationSerializer" +} + +func (m *awsRestxml_serializeOpEndpointWithHostLabelHeaderOperation) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*EndpointWithHostLabelHeaderOperationInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + opPath, opQuery := httpbinding.SplitURI("/EndpointWithHostLabelHeaderOperation") + request.URL.Path = opPath + if len(request.URL.RawQuery) > 0 { + request.URL.RawQuery = "&" + opQuery + } else { + request.URL.RawQuery = opQuery + } + + request.Method = "POST" + restEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if err := awsRestxml_serializeOpHttpBindingsEndpointWithHostLabelHeaderOperationInput(input, restEncoder); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = restEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} +func awsRestxml_serializeOpHttpBindingsEndpointWithHostLabelHeaderOperationInput(v *EndpointWithHostLabelHeaderOperationInput, encoder *httpbinding.Encoder) error { + if v == nil { + return fmt.Errorf("unsupported serialization of nil %T", v) + } + + if v.AccountId != nil && len(*v.AccountId) > 0 { + locationName := "X-Amz-Account-Id" + encoder.SetHeader(locationName).String(*v.AccountId) + } + + return nil +} + +type awsRestxml_serializeOpEndpointWithHostLabelOperation struct { +} + +func (*awsRestxml_serializeOpEndpointWithHostLabelOperation) ID() string { + return "OperationSerializer" +} + +func (m *awsRestxml_serializeOpEndpointWithHostLabelOperation) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + opPath, opQuery := httpbinding.SplitURI("/EndpointWithHostLabelOperation") + request.URL.Path = opPath + if len(request.URL.RawQuery) > 0 { + request.URL.RawQuery = "&" + opQuery + } else { + request.URL.RawQuery = opQuery + } + + request.Method = "POST" + restEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + restEncoder.SetHeader("Content-Type").String("application/xml") + + xmlEncoder := smithyxml.NewEncoder(bytes.NewBuffer(nil)) + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "HostLabelInput", + }, + Attr: rootAttr, + } + if err := awsRestxml_serializeOpDocumentEndpointWithHostLabelOperationInput(input, xmlEncoder.RootElement(root)); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + if request, err = request.SetStream(bytes.NewReader(xmlEncoder.Bytes())); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = restEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} +func awsRestxml_serializeOpHttpBindingsEndpointWithHostLabelOperationInput(v *EndpointWithHostLabelOperationInput, encoder *httpbinding.Encoder) error { + if v == nil { + return fmt.Errorf("unsupported serialization of nil %T", v) + } + + return nil +} + +func awsRestxml_serializeOpDocumentEndpointWithHostLabelOperationInput(v *EndpointWithHostLabelOperationInput, value smithyxml.Value) error { + defer value.Close() + if v.Label != nil { + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "label", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + el.String(*v.Label) + } + return nil +} + type awsRestxml_serializeOpFlattenedXmlMap struct { } @@ -3892,6 +4084,91 @@ func awsRestxml_serializeOpDocumentXmlTimestampsInput(v *XmlTimestampsInput, val return nil } +type awsRestxml_serializeOpXmlUnions struct { +} + +func (*awsRestxml_serializeOpXmlUnions) ID() string { + return "OperationSerializer" +} + +func (m *awsRestxml_serializeOpXmlUnions) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*XmlUnionsInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + opPath, opQuery := httpbinding.SplitURI("/XmlUnions") + request.URL.Path = opPath + if len(request.URL.RawQuery) > 0 { + request.URL.RawQuery = "&" + opQuery + } else { + request.URL.RawQuery = opQuery + } + + request.Method = "PUT" + restEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + restEncoder.SetHeader("Content-Type").String("application/xml") + + xmlEncoder := smithyxml.NewEncoder(bytes.NewBuffer(nil)) + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "XmlUnionsInputOutput", + }, + Attr: rootAttr, + } + if err := awsRestxml_serializeOpDocumentXmlUnionsInput(input, xmlEncoder.RootElement(root)); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + if request, err = request.SetStream(bytes.NewReader(xmlEncoder.Bytes())); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = restEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} +func awsRestxml_serializeOpHttpBindingsXmlUnionsInput(v *XmlUnionsInput, encoder *httpbinding.Encoder) error { + if v == nil { + return fmt.Errorf("unsupported serialization of nil %T", v) + } + + return nil +} + +func awsRestxml_serializeOpDocumentXmlUnionsInput(v *XmlUnionsInput, value smithyxml.Value) error { + defer value.Close() + if v.UnionValue != nil { + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "unionValue", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + if err := awsRestxml_serializeDocumentXmlUnionShape(v.UnionValue, el); err != nil { + return err + } + } + return nil +} + func awsRestxml_serializeDocumentFlattenedXmlMapWithXmlNameInputOutputMap(v map[string]string, value smithyxml.Value) error { if !value.IsFlattened() { defer value.Close() @@ -4286,6 +4563,223 @@ func awsRestxml_serializeDocumentXmlNamespaceNested(v *types.XmlNamespaceNested, return nil } +func awsRestxml_serializeDocumentXmlNestedUnionStruct(v *types.XmlNestedUnionStruct, value smithyxml.Value) error { + defer value.Close() + if v.BooleanValue != nil { + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "booleanValue", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + el.Boolean(*v.BooleanValue) + } + if v.ByteValue != nil { + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "byteValue", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + el.Byte(*v.ByteValue) + } + if v.DoubleValue != nil { + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "doubleValue", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + el.Double(*v.DoubleValue) + } + if v.FloatValue != nil { + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "floatValue", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + el.Float(*v.FloatValue) + } + if v.IntegerValue != nil { + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "integerValue", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + el.Integer(*v.IntegerValue) + } + if v.LongValue != nil { + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "longValue", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + el.Long(*v.LongValue) + } + if v.ShortValue != nil { + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "shortValue", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + el.Short(*v.ShortValue) + } + if v.StringValue != nil { + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "stringValue", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + el.String(*v.StringValue) + } + return nil +} + +func awsRestxml_serializeDocumentXmlUnionShape(v types.XmlUnionShape, value smithyxml.Value) error { + defer value.Close() + switch uv := v.(type) { + case *types.XmlUnionShapeMemberBooleanValue: + customMemberNameAttr := []smithyxml.Attr{} + customMemberName := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "booleanValue", + }, + Attr: customMemberNameAttr, + } + av := value.MemberElement(customMemberName) + av.Boolean(uv.Value) + + case *types.XmlUnionShapeMemberByteValue: + customMemberNameAttr := []smithyxml.Attr{} + customMemberName := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "byteValue", + }, + Attr: customMemberNameAttr, + } + av := value.MemberElement(customMemberName) + av.Byte(uv.Value) + + case *types.XmlUnionShapeMemberDoubleValue: + customMemberNameAttr := []smithyxml.Attr{} + customMemberName := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "doubleValue", + }, + Attr: customMemberNameAttr, + } + av := value.MemberElement(customMemberName) + av.Double(uv.Value) + + case *types.XmlUnionShapeMemberFloatValue: + customMemberNameAttr := []smithyxml.Attr{} + customMemberName := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "floatValue", + }, + Attr: customMemberNameAttr, + } + av := value.MemberElement(customMemberName) + av.Float(uv.Value) + + case *types.XmlUnionShapeMemberIntegerValue: + customMemberNameAttr := []smithyxml.Attr{} + customMemberName := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "integerValue", + }, + Attr: customMemberNameAttr, + } + av := value.MemberElement(customMemberName) + av.Integer(uv.Value) + + case *types.XmlUnionShapeMemberLongValue: + customMemberNameAttr := []smithyxml.Attr{} + customMemberName := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "longValue", + }, + Attr: customMemberNameAttr, + } + av := value.MemberElement(customMemberName) + av.Long(uv.Value) + + case *types.XmlUnionShapeMemberShortValue: + customMemberNameAttr := []smithyxml.Attr{} + customMemberName := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "shortValue", + }, + Attr: customMemberNameAttr, + } + av := value.MemberElement(customMemberName) + av.Short(uv.Value) + + case *types.XmlUnionShapeMemberStringValue: + customMemberNameAttr := []smithyxml.Attr{} + customMemberName := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "stringValue", + }, + Attr: customMemberNameAttr, + } + av := value.MemberElement(customMemberName) + av.String(uv.Value) + + case *types.XmlUnionShapeMemberStructValue: + customMemberNameAttr := []smithyxml.Attr{} + customMemberName := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "structValue", + }, + Attr: customMemberNameAttr, + } + av := value.MemberElement(customMemberName) + if err := awsRestxml_serializeDocumentXmlNestedUnionStruct(&uv.Value, av); err != nil { + return err + } + + case *types.XmlUnionShapeMemberUnionValue: + customMemberNameAttr := []smithyxml.Attr{} + customMemberName := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "unionValue", + }, + Attr: customMemberNameAttr, + } + av := value.MemberElement(customMemberName) + if err := awsRestxml_serializeDocumentXmlUnionShape(uv.Value, av); err != nil { + return err + } + + default: + return fmt.Errorf("attempted to serialize unknown member type %T for union %T", uv, v) + + } + return nil +} + func awsRestxml_serializeDocumentBooleanList(v []bool, value smithyxml.Value) error { var array *smithyxml.Array if !value.IsFlattened() { diff --git a/internal/protocoltest/restxml/types/types.go b/internal/protocoltest/restxml/types/types.go index c3a9371614c..d1380bcf049 100644 --- a/internal/protocoltest/restxml/types/types.go +++ b/internal/protocoltest/restxml/types/types.go @@ -54,6 +54,108 @@ type XmlNamespaceNested struct { Values []string } +type XmlNestedUnionStruct struct { + BooleanValue *bool + + ByteValue *int8 + + DoubleValue *float64 + + FloatValue *float32 + + IntegerValue *int32 + + LongValue *int64 + + ShortValue *int16 + + StringValue *string +} + +// The following types satisfy this interface: +// XmlUnionShapeMemberStringValue +// XmlUnionShapeMemberBooleanValue +// XmlUnionShapeMemberByteValue +// XmlUnionShapeMemberShortValue +// XmlUnionShapeMemberIntegerValue +// XmlUnionShapeMemberLongValue +// XmlUnionShapeMemberFloatValue +// XmlUnionShapeMemberDoubleValue +// XmlUnionShapeMemberUnionValue +// XmlUnionShapeMemberStructValue +type XmlUnionShape interface { + isXmlUnionShape() +} + +type XmlUnionShapeMemberStringValue struct { + Value string +} + +func (*XmlUnionShapeMemberStringValue) isXmlUnionShape() {} + +type XmlUnionShapeMemberBooleanValue struct { + Value bool +} + +func (*XmlUnionShapeMemberBooleanValue) isXmlUnionShape() {} + +type XmlUnionShapeMemberByteValue struct { + Value int8 +} + +func (*XmlUnionShapeMemberByteValue) isXmlUnionShape() {} + +type XmlUnionShapeMemberShortValue struct { + Value int16 +} + +func (*XmlUnionShapeMemberShortValue) isXmlUnionShape() {} + +type XmlUnionShapeMemberIntegerValue struct { + Value int32 +} + +func (*XmlUnionShapeMemberIntegerValue) isXmlUnionShape() {} + +type XmlUnionShapeMemberLongValue struct { + Value int64 +} + +func (*XmlUnionShapeMemberLongValue) isXmlUnionShape() {} + +type XmlUnionShapeMemberFloatValue struct { + Value float32 +} + +func (*XmlUnionShapeMemberFloatValue) isXmlUnionShape() {} + +type XmlUnionShapeMemberDoubleValue struct { + Value float64 +} + +func (*XmlUnionShapeMemberDoubleValue) isXmlUnionShape() {} + +type XmlUnionShapeMemberUnionValue struct { + Value XmlUnionShape +} + +func (*XmlUnionShapeMemberUnionValue) isXmlUnionShape() {} + +type XmlUnionShapeMemberStructValue struct { + Value XmlNestedUnionStruct +} + +func (*XmlUnionShapeMemberStructValue) isXmlUnionShape() {} + type GreetingStruct struct { Hi *string } + +// UnknownUnionMember is returned when a union member is returned over the wire, +// but has an unknown tag. +type UnknownUnionMember struct { + Tag string + Value []byte +} + +func (*UnknownUnionMember) isXmlUnionShape() {} diff --git a/internal/protocoltest/restxml/types/types_exported_test.go b/internal/protocoltest/restxml/types/types_exported_test.go new file mode 100644 index 00000000000..a697663cb06 --- /dev/null +++ b/internal/protocoltest/restxml/types/types_exported_test.go @@ -0,0 +1,62 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package types_test + +import ( + "fmt" + "github.com/aws/aws-sdk-go-v2/internal/protocoltest/restxml/types" +) + +func ExampleXmlUnionShape_outputUsage() { + var union types.XmlUnionShape + // type switches can be used to check the union value + switch v := union.(type) { + case *types.XmlUnionShapeMemberBooleanValue: + _ = v.Value // Value is bool + + case *types.XmlUnionShapeMemberByteValue: + _ = v.Value // Value is int8 + + case *types.XmlUnionShapeMemberDoubleValue: + _ = v.Value // Value is float64 + + case *types.XmlUnionShapeMemberFloatValue: + _ = v.Value // Value is float32 + + case *types.XmlUnionShapeMemberIntegerValue: + _ = v.Value // Value is int32 + + case *types.XmlUnionShapeMemberLongValue: + _ = v.Value // Value is int64 + + case *types.XmlUnionShapeMemberShortValue: + _ = v.Value // Value is int16 + + case *types.XmlUnionShapeMemberStringValue: + _ = v.Value // Value is string + + case *types.XmlUnionShapeMemberStructValue: + _ = v.Value // Value is types.XmlNestedUnionStruct + + case *types.XmlUnionShapeMemberUnionValue: + _ = v.Value // Value is types.XmlUnionShape + + case *types.UnknownUnionMember: + fmt.Println("unknown tag:", v.Tag) + + default: + fmt.Println("union is nil or unknown type") + + } +} + +var _ *string +var _ *int32 +var _ *bool +var _ *int64 +var _ *float64 +var _ *int16 +var _ *int8 +var _ *types.XmlNestedUnionStruct +var _ types.XmlUnionShape +var _ *float32 diff --git a/internal/protocoltest/restxml/validators.go b/internal/protocoltest/restxml/validators.go index aa10431214b..a4b005ab671 100644 --- a/internal/protocoltest/restxml/validators.go +++ b/internal/protocoltest/restxml/validators.go @@ -29,6 +29,46 @@ func (m *validateOpConstantQueryString) HandleInitialize(ctx context.Context, in return next.HandleInitialize(ctx, in) } +type validateOpEndpointWithHostLabelHeaderOperation struct { +} + +func (*validateOpEndpointWithHostLabelHeaderOperation) ID() string { + return "OperationInputValidation" +} + +func (m *validateOpEndpointWithHostLabelHeaderOperation) HandleInitialize(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) ( + out middleware.InitializeOutput, metadata middleware.Metadata, err error, +) { + input, ok := in.Parameters.(*EndpointWithHostLabelHeaderOperationInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input parameters type %T", in.Parameters) + } + if err := validateOpEndpointWithHostLabelHeaderOperationInput(input); err != nil { + return out, metadata, err + } + return next.HandleInitialize(ctx, in) +} + +type validateOpEndpointWithHostLabelOperation struct { +} + +func (*validateOpEndpointWithHostLabelOperation) ID() string { + return "OperationInputValidation" +} + +func (m *validateOpEndpointWithHostLabelOperation) HandleInitialize(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) ( + out middleware.InitializeOutput, metadata middleware.Metadata, err error, +) { + input, ok := in.Parameters.(*EndpointWithHostLabelOperationInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input parameters type %T", in.Parameters) + } + if err := validateOpEndpointWithHostLabelOperationInput(input); err != nil { + return out, metadata, err + } + return next.HandleInitialize(ctx, in) +} + type validateOpHttpRequestWithGreedyLabelInPath struct { } @@ -93,6 +133,14 @@ func addOpConstantQueryStringValidationMiddleware(stack *middleware.Stack) error return stack.Initialize.Add(&validateOpConstantQueryString{}, middleware.After) } +func addOpEndpointWithHostLabelHeaderOperationValidationMiddleware(stack *middleware.Stack) error { + return stack.Initialize.Add(&validateOpEndpointWithHostLabelHeaderOperation{}, middleware.After) +} + +func addOpEndpointWithHostLabelOperationValidationMiddleware(stack *middleware.Stack) error { + return stack.Initialize.Add(&validateOpEndpointWithHostLabelOperation{}, middleware.After) +} + func addOpHttpRequestWithGreedyLabelInPathValidationMiddleware(stack *middleware.Stack) error { return stack.Initialize.Add(&validateOpHttpRequestWithGreedyLabelInPath{}, middleware.After) } @@ -120,6 +168,36 @@ func validateOpConstantQueryStringInput(v *ConstantQueryStringInput) error { } } +func validateOpEndpointWithHostLabelHeaderOperationInput(v *EndpointWithHostLabelHeaderOperationInput) error { + if v == nil { + return nil + } + invalidParams := smithy.InvalidParamsError{Context: "EndpointWithHostLabelHeaderOperationInput"} + if v.AccountId == nil { + invalidParams.Add(smithy.NewErrParamRequired("AccountId")) + } + if invalidParams.Len() > 0 { + return invalidParams + } else { + return nil + } +} + +func validateOpEndpointWithHostLabelOperationInput(v *EndpointWithHostLabelOperationInput) error { + if v == nil { + return nil + } + invalidParams := smithy.InvalidParamsError{Context: "EndpointWithHostLabelOperationInput"} + if v.Label == nil { + invalidParams.Add(smithy.NewErrParamRequired("Label")) + } + if invalidParams.Len() > 0 { + return invalidParams + } else { + return nil + } +} + func validateOpHttpRequestWithGreedyLabelInPathInput(v *HttpRequestWithGreedyLabelInPathInput) error { if v == nil { return nil diff --git a/internal/protocoltest/restxmlwithnamespace/api_op_SimpleScalarProperties.go b/internal/protocoltest/restxmlwithnamespace/api_op_SimpleScalarProperties.go index e3e49899134..24ecf052705 100644 --- a/internal/protocoltest/restxmlwithnamespace/api_op_SimpleScalarProperties.go +++ b/internal/protocoltest/restxmlwithnamespace/api_op_SimpleScalarProperties.go @@ -5,6 +5,7 @@ package restxmlwithnamespace import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/aws-sdk-go-v2/internal/protocoltest/restxmlwithnamespace/types" "github.com/aws/smithy-go/middleware" smithyhttp "github.com/aws/smithy-go/transport/http" ) @@ -39,6 +40,8 @@ type SimpleScalarPropertiesInput struct { LongValue *int64 + Nested *types.NestedWithNamespace + ShortValue *int16 StringValue *string @@ -61,6 +64,8 @@ type SimpleScalarPropertiesOutput struct { LongValue *int64 + Nested *types.NestedWithNamespace + ShortValue *int16 StringValue *string diff --git a/internal/protocoltest/restxmlwithnamespace/api_op_SimpleScalarProperties_test.go b/internal/protocoltest/restxmlwithnamespace/api_op_SimpleScalarProperties_test.go index 5440dc1252e..11e9dc9e7d8 100644 --- a/internal/protocoltest/restxmlwithnamespace/api_op_SimpleScalarProperties_test.go +++ b/internal/protocoltest/restxmlwithnamespace/api_op_SimpleScalarProperties_test.go @@ -7,6 +7,7 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/aws" awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/aws-sdk-go-v2/internal/protocoltest/restxmlwithnamespace/types" "github.com/aws/smithy-go/middleware" "github.com/aws/smithy-go/ptr" smithytesting "github.com/aws/smithy-go/testing" @@ -49,6 +50,9 @@ func TestClient_SimpleScalarProperties_awsRestxmlSerialize(t *testing.T) { LongValue: ptr.Int64(4), FloatValue: ptr.Float32(5.5), DoubleValue: ptr.Float64(6.5), + Nested: &types.NestedWithNamespace{ + AttrField: ptr.String("nestedAttrValue"), + }, }, ExpectMethod: "PUT", ExpectURIPath: "/SimpleScalarProperties", @@ -69,6 +73,7 @@ func TestClient_SimpleScalarProperties_awsRestxmlSerialize(t *testing.T) { 4 5.5 6.5 + `)) }, @@ -165,6 +170,7 @@ func TestClient_SimpleScalarProperties_awsRestxmlDeserialize(t *testing.T) { 4 5.5 6.5 + `), ExpectResult: &SimpleScalarPropertiesOutput{ @@ -178,6 +184,9 @@ func TestClient_SimpleScalarProperties_awsRestxmlDeserialize(t *testing.T) { LongValue: ptr.Int64(4), FloatValue: ptr.Float32(5.5), DoubleValue: ptr.Float64(6.5), + Nested: &types.NestedWithNamespace{ + AttrField: ptr.String("nestedAttrValue"), + }, }, }, } diff --git a/internal/protocoltest/restxmlwithnamespace/deserializers.go b/internal/protocoltest/restxmlwithnamespace/deserializers.go index a6394da856e..d32088017d8 100644 --- a/internal/protocoltest/restxmlwithnamespace/deserializers.go +++ b/internal/protocoltest/restxmlwithnamespace/deserializers.go @@ -9,6 +9,7 @@ import ( "fmt" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" awsxml "github.com/aws/aws-sdk-go-v2/aws/protocol/xml" + "github.com/aws/aws-sdk-go-v2/internal/protocoltest/restxmlwithnamespace/types" smithy "github.com/aws/smithy-go" smithyxml "github.com/aws/smithy-go/encoding/xml" smithyio "github.com/aws/smithy-go/io" @@ -252,6 +253,12 @@ func awsRestxml_deserializeOpDocumentSimpleScalarPropertiesOutput(v **SimpleScal sv.LongValue = ptr.Int64(i64) } + case strings.EqualFold("Nested", t.Name.Local): + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + if err := awsRestxml_deserializeDocumentNestedWithNamespace(&sv.Nested, nodeDecoder); err != nil { + return err + } + case strings.EqualFold("shortValue", t.Name.Local): val, err := decoder.Value() if err != nil { @@ -311,3 +318,54 @@ func awsRestxml_deserializeOpDocumentSimpleScalarPropertiesOutput(v **SimpleScal *v = sv return nil } + +func awsRestxml_deserializeDocumentNestedWithNamespace(v **types.NestedWithNamespace, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var sv *types.NestedWithNamespace + if *v == nil { + sv = &types.NestedWithNamespace{} + } else { + sv = *v + } + + for _, attr := range decoder.StartEl.Attr { + name := attr.Name.Local + if len(attr.Name.Space) != 0 { + name = attr.Name.Space + `:` + attr.Name.Local + } + switch { + case strings.EqualFold("xsi:someName", name): + val := []byte(attr.Value) + { + xtv := string(val) + sv.AttrField = ptr.String(xtv) + } + + } + } + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + originalDecoder := decoder + decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) + switch { + default: + // Do nothing and ignore the unexpected tag element + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + decoder = originalDecoder + } + *v = sv + return nil +} diff --git a/internal/protocoltest/restxmlwithnamespace/go.mod b/internal/protocoltest/restxmlwithnamespace/go.mod index 51d7f5e0bd1..b40538f7cd8 100644 --- a/internal/protocoltest/restxmlwithnamespace/go.mod +++ b/internal/protocoltest/restxmlwithnamespace/go.mod @@ -1,6 +1,6 @@ module github.com/aws/aws-sdk-go-v2/internal/protocoltest/restxmlwithnamespace -go 1.15 +go 1.16 require ( github.com/aws/aws-sdk-go-v2 v1.2.0 diff --git a/internal/protocoltest/restxmlwithnamespace/serializers.go b/internal/protocoltest/restxmlwithnamespace/serializers.go index d1f6270019d..ca48f0b5b09 100644 --- a/internal/protocoltest/restxmlwithnamespace/serializers.go +++ b/internal/protocoltest/restxmlwithnamespace/serializers.go @@ -6,6 +6,7 @@ import ( "bytes" "context" "fmt" + "github.com/aws/aws-sdk-go-v2/internal/protocoltest/restxmlwithnamespace/types" smithy "github.com/aws/smithy-go" "github.com/aws/smithy-go/encoding/httpbinding" smithyxml "github.com/aws/smithy-go/encoding/xml" @@ -158,6 +159,20 @@ func awsRestxml_serializeOpDocumentSimpleScalarPropertiesInput(v *SimpleScalarPr el := value.MemberElement(root) el.Long(*v.LongValue) } + if v.Nested != nil { + rootAttr := []smithyxml.Attr{} + rootAttr = append(rootAttr, smithyxml.NewNamespaceAttribute("xsi", "https://example.com")) + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "Nested", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + if err := awsRestxml_serializeDocumentNestedWithNamespace(v.Nested, el); err != nil { + return err + } + } if v.ShortValue != nil { rootAttr := []smithyxml.Attr{} root := smithyxml.StartElement{ @@ -193,3 +208,8 @@ func awsRestxml_serializeOpDocumentSimpleScalarPropertiesInput(v *SimpleScalarPr } return nil } + +func awsRestxml_serializeDocumentNestedWithNamespace(v *types.NestedWithNamespace, value smithyxml.Value) error { + defer value.Close() + return nil +} diff --git a/internal/protocoltest/restxmlwithnamespace/types/types.go b/internal/protocoltest/restxmlwithnamespace/types/types.go new file mode 100644 index 00000000000..7da29c7e0bc --- /dev/null +++ b/internal/protocoltest/restxmlwithnamespace/types/types.go @@ -0,0 +1,7 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package types + +type NestedWithNamespace struct { + AttrField *string +}