Skip to content

Relax httpPrefixHeaders constraint #2565

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 110 additions & 19 deletions docs/source-2.0/spec/http-bindings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -643,8 +643,8 @@ Conflicts with
:ref:`httpPayload-trait`,
:ref:`httpResponseCode-trait`

``httpHeader`` serialization rules:
-----------------------------------
Serialization rules
-------------------

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

``httpLabel`` serialization rules
---------------------------------
Serialization rules
-------------------

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

Given the following Smithy model:


.. code-block:: smithy
@readonly
Expand Down Expand Up @@ -975,14 +974,61 @@ An example HTTP request would be serialized as:
X-Foo-first: hi
X-Foo-second: there

Given the following Smithy model that also uses the ``httpHeader`` trait:

.. code-block:: smithy
@readonly
@http(method: "GET", uri: "/myOperation")
operation MyOperation {
input: MyOperationInput
}
@input
structure MyOperationInput {
@httpPrefixHeaders("X-Foo-")
headers: MapOfStrings
@httpHeader("X-Foo-Value")
foo: String
}
map MapOfStrings {
key: String
value: String
}
And given the following input to ``MyOperation``:

.. code-block:: json
{
"headers": {
"Value": "not sent"
}
"foo": "resolved"
}
An example HTTP request would be serialized as:

::

GET /myOperation
Host: <server>
X-Foo-Value: resolved


Disambiguation of ``httpPrefixHeaders``
---------------------------------------

In order to differentiate ``httpPrefixHeaders`` from other headers, when
``httpPrefixHeaders`` are used, no other :ref:`httpHeader-trait` bindings can
start with the same prefix provided in ``httpPrefixHeaders`` trait. If
``httpPrefixHeaders`` is set to an empty string, then no other members can be
bound to ``headers``.
``httpPrefixHeaders`` are used with a non-empty string, no other
:ref:`httpHeader-trait` bindings can start with the same prefix provided in
``httpPrefixHeaders`` trait.

If ``httpPrefixHeaders`` is set to an empty string, then other members can be
bound to ``headers``. However, this can lead to ambiguity on the source of
provided header values.

.. note::

Expand Down Expand Up @@ -1134,7 +1180,7 @@ target input map as query string parameters in an HTTP request:
@input
structure ListThingsInput {
@httpQueryParams()
@httpQueryParams
myParams: MapOfStrings
}
Expand All @@ -1143,6 +1189,50 @@ target input map as query string parameters in an HTTP request:
value: String
}
Given the following Smithy model that also uses the ``httpQuery`` trait:

.. code-block:: smithy
@readonly
@http(method: "GET", uri: "/myOperation")
operation MyOperation {
input: MyOperationInput
}
@input
structure MyOperationInput {
@httpQueryParams
query: MapOfStrings
@httpQuery
foo: String
}
map MapOfStrings {
key: String
value: String
}
And given the following input to ``MyOperation``:

.. code-block:: json
{
"query": {
"foo": "not sent"
}
"foo": "resolved"
}
An example HTTP request would be serialized as:

::

GET /myOperation?foo=resolved
Host: <server>


Serialization rules
-------------------

Expand Down Expand Up @@ -1378,6 +1468,7 @@ See
output: PutSomethingOutput
}
.. _serializing-http-messages:

Serializing HTTP messages
=========================
Expand All @@ -1393,14 +1484,14 @@ parameters:
corresponding structure member by name:

1. If the member has the ``httpLabel`` trait, expand the value into the URI.
2. If the member has the ``httpQuery`` trait, serialize the value into the
HTTP request as a query string parameter.
3. If the member has the ``httpQueryParams`` trait, serialize the values into
2. If the member has the ``httpQueryParams`` trait, serialize the values into
the HTTP request as query string parameters.
4. If the member has the ``httpHeader`` trait, serialize the value in an
HTTP header using the value of the ``httpHeader`` trait.
5. If the member has the ``httpPrefixHeaders`` trait and the value is a map,
3. If the member has the ``httpQuery`` trait, serialize the value into the
HTTP request as a query string parameter.
4. If the member has the ``httpPrefixHeaders`` trait and the value is a map,
serialize the map key value pairs as prefixed HTTP headers.
5. If the member has the ``httpHeader`` trait, serialize the value in an
HTTP header using the value of the ``httpHeader`` trait.
6. If the member has the ``httpPayload`` trait, serialize the value as the
body of the request.
7. If the member has no bindings, serialize the key-value pair as part of a
Expand All @@ -1418,10 +1509,10 @@ parameters:
3. Iterate over all of the key-value pairs of the parameters and find the
corresponding structure member by name:

1. If the member has the ``httpHeader`` trait, serialize the value in an
HTTP header using the value of the ``httpHeader`` trait.
2. If the member has the ``httpPrefixHeaders`` trait and the value is a map,
1. If the member has the ``httpPrefixHeaders`` trait and the value is a map,
serialize the map key value pairs as prefixed HTTP headers.
2. If the member has the ``httpHeader`` trait, serialize the value in an
HTTP header using the value of the ``httpHeader`` trait.
3. If the member has the ``httpPayload`` trait, serialize the value as the
body of the response.
4. If the member has no bindings, serialize the key-value pair as part of a
Expand Down
102 changes: 102 additions & 0 deletions smithy-aws-protocol-tests/model/restJson1/http-prefix-headers.smithy
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,105 @@ structure HttpPrefixHeadersInResponseOutput {
@httpPrefixHeaders("")
prefixHeaders: StringMap,
}

/// Clients that perform this test extract all headers from the response.
@readonly
@http(uri: "/HttpEmptyPrefixHeaders", method: "GET")
operation HttpEmptyPrefixHeaders {
input := {
@httpPrefixHeaders("")
prefixHeaders: StringMap

@httpHeader("hello")
specificHeader: String
}
output := {
@httpPrefixHeaders("")
prefixHeaders: StringMap

@httpHeader("hello")
specificHeader: String
}
}

apply HttpEmptyPrefixHeaders @httpRequestTests([
{
id: "RestJsonHttpEmptyPrefixHeadersRequestClient"
documentation: "Serializes all request headers, using specific when present"
protocol: restJson1
method: "GET"
uri: "/HttpEmptyPrefixHeaders"
body: ""
headers: {
"x-foo": "Foo",
"hello": "There"
}
params: {
prefixHeaders: {
"x-foo": "Foo",
"hello": "Hello"
}
specificHeader: "There"
}
appliesTo: "client"
}
{
id: "RestJsonHttpEmptyPrefixHeadersRequestServer"
documentation: "Deserializes all request headers with the same for prefix and specific"
protocol: restJson1
method: "GET"
uri: "/HttpEmptyPrefixHeaders"
body: ""
headers: {
"x-foo": "Foo",
"hello": "There"
}
params: {
prefixHeaders: {
"x-foo": "Foo",
"hello": "There"
}
specificHeader: "There"
}
appliesTo: "server"
}
])

apply HttpEmptyPrefixHeaders @httpResponseTests([
{
id: "RestJsonHttpEmptyPrefixHeadersResponseClient"
documentation: "Deserializes all response headers with the same for prefix and specific"
protocol: restJson1
code: 200
headers: {
"x-foo": "Foo",
"hello": "There"
}
params: {
prefixHeaders: {
"x-foo": "Foo",
"hello": "There"
}
specificHeader: "There"
}
appliesTo: "client"
}
{
id: "RestJsonHttpEmptyPrefixHeadersResponseServer"
documentation: "Serializes all response headers, using specific when present"
protocol: restJson1
code: 200
headers: {
"x-foo": "Foo",
"hello": "There"
}
params: {
prefixHeaders: {
"x-foo": "Foo",
"hello": "Hello"
}
specificHeader: "There"
}
appliesTo: "server"
}
])
1 change: 1 addition & 0 deletions smithy-aws-protocol-tests/model/restJson1/main.smithy
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ service RestJson {
// @httpPrefixHeaders tests
HttpPrefixHeaders,
HttpPrefixHeadersInResponse,
HttpEmptyPrefixHeaders,

// @httpPayload tests
HttpPayloadTraits,
Expand Down
Loading
Loading