Skip to content

Commit a511008

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 a511008

File tree

9 files changed

+752
-863
lines changed

9 files changed

+752
-863
lines changed

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

Lines changed: 110 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,61 @@ 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 non-empty string, no other
1026+
:ref:`httpHeader-trait` bindings can start with the same prefix provided in
1027+
``httpPrefixHeaders`` trait.
1028+
1029+
If ``httpPrefixHeaders`` is set to an empty string, then other members can be
1030+
bound to ``headers``. However, this can lead to ambiguity on the source of
1031+
provided header values.
9861032

9871033
.. note::
9881034

@@ -1134,7 +1180,7 @@ target input map as query string parameters in an HTTP request:
11341180
11351181
@input
11361182
structure ListThingsInput {
1137-
@httpQueryParams()
1183+
@httpQueryParams
11381184
myParams: MapOfStrings
11391185
}
11401186
@@ -1143,6 +1189,50 @@ target input map as query string parameters in an HTTP request:
11431189
value: String
11441190
}
11451191
1192+
1193+
Given the following Smithy model that also uses the ``httpQuery`` trait:
1194+
1195+
.. code-block:: smithy
1196+
1197+
@readonly
1198+
@http(method: "GET", uri: "/myOperation")
1199+
operation MyOperation {
1200+
input: MyOperationInput
1201+
}
1202+
1203+
@input
1204+
structure MyOperationInput {
1205+
@httpQueryParams
1206+
query: MapOfStrings
1207+
1208+
@httpQuery
1209+
foo: String
1210+
}
1211+
1212+
map MapOfStrings {
1213+
key: String
1214+
value: String
1215+
}
1216+
1217+
And given the following input to ``MyOperation``:
1218+
1219+
.. code-block:: json
1220+
1221+
{
1222+
"query": {
1223+
"foo": "not sent"
1224+
}
1225+
"foo": "resolved"
1226+
}
1227+
1228+
An example HTTP request would be serialized as:
1229+
1230+
::
1231+
1232+
GET /myOperation?foo=resolved
1233+
Host: <server>
1234+
1235+
11461236
Serialization rules
11471237
-------------------
11481238

@@ -1378,6 +1468,7 @@ See
13781468
output: PutSomethingOutput
13791469
}
13801470
1471+
.. _serializing-http-messages:
13811472

13821473
Serializing HTTP messages
13831474
=========================
@@ -1393,14 +1484,14 @@ parameters:
13931484
corresponding structure member by name:
13941485

13951486
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
1487+
2. If the member has the ``httpQueryParams`` trait, serialize the values into
13991488
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,
1489+
3. If the member has the ``httpQuery`` trait, serialize the value into the
1490+
HTTP request as a query string parameter.
1491+
4. If the member has the ``httpPrefixHeaders`` trait and the value is a map,
14031492
serialize the map key value pairs as prefixed HTTP headers.
1493+
5. If the member has the ``httpHeader`` trait, serialize the value in an
1494+
HTTP header using the value of the ``httpHeader`` trait.
14041495
6. If the member has the ``httpPayload`` trait, serialize the value as the
14051496
body of the request.
14061497
7. If the member has no bindings, serialize the key-value pair as part of a
@@ -1418,10 +1509,10 @@ parameters:
14181509
3. Iterate over all of the key-value pairs of the parameters and find the
14191510
corresponding structure member by name:
14201511

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,
1512+
1. If the member has the ``httpPrefixHeaders`` trait and the value is a map,
14241513
serialize the map key value pairs as prefixed HTTP headers.
1514+
2. If the member has the ``httpHeader`` trait, serialize the value in an
1515+
HTTP header using the value of the ``httpHeader`` trait.
14251516
3. If the member has the ``httpPayload`` trait, serialize the value as the
14261517
body of the response.
14271518
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)