Skip to content
Open
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
110 changes: 51 additions & 59 deletions cloudevents/bindings/http-protocol-binding.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,9 @@ The [`data`](#22-data) byte-sequence is used as the HTTP message body.
#### 3.1.3. Metadata Headers

All other [CloudEvents][ce] attributes, including extensions, MUST be
individually mapped to and from distinct HTTP message header.
individually mapped to and from distinct HTTP message headers and follow
the guidelines defined by the
[HTTP specification](https://www.rfc-editor.org/info/rfc9110/#section-5.1).

CloudEvents extensions that define their own attributes MAY define a secondary
mapping to HTTP headers for those attributes, especially if specific attributes
Expand All @@ -205,7 +207,7 @@ Examples:
* `id` maps to `ce-id`
* `specversion` maps to `ce-specversion`

Note: per the [HTTP](https://tools.ietf.org/html/rfc7230#section-3.2)
Note: per the [HTTP](https://www.rfc-editor.org/info/rfc9110/#section-5.1)
specification, header names are case-insensitive.

##### 3.1.3.2. HTTP Header Values
Expand All @@ -214,52 +216,36 @@ The value for each HTTP header is constructed from the respective attribute
type's [canonical string representation][ce-types].

Some CloudEvents metadata attributes can contain arbitrary UTF-8 string content,
and per [RFC7230, section 3][rfc7230-section-3], HTTP headers MUST only use
printable characters from the US-ASCII character set, and are terminated by a
CRLF sequence with OPTIONAL whitespace around the header value.

When encoding a CloudEvent as an HTTP message, string values
represented as HTTP header values MUST be percent-encoded as
described below. This is compatible with [RFC3986, section
2.1][rfc3986-section-2-1] but is more specific about what needs
encoding. The resulting string SHOULD NOT be further encoded.
(Rationale: quoted string escaping is unnecessary when every space
and double-quote character is already percent-encoded.)

When decoding an HTTP message into a CloudEvent, any HTTP header
value MUST first be unescaped with respect to double-quoted strings,
as described in [RFC7230, section 3.2.6][rfc7230-section-3-2-6]. A single
round of percent-decoding MUST then be performed as described
below. HTTP headers for CloudEvent attribute values do not support
parenthetical comments, so the initial unescaping only needs to handle
double-quoted values, including processing backslash escapes within
double-quoted values. Header values produced via the
percent-encoding described here will never include double-quoted
values, but they MUST be supported when receiving events, for
compatibility with older versions of this specification which did
not require double-quote and space characters to be percent-encoded.

Percent encoding is performed by considering each Unicode character
within the attribute's canonical string representation. Any
character represented in memory as a [Unicode surrogate
pair][surrogate-pair] MUST be treated as a single Unicode character.
The following characters MUST be percent-encoded:

- Space (U+0020)
- Double-quote (U+0022)
- Percent (U+0025)
- Any characters outside the printable ASCII range of U+0021-U+007E
inclusive

Attribute values are already constrained to prohibit characters in
the range U+0000-U+001F inclusive and U+007F-U+009F inclusive;
however for simplicity and to account for potential future changes,
it is RECOMMENDED that any HTTP header encoding implementation treats
such characters as requiring percent-encoding.

Space and double-quote are encoded to avoid requiring any further
quoting. Percent is encoded to avoid ambiguity with percent-encoding
itself.
and per the
[HTTP specification](https://www.rfc-editor.org/info/rfc9110/#section-5), any
non-printable characters from the US-ASCII character set MUST be encoded.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at that RFC, section 5 doesn't actually mention percent-encoding explicitly as far as I can see. I've only skimmed admittedly - should we perhaps clarify exactly which bit of section 5 we're talking about, and maybe link to an additional spec, RFC 3986 perhaps?)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're correct that it just says that things must be encoded but it leaves it open for people to choose what encoding mechanism they want. So from that perspective, we're talking about ALL of section 5. I added a link to 3986 for %-encoding.

CloudEvents implementations MUST use
[percent-encoding](https://www.rfc-editor.org/info/rfc8187).

Implementations MAY choose to percent-encode printable US-ASCII characters in
addition to the characters mandated to be encoded by
[RFC8187](https://www.rfc-editor.org/info/rfc8187).

Since CloudEvents does not define a list/array data type, CloudEvents HTTP
headers SHOULD NOT need to leverage the "combined field value"
feature of HTTP where multiple header values can be specified on a single
HTTP header separated by a comma (`,`).

Previous versions of the CloudEvents specification mandated that all
non-leading/trailing spaces be percent-encoded, however, that is no longer the
case. Instead, per the HTTP specification, only leading or trailing spaces that
are not meant to be "stripped" MUST be encoded. Note that all spaces that are
within double-quoted range of characters, or are non-leading/trailing,
MUST NOT be stripped by receivers.

Processing of double-quotes MUST adhere to the HTTP specification.

Percent-encoding is performed by considering each non-printable Unicode
character (ones outside the ASCII range of U+0021-U+007E) within the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the double quote character always be percent-encoded too?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And do we have to encode a space, if it's already within a string? So for example does "x y" have to be encoded as "x%20y" or is it okay as-is? As the space isn't leading or trailing, I wouldn't expect it to be trimmed.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, double quotes should only be encoded if they are part of the actual value. Otherwise, a double-quote is just for grouping purposes. E.g. if I need leading spaces retained then I can encode them or wrap them in double-quotes.

No, you don't need to encode a space that's in a string - so x y can remain x y and it'll work just fine.

attribute's canonical string representation. Any character represented in
memory as a [Unicode surrogate pair][surrogate-pair] MUST be treated as a
single Unicode character. Note that percent (`%`), as a character of the
value and not part of an encoding sequence, MUST also be encoded.

Steps to encode a Unicode character:

Expand All @@ -272,21 +258,27 @@ Steps to encode a Unicode character:
Percent-encoding SHOULD be performed using upper-case for values A-F,
but decoding MUST accept lower-case values.

When performing percent-decoding (when decoding an HTTP message to a
CloudEvent), values that have been unnecessarily percent-encoded MUST be
accepted, but encoded byte sequences which are invalid in UTF-8 MUST be
rejected. (For example, "%C0%A0" is an overlong encoding of U+0020, and
MUST be rejected.)
Decoding of an HTTP header value MUST adhere to the HTTP specification.
For clarity, that includes:
- removing any non-encoded leading/trailing whitespaces from each value.
- processing backslashed (`\`) characters within double-quoted ranges.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't mentioned in the encoding part as far as I can see. Should it be?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no it's part of the http spec. I'm trying hard not to duplicate the entire spec - but if you think I should for this I can.... or I can do the other route and remove this "For clarity" section entirely.

- removing any non-encoded double-quoted characters from each value.
- decoding any percent-encoded characters.

Example: a header value of "Euro € 😀" SHOULD be encoded as follows:
When performing percent-decoding, values that have been unnecessarily
percent-encoded MUST be accepted, but encoded byte sequences which are invalid
in UTF-8 MUST be rejected. (For example, "%C0%A0" is an overlong encoding of
U+0020, and MUST be rejected.)

- The characters, 'E', 'u', 'r', 'o' do not require encoding
Example: a header value of `Euro € 😀` SHOULD be encoded as
follows:

- The characters, `E`, `u`, `r`, `o` do not require encoding
- Space, the Euro symbol, and the grinning face emoji require encoding.
They are characters U+0020, U+20AC and U+1F600 respectively.
- The encoded HTTP header value is therefore "Euro%20%E2%82%AC%20%F0%9F%98%80"
where "%20" is the encoded form of space, "%E2%82%AC" is the encoded form
of the Euro symbol, and "%F0%9F%98%80" is the encoded form of the
grinning face emoji.
- The encoded HTTP header value is therefore `Euro %E2%82%AC%F0%9F%98%80`
where `%E2%82%AC` is the encoded form of the Euro symbol, and `%F0%9F%98%80`
is the encoded form of the grinning face emoji.

#### 3.1.4. Examples

Expand Down
Loading