From 2e9cf00651268e239698d683baca82af4bf36485 Mon Sep 17 00:00:00 2001 From: david-perez Date: Fri, 7 Jun 2024 16:12:28 +0200 Subject: [PATCH 1/3] Add protocol tests relating to `Content-Type` and `@httpPayload` Initial motivation for this stems off #2310, but for when the input is `@httpPayload`-bound. It's important that we test `Content-Type` specifically with `@httpPayload` operations, because the header can be checked without having to inspect the body, and because the spec has special provisions (https://smithy.io/2.0/aws/protocols/aws-restjson1-protocol.html#content-type). There were no protocol tests exercising `Content-Type` when the input is `@httpPayload`-bound: - In the case of blobs, servers must accept any (test already exists) and no `Content-Type` (test added in this commit). - In other cases, there were protocol tests for `union` and `structure` shapes. I've added an operation with an `@httpPayload`-bound string shape. Note that `document` shapes remain untested. --- .../model/restJson1/http-payload.smithy | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/smithy-aws-protocol-tests/model/restJson1/http-payload.smithy b/smithy-aws-protocol-tests/model/restJson1/http-payload.smithy index d2acdae8fb7..14d1e19c7fd 100644 --- a/smithy-aws-protocol-tests/model/restJson1/http-payload.smithy +++ b/smithy-aws-protocol-tests/model/restJson1/http-payload.smithy @@ -6,6 +6,7 @@ $version: "2.0" namespace aws.protocoltests.restjson use aws.protocols#restJson1 +use smithy.test#httpMalformedRequestTests use aws.protocoltests.shared#TextPlainBlob use smithy.test#httpRequestTests use smithy.test#httpResponseTests @@ -76,6 +77,26 @@ apply HttpPayloadTraits @httpRequestTests([ }, appliesTo: "server", }, + { + id: "RestJsonHttpPayloadTraitsWithBlobAcceptsNoContentType", + documentation: """ + Servers must accept no content type for blob inputs + without the media type trait.""", + protocol: restJson1, + method: "POST", + uri: "/HttpPayloadTraits", + body: "This is definitely a jpeg", + bodyMediaType: "application/octet-stream", + headers: { + "X-Foo": "Foo", + }, + params: { + foo: "Foo", + blob: "This is definitely a jpeg" + }, + appliesTo: "server", + tags: [ "content-type" ] + }, { id: "RestJsonHttpPayloadTraitsWithBlobAcceptsAllAccepts", documentation: """ @@ -353,3 +374,120 @@ structure HttpPayloadWithUnionInputOutput { union UnionPayload { greeting: String } + +/// This example serializes a string shape in the payload. +/// +/// In this example, no JSON document is synthesized because the payload is +/// not a structure or a union type. +@http(uri: "/HttpPayloadTraitOnString", method: "POST") +operation HttpPayloadTraitOnString { + input: HttpPayloadTraitOnStringInputOutput, + output: HttpPayloadTraitOnStringInputOutput +} + +structure HttpPayloadTraitOnStringInputOutput { + @httpPayload + foo: String, +} + +apply HttpPayloadTraitOnString @httpRequestTests([ + { + id: "RestJsonHttpPayloadTraitOnString", + documentation: "Serializes a string in the HTTP payload", + protocol: restJson1, + method: "POST", + uri: "/HttpPayloadTraitOnString", + body: "Foo", + bodyMediaType: "text/plain", + headers: { + "Content-Type": "text/plain", + }, + requireHeaders: [ + "Content-Length" + ], + params: { + foo: "Foo", + } + }, +]) + +apply HttpPayloadTraitOnString @httpResponseTests([ + { + id: "RestJsonHttpPayloadTraitOnString", + documentation: "Serializes a string in the HTTP payload", + protocol: restJson1, + code: 200, + body: "Foo", + bodyMediaType: "text/plain", + headers: { + "Content-Type": "text/plain", + }, + params: { + foo: "Foo", + } + }, +]) + +apply HttpPayloadTraitOnString @httpMalformedRequestTests([ + { + id: "RestJsonHttpPayloadTraitOnStringNoContentType", + documentation: "Serializes a string in the HTTP payload without a content-type header", + protocol: restJson1, + request: { + method: "POST", + uri: "/HttpPayloadTraitOnString", + body: "Foo", + // We expect a `Content-Type` header but none was provided. + }, + response: { + code: 415, + headers: { + "x-amzn-errortype": "UnsupportedMediaTypeException" + } + }, + tags: [ "content-type" ] + }, + { + id: "RestJsonHttpPayloadTraitOnStringWrongContentType", + documentation: "Serializes a string in the HTTP payload without the expected content-type header", + protocol: restJson1, + request: { + method: "POST", + uri: "/HttpPayloadTraitOnString", + body: "Foo", + headers: { + // We expect `text/plain`. + "Content-Type": "application/json", + }, + }, + response: { + code: 415, + headers: { + "x-amzn-errortype": "UnsupportedMediaTypeException" + } + }, + tags: [ "content-type" ] + }, + { + id: "RestJsonHttpPayloadTraitOnStringUnsatisfiableAccept", + documentation: "Serializes a string in the HTTP payload with an unstatisfiable accept header", + protocol: restJson1, + request: { + method: "POST", + uri: "/HttpPayloadTraitOnString", + body: "Foo", + headers: { + "Content-Type": "text/plain", + // We can't satisfy this requirement; the server will return `text/plain`. + "Accept": "application/json", + }, + }, + response: { + code: 406, + headers: { + "x-amzn-errortype": "NotAcceptableException" + } + }, + tags: [ "accept" ] + }, +]) From 423262a739ac2f2d72e2109bd016bc07e1ec1e64 Mon Sep 17 00:00:00 2001 From: david-perez Date: Tue, 11 Jun 2024 17:08:01 +0200 Subject: [PATCH 2/3] Add missing `Content-Type` headers to @httpPayload protocol tests As per the specs for these protocols, a `Content-Type` header should be set. Server should reject requests when an expected `Content-Type` header is not found (protcol tests for that are added in #2314). - https://smithy.io/2.0/aws/protocols/aws-restjson1-protocol.html#content-type - https://smithy.io/2.0/aws/protocols/aws-restxml-protocol.html#content-type --- .../model/restJson1/http-string-payload.smithy | 4 ++++ .../model/restXml/http-string-payload.smithy | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/smithy-aws-protocol-tests/model/restJson1/http-string-payload.smithy b/smithy-aws-protocol-tests/model/restJson1/http-string-payload.smithy index 8aa1f517b43..52cab5cc99f 100644 --- a/smithy-aws-protocol-tests/model/restJson1/http-string-payload.smithy +++ b/smithy-aws-protocol-tests/model/restJson1/http-string-payload.smithy @@ -10,6 +10,7 @@ use smithy.test#httpResponseTests { id: "RestJsonEnumPayloadRequest", uri: "/EnumPayload", + headers: { "Content-Type": "text/plain" }, body: "enumvalue", params: { payload: "enumvalue" }, method: "POST", @@ -19,6 +20,7 @@ use smithy.test#httpResponseTests @httpResponseTests([ { id: "RestJsonEnumPayloadResponse", + headers: { "Content-Type": "text/plain" }, body: "enumvalue", params: { payload: "enumvalue" }, protocol: "aws.protocols#restJson1", @@ -44,6 +46,7 @@ enum StringEnum { { id: "RestJsonStringPayloadRequest", uri: "/StringPayload", + headers: { "Content-Type": "text/plain" }, body: "rawstring", params: { payload: "rawstring" }, method: "POST", @@ -53,6 +56,7 @@ enum StringEnum { @httpResponseTests([ { id: "RestJsonStringPayloadResponse", + headers: { "Content-Type": "text/plain" }, body: "rawstring", params: { payload: "rawstring" }, protocol: "aws.protocols#restJson1", diff --git a/smithy-aws-protocol-tests/model/restXml/http-string-payload.smithy b/smithy-aws-protocol-tests/model/restXml/http-string-payload.smithy index 851e34066e3..9b25b3af094 100644 --- a/smithy-aws-protocol-tests/model/restXml/http-string-payload.smithy +++ b/smithy-aws-protocol-tests/model/restXml/http-string-payload.smithy @@ -10,6 +10,7 @@ use smithy.test#httpResponseTests { id: "RestXmlEnumPayloadRequest", uri: "/EnumPayload", + headers: { "Content-Type": "text/plain" }, body: "enumvalue", params: { payload: "enumvalue" }, method: "POST", @@ -19,6 +20,7 @@ use smithy.test#httpResponseTests @httpResponseTests([ { id: "RestXmlEnumPayloadResponse", + headers: { "Content-Type": "text/plain" }, body: "enumvalue", params: { payload: "enumvalue" }, protocol: "aws.protocols#restXml", @@ -44,6 +46,7 @@ enum StringEnum { { id: "RestXmlStringPayloadRequest", uri: "/StringPayload", + headers: { "Content-Type": "text/plain" }, body: "rawstring", params: { payload: "rawstring" }, method: "POST", @@ -53,6 +56,7 @@ enum StringEnum { @httpResponseTests([ { id: "RestXmlStringPayloadResponse", + headers: { "Content-Type": "text/plain" }, body: "rawstring", params: { payload: "rawstring" }, protocol: "aws.protocols#restXml", From bb492a6d16238f8f859b9a61ae2321dcc064787f Mon Sep 17 00:00:00 2001 From: david-perez Date: Fri, 14 Jun 2024 01:01:54 +0200 Subject: [PATCH 3/3] Add operation to service --- smithy-aws-protocol-tests/model/restJson1/main.smithy | 1 + 1 file changed, 1 insertion(+) diff --git a/smithy-aws-protocol-tests/model/restJson1/main.smithy b/smithy-aws-protocol-tests/model/restJson1/main.smithy index 2a414502b46..5e517195158 100644 --- a/smithy-aws-protocol-tests/model/restJson1/main.smithy +++ b/smithy-aws-protocol-tests/model/restJson1/main.smithy @@ -62,6 +62,7 @@ service RestJson { HttpEnumPayload, HttpStringPayload, HttpPayloadWithUnion, + HttpPayloadTraitOnString, // @httpResponseCode tests HttpResponseCode,