Skip to content

Commit 7eb81a5

Browse files
committed
Relax httpPrefixHeaders constraint
This commit relaxes the constraint on the `@httpPrefixHeaders` trait when the prefix is set to an empty string, lowering the validation's severity to a NOTE. This case is usualy meant for proxying all headers through a request or response, where conflicts are well understood. This change comes with updated guidance to simplify the strategy for serializing HTTP messages, examples for these use cases, guidance on how to do this in a readable way, and other minor HTTP binding specification cleanup.
1 parent 84d3ccb commit 7eb81a5

File tree

9 files changed

+749
-863
lines changed

9 files changed

+749
-863
lines changed

docs/source-2.0/spec/http-bindings.rst

Lines changed: 107 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -643,8 +643,8 @@ Conflicts with
643643
:ref:`httpPayload-trait`,
644644
:ref:`httpResponseCode-trait`
645645

646-
``httpHeader`` serialization rules:
647-
-----------------------------------
646+
Serialization rules
647+
-------------------
648648

649649
* When a :ref:`list <list>` shape is targeted, each member of the shape is
650650
serialized as a separate HTTP header either by concatenating the values
@@ -792,8 +792,8 @@ Applying the ``httpLabel`` trait to members
792792
* If the corresponding URI label in the operation is greedy, then the
793793
``httpLabel`` trait MUST target a member that targets a ``string`` shape.
794794

795-
``httpLabel`` serialization rules
796-
---------------------------------
795+
Serialization rules
796+
-------------------
797797

798798
- ``boolean`` values are serialized as ``true`` or ``false``.
799799
- ``timestamp`` values are serialized as an :rfc:`3339` string by default
@@ -935,7 +935,6 @@ Structurally exclusive
935935

936936
Given the following Smithy model:
937937

938-
939938
.. code-block:: smithy
940939
941940
@readonly
@@ -975,14 +974,58 @@ An example HTTP request would be serialized as:
975974
X-Foo-first: hi
976975
X-Foo-second: there
977976

977+
Given the following Smithy model that also uses the ``httpHeader`` trait:
978+
979+
.. code-block:: smithy
980+
981+
@readonly
982+
@http(method: "GET", uri: "/myOperation")
983+
operation MyOperation {
984+
input: MyOperationInput
985+
}
986+
987+
@input
988+
structure MyOperationInput {
989+
@httpPrefixHeaders("X-Foo-")
990+
headers: MapOfStrings
991+
992+
@httpHeader("X-Foo-Value")
993+
foo: String
994+
}
995+
996+
map MapOfStrings {
997+
key: String
998+
value: String
999+
}
1000+
1001+
And given the following input to ``MyOperation``:
1002+
1003+
.. code-block:: json
1004+
1005+
{
1006+
"headers": {
1007+
"Value": "not sent"
1008+
}
1009+
"foo": "resolved"
1010+
}
1011+
1012+
An example HTTP request would be serialized as:
1013+
1014+
::
1015+
1016+
GET /myOperation
1017+
Host: <server>
1018+
X-Foo-Value: resolved
1019+
1020+
9781021
Disambiguation of ``httpPrefixHeaders``
9791022
---------------------------------------
9801023

9811024
In order to differentiate ``httpPrefixHeaders`` from other headers, when
982-
``httpPrefixHeaders`` are used, no other :ref:`httpHeader-trait` bindings can
983-
start with the same prefix provided in ``httpPrefixHeaders`` trait. If
984-
``httpPrefixHeaders`` is set to an empty string, then no other members can be
985-
bound to ``headers``.
1025+
``httpPrefixHeaders`` are used with a defined prefix, no other
1026+
:ref:`httpHeader-trait` bindings can start with the same prefix provided in
1027+
``httpPrefixHeaders`` trait. If ``httpPrefixHeaders`` is set to an empty
1028+
string, then other members can be bound to ``headers``.
9861029

9871030
.. note::
9881031

@@ -1134,7 +1177,7 @@ target input map as query string parameters in an HTTP request:
11341177
11351178
@input
11361179
structure ListThingsInput {
1137-
@httpQueryParams()
1180+
@httpQueryParams
11381181
myParams: MapOfStrings
11391182
}
11401183
@@ -1143,6 +1186,50 @@ target input map as query string parameters in an HTTP request:
11431186
value: String
11441187
}
11451188
1189+
1190+
Given the following Smithy model that also uses the ``httpQuery`` trait:
1191+
1192+
.. code-block:: smithy
1193+
1194+
@readonly
1195+
@http(method: "GET", uri: "/myOperation")
1196+
operation MyOperation {
1197+
input: MyOperationInput
1198+
}
1199+
1200+
@input
1201+
structure MyOperationInput {
1202+
@httpQueryParams
1203+
query: MapOfStrings
1204+
1205+
@httpQuery
1206+
foo: String
1207+
}
1208+
1209+
map MapOfStrings {
1210+
key: String
1211+
value: String
1212+
}
1213+
1214+
And given the following input to ``MyOperation``:
1215+
1216+
.. code-block:: json
1217+
1218+
{
1219+
"query": {
1220+
"foo": "not sent"
1221+
}
1222+
"foo": "resolved"
1223+
}
1224+
1225+
An example HTTP request would be serialized as:
1226+
1227+
::
1228+
1229+
GET /myOperation?foo=resolved
1230+
Host: <server>
1231+
1232+
11461233
Serialization rules
11471234
-------------------
11481235

@@ -1378,6 +1465,7 @@ See
13781465
output: PutSomethingOutput
13791466
}
13801467
1468+
.. _serializing-http-messages:
13811469

13821470
Serializing HTTP messages
13831471
=========================
@@ -1393,14 +1481,14 @@ parameters:
13931481
corresponding structure member by name:
13941482

13951483
1. If the member has the ``httpLabel`` trait, expand the value into the URI.
1396-
2. If the member has the ``httpQuery`` trait, serialize the value into the
1397-
HTTP request as a query string parameter.
1398-
3. If the member has the ``httpQueryParams`` trait, serialize the values into
1484+
2. If the member has the ``httpQueryParams`` trait, serialize the values into
13991485
the HTTP request as query string parameters.
1400-
4. If the member has the ``httpHeader`` trait, serialize the value in an
1401-
HTTP header using the value of the ``httpHeader`` trait.
1402-
5. If the member has the ``httpPrefixHeaders`` trait and the value is a map,
1486+
3. If the member has the ``httpQuery`` trait, serialize the value into the
1487+
HTTP request as a query string parameter.
1488+
4. If the member has the ``httpPrefixHeaders`` trait and the value is a map,
14031489
serialize the map key value pairs as prefixed HTTP headers.
1490+
5. If the member has the ``httpHeader`` trait, serialize the value in an
1491+
HTTP header using the value of the ``httpHeader`` trait.
14041492
6. If the member has the ``httpPayload`` trait, serialize the value as the
14051493
body of the request.
14061494
7. If the member has no bindings, serialize the key-value pair as part of a
@@ -1418,10 +1506,10 @@ parameters:
14181506
3. Iterate over all of the key-value pairs of the parameters and find the
14191507
corresponding structure member by name:
14201508

1421-
1. If the member has the ``httpHeader`` trait, serialize the value in an
1422-
HTTP header using the value of the ``httpHeader`` trait.
1423-
2. If the member has the ``httpPrefixHeaders`` trait and the value is a map,
1509+
1. If the member has the ``httpPrefixHeaders`` trait and the value is a map,
14241510
serialize the map key value pairs as prefixed HTTP headers.
1511+
2. If the member has the ``httpHeader`` trait, serialize the value in an
1512+
HTTP header using the value of the ``httpHeader`` trait.
14251513
3. If the member has the ``httpPayload`` trait, serialize the value as the
14261514
body of the response.
14271515
4. If the member has no bindings, serialize the key-value pair as part of a

smithy-aws-protocol-tests/model/restJson1/http-prefix-headers.smithy

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,105 @@ structure HttpPrefixHeadersInResponseOutput {
149149
@httpPrefixHeaders("")
150150
prefixHeaders: StringMap,
151151
}
152+
153+
/// Clients that perform this test extract all headers from the response.
154+
@readonly
155+
@http(uri: "/HttpEmptyPrefixHeaders", method: "GET")
156+
operation HttpEmptyPrefixHeaders {
157+
input := {
158+
@httpPrefixHeaders("")
159+
prefixHeaders: StringMap
160+
161+
@httpHeader("hello")
162+
specificHeader: String
163+
}
164+
output := {
165+
@httpPrefixHeaders("")
166+
prefixHeaders: StringMap
167+
168+
@httpHeader("hello")
169+
specificHeader: String
170+
}
171+
}
172+
173+
apply HttpEmptyPrefixHeaders @httpRequestTests([
174+
{
175+
id: "RestJsonHttpEmptyPrefixHeadersRequestClient"
176+
documentation: "Serializes all request headers, using specific when present"
177+
protocol: restJson1
178+
method: "GET"
179+
uri: "/HttpEmptyPrefixHeaders"
180+
body: ""
181+
headers: {
182+
"x-foo": "Foo",
183+
"hello": "There"
184+
}
185+
params: {
186+
prefixHeaders: {
187+
"x-foo": "Foo",
188+
"hello": "Hello"
189+
}
190+
specificHeader: "There"
191+
}
192+
appliesTo: "client"
193+
}
194+
{
195+
id: "RestJsonHttpEmptyPrefixHeadersRequestServer"
196+
documentation: "Deserializes all request headers with the same for prefix and specific"
197+
protocol: restJson1
198+
method: "GET"
199+
uri: "/HttpEmptyPrefixHeaders"
200+
body: ""
201+
headers: {
202+
"x-foo": "Foo",
203+
"hello": "There"
204+
}
205+
params: {
206+
prefixHeaders: {
207+
"x-foo": "Foo",
208+
"hello": "There"
209+
}
210+
specificHeader: "There"
211+
}
212+
appliesTo: "server"
213+
}
214+
])
215+
216+
apply HttpEmptyPrefixHeaders @httpResponseTests([
217+
{
218+
id: "RestJsonHttpEmptyPrefixHeadersResponseClient"
219+
documentation: "Deserializes all response headers with the same for prefix and specific"
220+
protocol: restJson1
221+
code: 200
222+
headers: {
223+
"x-foo": "Foo",
224+
"hello": "There"
225+
}
226+
params: {
227+
prefixHeaders: {
228+
"x-foo": "Foo",
229+
"hello": "There"
230+
}
231+
specificHeader: "There"
232+
}
233+
appliesTo: "client"
234+
}
235+
{
236+
id: "RestJsonHttpEmptyPrefixHeadersResponseServer"
237+
documentation: "Serializes all response headers, using specific when present"
238+
protocol: restJson1
239+
code: 200
240+
headers: {
241+
"x-foo": "Foo",
242+
"hello": "There"
243+
}
244+
params: {
245+
prefixHeaders: {
246+
"x-foo": "Foo",
247+
"hello": "Hello"
248+
}
249+
specificHeader: "There"
250+
}
251+
appliesTo: "server"
252+
}
253+
])

smithy-aws-protocol-tests/model/restJson1/main.smithy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ service RestJson {
5454
// @httpPrefixHeaders tests
5555
HttpPrefixHeaders,
5656
HttpPrefixHeadersInResponse,
57+
HttpEmptyPrefixHeaders,
5758

5859
// @httpPayload tests
5960
HttpPayloadTraits,

0 commit comments

Comments
 (0)