From c4b51fa8c0de7e4d27e91baee2ff5120ec3ace34 Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Mon, 23 Jun 2025 13:46:33 -0700 Subject: [PATCH 1/4] Provide guidance for Set-Cookie The Set-Cookie response header breaks the normal rules for headers with multiple values and requires special handling. --- src/oas.md | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/oas.md b/src/oas.md index e91c9cb08a..641649e427 100644 --- a/src/oas.md +++ b/src/oas.md @@ -2451,6 +2451,72 @@ Using `content` with a `text/plain` media type is RECOMMENDED for headers where | ---- | :----: | ---- | | content | Map[`string`, [Media Type Object](#media-type-object)] | A map containing the representations for the header. The key is the media type and the value describes it. The map MUST only contain one entry. | +##### Representing the `Set-Cookie` Header + +As noted in [[!RFC9110]] [Section 5.3](https://www.rfc-editor.org/rfc/rfc9110.html#section-5.3) the `Set-Cookie` response header violates the requirements for representing multiple values as a comma-separated list, as `style: "simple"` produces. + +```http +Set-Cookie: lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT +Set-Cookie: foo=bar; Expires=Wed, 09 Jun 2021 10:18:14 GMT +``` + +If these values were to be place on a single line using `style: "simple"`, the result would be `lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT,foo=bar; Expires=Wed, 09 Jun 2021 10:18:14 GMT`, which when split would then produce four values: `lang=en-US; Expires=Wed`, `09 Jun 2021 10:18:14 GMT`, `foo=bar; Expires=Wed`, and `09 Jun 2021 10:18:14 GMT`. +While the two dates (`09...`) are not valid `Set-Cookie` values on their own, [[?RFC6265]] does not provide any guarantee that all such embedded uses of commas will produce detectable errors when split in this way. + +RFC9110 therefore advises recipients to 'handle "Set-Cookie" as a special case while processing fields,' so the OAS similarly special-cases its handling of `Set-Cookie` as follows: + +For the `Set-Cookie` response header _**only**_, `style: "simple"` MUST be treated as producing a newline-delimited list instead of a comma-separated list, with each line corresponding to the value of a single `Set-Cookie:` header field. +This newline-delimited format MUST be used whenever a string representing the values is required, including in the [Example Object's](#example-object) serialized example fields, and when using `content` with a `text/plain` [Media Type Object](#media-type-object) as is necessary to prevent percent-encoding whitespace. + +The following example shows two different ways to describe `Set-Cookie` headers that require cookies named `"lang"` and `"foo"`. The first uses `content` to preserve the necessary whitespace in the `"Expires"` cookie attribute, while the second shows the use of `style: "simple"` and forbids whitespace to ensure that values work with this serialization approach: + +```yaml +components: + headers: + SetCookieWithExpires: + # Spaces within the Expires values prevent the use of `schema` and + # `style` as they would be percent-encoded, even with `allowReserved`. + content: + text/plain: + schema: + type: string + allOf: + - pattern: "^lang=[^;];.*Expires=" + - pattern: "^foo=[^;];.*Expires=" + examples: + WithExpires: + # This demonstrates that the text is required to be provided + # in the final format, and is not changed by serialization. + # In practice, it is not necessary to show both fields here. + dataValue: | + lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT + foo=bar; Expires=Wed, 09 Jun 2021 10:18:14 GMT + serializedValue: | + lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT + foo=bar; Expires=Wed, 09 Jun 2021 10:18:14 GMT + SetCookieWithNoSpaces: + schema: + type: object + required: + - lang + - foo + additionalProperties: + type: string + pattern: "^[^[:space:]]$" + style: simple + explode: true + allowReserved: true # "=", ";", and " " are reserved + examples: + SetCookies: + dataValue: { + "lang": "en-US", + "foo": "bar" + } + serializedValue: | + lang=en-US + foo=bar +``` + ##### Header Object Example A simple header of type `integer`: From dbcb69239e6f860454348e8c51618777bf0f06bf Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Mon, 30 Jun 2025 10:14:03 -0700 Subject: [PATCH 2/4] Fix typo Co-authored-by: Phil Sturgeon <67381+philsturgeon@users.noreply.github.com> --- src/oas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/oas.md b/src/oas.md index 641649e427..3f50fa57dc 100644 --- a/src/oas.md +++ b/src/oas.md @@ -2460,7 +2460,7 @@ Set-Cookie: lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT Set-Cookie: foo=bar; Expires=Wed, 09 Jun 2021 10:18:14 GMT ``` -If these values were to be place on a single line using `style: "simple"`, the result would be `lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT,foo=bar; Expires=Wed, 09 Jun 2021 10:18:14 GMT`, which when split would then produce four values: `lang=en-US; Expires=Wed`, `09 Jun 2021 10:18:14 GMT`, `foo=bar; Expires=Wed`, and `09 Jun 2021 10:18:14 GMT`. +If these values were to be placed on a single line using `style: "simple"`, the result would be `lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT,foo=bar; Expires=Wed, 09 Jun 2021 10:18:14 GMT`, which when split would then produce four values: `lang=en-US; Expires=Wed`, `09 Jun 2021 10:18:14 GMT`, `foo=bar; Expires=Wed`, and `09 Jun 2021 10:18:14 GMT`. While the two dates (`09...`) are not valid `Set-Cookie` values on their own, [[?RFC6265]] does not provide any guarantee that all such embedded uses of commas will produce detectable errors when split in this way. RFC9110 therefore advises recipients to 'handle "Set-Cookie" as a special case while processing fields,' so the OAS similarly special-cases its handling of `Set-Cookie` as follows: From 734129d45804395457689c896c961d32b02ccb82 Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Fri, 4 Jul 2025 09:52:17 -0700 Subject: [PATCH 3/4] Explain when Set-Cookie workaround is needed Also remove a stray line from an example that didn't really hurt but wasn't needed and could have been confusing. --- src/oas.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/oas.md b/src/oas.md index 3f50fa57dc..b9c3dc2e1c 100644 --- a/src/oas.md +++ b/src/oas.md @@ -2463,7 +2463,11 @@ Set-Cookie: foo=bar; Expires=Wed, 09 Jun 2021 10:18:14 GMT If these values were to be placed on a single line using `style: "simple"`, the result would be `lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT,foo=bar; Expires=Wed, 09 Jun 2021 10:18:14 GMT`, which when split would then produce four values: `lang=en-US; Expires=Wed`, `09 Jun 2021 10:18:14 GMT`, `foo=bar; Expires=Wed`, and `09 Jun 2021 10:18:14 GMT`. While the two dates (`09...`) are not valid `Set-Cookie` values on their own, [[?RFC6265]] does not provide any guarantee that all such embedded uses of commas will produce detectable errors when split in this way. -RFC9110 therefore advises recipients to 'handle "Set-Cookie" as a special case while processing fields,' so the OAS similarly special-cases its handling of `Set-Cookie` as follows: +RFC9110 therefore advises recipients to 'handle "Set-Cookie" as a special case while processing fields,' so the OAS similarly special-cases its handling of `Set-Cookie`. + +When an OAS implementation is mapping directly between the multi-`Set-Cookie:` header line format and an array representation, without any intermediate single string holding the multiple values, no special handling is needed as the behavior is the same as for headers that can be either on a single line with comma-separated values or on multiple lines. + +However, if a multi-value text representation is needed, such as for a `text/plain` representation (using the `content` field) or in an Example Object, the following special handling is required: For the `Set-Cookie` response header _**only**_, `style: "simple"` MUST be treated as producing a newline-delimited list instead of a comma-separated list, with each line corresponding to the value of a single `Set-Cookie:` header field. This newline-delimited format MUST be used whenever a string representing the values is required, including in the [Example Object's](#example-object) serialized example fields, and when using `content` with a `text/plain` [Media Type Object](#media-type-object) as is necessary to prevent percent-encoding whitespace. @@ -2505,7 +2509,6 @@ components: pattern: "^[^[:space:]]$" style: simple explode: true - allowReserved: true # "=", ";", and " " are reserved examples: SetCookies: dataValue: { From 120b1d5fb57cd968729353752704f00747742489 Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Tue, 8 Jul 2025 14:33:45 -0700 Subject: [PATCH 4/4] Better wording and grammar Co-authored-by: Lorna Jane Mitchell --- src/oas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/oas.md b/src/oas.md index b9c3dc2e1c..768a273f94 100644 --- a/src/oas.md +++ b/src/oas.md @@ -2463,7 +2463,7 @@ Set-Cookie: foo=bar; Expires=Wed, 09 Jun 2021 10:18:14 GMT If these values were to be placed on a single line using `style: "simple"`, the result would be `lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT,foo=bar; Expires=Wed, 09 Jun 2021 10:18:14 GMT`, which when split would then produce four values: `lang=en-US; Expires=Wed`, `09 Jun 2021 10:18:14 GMT`, `foo=bar; Expires=Wed`, and `09 Jun 2021 10:18:14 GMT`. While the two dates (`09...`) are not valid `Set-Cookie` values on their own, [[?RFC6265]] does not provide any guarantee that all such embedded uses of commas will produce detectable errors when split in this way. -RFC9110 therefore advises recipients to 'handle "Set-Cookie" as a special case while processing fields,' so the OAS similarly special-cases its handling of `Set-Cookie`. +RFC9110 therefore advises recipients to 'handle "Set-Cookie" as a special case while processing fields,' so the OAS similarly applies a special case to its handling of `Set-Cookie`. When an OAS implementation is mapping directly between the multi-`Set-Cookie:` header line format and an array representation, without any intermediate single string holding the multiple values, no special handling is needed as the behavior is the same as for headers that can be either on a single line with comma-separated values or on multiple lines.