draft-ietf-httpbis-no-vary-search-03.txt   draft-ietf-httpbis-no-vary-search-latest.txt 
HyperText Transfer Protocol HyperText Transfer Protocol
Internet-Draft Internet-Draft
Intended status: Standards Track Google LLC Intended status: Standards Track , Ed.
Expires: April 2, 2026 September 29, 2025 Expires: August 9, 2026 Google LLC
February 05, 2026
The No-Vary-Search HTTP Response Header Field The No-Vary-Search HTTP Caching Extension
draft-ietf-httpbis-no-vary-search-03 draft-ietf-httpbis-no-vary-search-latest
Abstract Abstract
This specification defines a proposed HTTP response header field for This specification defines an extension to HTTP Caching, changing how
changing how URL search parameters impact caching. URI query parameters impact caching.
About This Document About This Document
This note is to be removed before publishing as an RFC. This note is to be removed before publishing as an RFC.
The latest revision of this draft can be found at The latest revision of this draft can be found at
<https://httpwg.org/http-extensions/draft-ietf-httpbis-no-vary- <https://httpwg.org/http-extensions/draft-ietf-httpbis-no-vary-
search.html>. Status information for this document may be found at search.html>. Status information for this document may be found at
<https://datatracker.ietf.org/doc/draft-ietf-httpbis-no-vary- <https://datatracker.ietf.org/doc/draft-ietf-httpbis-no-vary-
search/>. search/>.
skipping to change at page 1, line 48 skipping to change at page 2, line 4
Internet-Drafts are working documents of the Internet Engineering Internet-Drafts are working documents of the Internet Engineering
Task Force (IETF). Note that other groups may also distribute Task Force (IETF). Note that other groups may also distribute
working documents as Internet-Drafts. The list of current Internet- working documents as Internet-Drafts. The list of current Internet-
Drafts is at https://datatracker.ietf.org/drafts/current/. Drafts is at https://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months Internet-Drafts are draft documents valid for a maximum of six months
and may be updated, replaced, or obsoleted by other documents at any and may be updated, replaced, or obsoleted by other documents at any
time. It is inappropriate to use Internet-Drafts as reference time. It is inappropriate to use Internet-Drafts as reference
material or to cite them other than as "work in progress." material or to cite them other than as "work in progress."
This Internet-Draft will expire on August 9, 2026.
This Internet-Draft will expire on April 2, 2026.
Copyright Notice Copyright Notice
Copyright (c) 2025 IETF Trust and the persons identified as the Copyright (c) 2026 IETF Trust and the persons identified as the
document authors. All rights reserved. document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents Provisions Relating to IETF Documents
(https://trustee.ietf.org/license-info) in effect on the date of (https://trustee.ietf.org/license-info) in effect on the date of
publication of this document. Please review these documents publication of this document. Please review these documents
carefully, as they describe your rights and restrictions with respect carefully, as they describe your rights and restrictions with respect
to this document. Code Components extracted from this document must to this document. Code Components extracted from this document must
include Simplified BSD License text as described in Section 4.e of include Simplified BSD License text as described in Section 4.e of
the Trust Legal Provisions and are provided without warranty as the Trust Legal Provisions and are provided without warranty as
described in the Simplified BSD License. described in the Simplified BSD License.
Table of Contents Table of Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3
2. Conventions and Definitions . . . . . . . . . . . . . . . . . 3 2. Conventions and Definitions . . . . . . . . . . . . . . . . . 4
3. HTTP header field definition . . . . . . . . . . . . . . . . 4 3. HTTP header field definition . . . . . . . . . . . . . . . . 4
4. Data model . . . . . . . . . . . . . . . . . . . . . . . . . 5 4. Data model . . . . . . . . . . . . . . . . . . . . . . . . . 5
5. Parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5. Parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
5.1. Parse a URL search variance . . . . . . . . . . . . . . . 6 5.1. Parse a URL variation config . . . . . . . . . . . . . . 6
5.2. Obtain a URL search variance . . . . . . . . . . . . . . 9 5.2. Obtain a URL variation config . . . . . . . . . . . . . . 9
5.2.1. Examples . . . . . . . . . . . . . . . . . . . . . . 9 5.2.1. Examples . . . . . . . . . . . . . . . . . . . . . . 9
5.3. Parse a key . . . . . . . . . . . . . . . . . . . . . . . 11 5.3. Parse a key . . . . . . . . . . . . . . . . . . . . . . . 11
5.3.1. Examples . . . . . . . . . . . . . . . . . . . . . . 12 5.3.1. Examples . . . . . . . . . . . . . . . . . . . . . . 12
6. Comparing . . . . . . . . . . . . . . . . . . . . . . . . . . 12 6. Comparing . . . . . . . . . . . . . . . . . . . . . . . . . . 12
6.1. Examples . . . . . . . . . . . . . . . . . . . . . . . . 15 6.1. Examples . . . . . . . . . . . . . . . . . . . . . . . . 15
7. Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 7. Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
8. Security Considerations . . . . . . . . . . . . . . . . . . . 18 8. Security Considerations . . . . . . . . . . . . . . . . . . . 18
9. Privacy Considerations . . . . . . . . . . . . . . . . . . . 18 9. Privacy Considerations . . . . . . . . . . . . . . . . . . . 18
10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 19 10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 19
10.1. HTTP Field Names . . . . . . . . . . . . . . . . . . . . 19 10.1. HTTP Field Names . . . . . . . . . . . . . . . . . . . . 19
11. References . . . . . . . . . . . . . . . . . . . . . . . . . 19 11. References . . . . . . . . . . . . . . . . . . . . . . . . . 19
11.1. Normative References . . . . . . . . . . . . . . . . . . 19 11.1. Normative References . . . . . . . . . . . . . . . . . . 19
11.2. Informative References . . . . . . . . . . . . . . . . . 20 11.2. Informative References . . . . . . . . . . . . . . . . . 20
11.3. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 20 11.3. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 22 Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 22
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 22 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 23
1. Introduction 1. Introduction
HTTP caching [HTTP-CACHING] is based on reusing resources which match HTTP caching [HTTP-CACHING] is based on reusing resources which match
across a number of cache keys. One of the most prominent is the across a number of cache keys, with the most important one being the
presented target URI (Section 7.1 of [HTTP]). However, sometimes presented target URI (Section 7.1 of [HTTP]). However, sometimes
multiple URLs can represent the same resource. This leads to caches multiple URIs can represent the same resource. This leads to caches
not always being as helpful as they could be: if the cache contains not always being as helpful as they could be: if the cache contains a
the resource under one URI, but the resource is then requested under response under one URI, but the response is then requested under
another, the cached version will be ignored. another, the cached version will be ignored.
The "No-Vary-Search" HTTP header field tackles a specific subset of The "No-Vary-Search" response header field defines a caching
this general problem, for when a resource has multiple URLs which extension, as described in Section 4 of [HTTP-CACHING], that tackles
differ only in certain query components. It allows resources to a specific subset of this general problem, for when different URIs
declare that some or all parts of the query do not semantically that only differ in certain query parameters identify the same
affect the served resource, and thus can be ignored for cache resource. It allows resources to declare that some or all parts of
matching purposes. For example, if the order of the query parameter the query component do not semantically affect the served response,
keys do not semantically affect the served resource, this is and thus can be ignored for cache matching purposes. For example, if
indicated using the order of the query parameters do not affect which resource is
identified, this is indicated using
No-Vary-Search: key-order No-Vary-Search: key-order
If the specific query parameters (e.g., ones indicating something for If the specific query parameters (e.g., ones indicating something for
analytics) do not semantically affect the served resource, this is analytics) do not semantically affect the served resource, this is
indicated using indicated using
No-Vary-Search: params=("utm_source" "utm_medium" "utm_campaign") No-Vary-Search: params=("utm_source" "utm_medium" "utm_campaign")
And if the resource instead wants to take an allowlist-based And if the resource instead wants to take an allowlist-based
approach, where only certain known query parameters semantically approach, where only certain known query parameters semantically
affect the served resource, they can use affect the served response, they can use
No-Vary-Search: params, except=("productId") No-Vary-Search: params, except=("productId")
Section 3 defines the header, using the [STRUCTURED-FIELDS] Note that "cache busting" by sending unique query parameters to avoid
framework. Section 4 and Section 5 illustrate the data model for how retrieving a cached response can be made ineffective by the "No-Vary-
the header can be represented in specifications, and the process for Search" header field.
parsing the raw output from the structured field parser into that
data model. Section 6 gives the key algorithm for comparing if two Section 3 defines the new response header field "No-Vary-Search",
URLs are equivalent under the influence of the header; notably, it using the [STRUCTURED-FIELDS] framework. Section 4 and Section 5
leans on the decomposition of the query component into keys and illustrate the data model for how the field value can be represented
values given by the application/x-www-form-urlencoded [1] format in specifications, and the process for parsing the raw output from
specified in [WHATWG-URL]. (As such, this header is not useful for the structured field parser into that data model. Section 6 gives
URLs whose query component does not follow that format.) Finally, the key algorithm for comparing if two URLs are equivalent under the
Section 7 explains how to modify [HTTP-CACHING] to take into account influence of the header field; notably, it leans on the decomposition
this new equivalence. of the query component into keys and values given by the application/
x-www-form-urlencoded [1] format specified in [WHATWG-URL]. (As
such, this header field is not useful for URLs whose query component
does not follow that format.) Finally, Section 7 explains how to
extend Section 4 of [HTTP-CACHING] to take this new equivalence into
account.
2. Conventions and Definitions 2. Conventions and Definitions
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
"OPTIONAL" in this document are to be interpreted as described in "OPTIONAL" in this document are to be interpreted as described in
BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all
capitals, as shown here. capitals, as shown here.
In this document, the terms "URI" and "URL" are used interchangeably,
depending on context. "URI" is used in the context of [URI], [HTTP],
and [HTTP-CACHING], whereas "URL" is used in the context of the
algorithms specified in [WHATWG-URL].
This document also adopts some conventions and notation typical in This document also adopts some conventions and notation typical in
WHATWG and W3C usage, especially as it relates to algorithms. See WHATWG and W3C usage, especially as it relates to algorithms. See
[WHATWG-INFRA], and in particular: [WHATWG-INFRA], and in particular:
o its definition of lists, including the list literal notation << 1, o its definition of lists, including the list literal notation << 1,
2, 3 >>. 2, 3 >>.
o its definition of strings, including their representation as code o its definition of strings, including their representation as code
units. units.
skipping to change at page 5, line 10 skipping to change at page 5, line 24
true. true.
The dictionary MAY contain entries whose keys are not one of "key- The dictionary MAY contain entries whose keys are not one of "key-
order", "params", and "except", but their meaning is not defined by order", "params", and "except", but their meaning is not defined by
this specification. Implementations of this specification will this specification. Implementations of this specification will
ignore such entries (but future documents might assign meaning to ignore such entries (but future documents might assign meaning to
such entries). such entries).
As always, the authoring conformance requirements are not binding As always, the authoring conformance requirements are not binding
on implementations. Implementations instead need to implement the on implementations. Implementations instead need to implement the
processing model given by the obtain a URL search variance processing model for URL variation configurations (configs) given
algorithm (Section 5.2). by the obtain a URL variation config algorithm (Section 5.2).
4. Data model 4. Data model
A _URL search variance_ consists of the following: A _URL variation config_ consists of the following:
no-vary params no-vary params
either the special value *wildcard* or a list of strings either the special value *wildcard* or a list of strings
vary params vary params
either the special value *wildcard* or a list of strings either the special value *wildcard* or a list of strings
vary on key order vary on key order
a boolean a boolean
The default URL search variance is a URL search variance whose no- The default URL variation config is a URL variation config whose no-
vary params is an empty list, vary params is *wildcard*, and vary on vary params is an empty list, vary params is *wildcard*, and vary on
key order is true. key order is true.
The obtain a URL search variance algorithm (Section 5.2) ensures that The obtain a URL variation config algorithm (Section 5.2) ensures
all URL search variances obey the following constraints: that all URL variation configs obey the following constraints:
o vary params is a list if and only if the no-vary params is o vary params is a list if and only if the no-vary params is
*wildcard*; and *wildcard*; and
o no-vary params is a list if and only if the vary params is o no-vary params is a list if and only if the vary params is
*wildcard*. *wildcard*.
5. Parsing 5. Parsing
5.1. Parse a URL search variance
To parse a URL search variance given _value_: 5.1. Parse a URL variation config
1. If _value_ is null, then return the default URL search variance. To parse a URL variation config given _value_:
2. Let _result_ be a new URL search variance. 1. If _value_ is null, then return the default URL variation config.
2. Let _result_ be a new URL variation config.
3. Set _result_'s vary on key order to true. 3. Set _result_'s vary on key order to true.
4. If _value_[""key-order""] exists: 4. If _value_[""key-order""] exists:
1. If _value_[""key-order""] is not a boolean, then return the 1. If _value_[""key-order""] is not a boolean, then return the
default URL search variance. default URL variation config.
2. Set _result_'s vary on key order to the boolean negation of 2. Set _result_'s vary on key order to the boolean negation of
_value_[""key-order""]. _value_[""key-order""].
5. If _value_[""params""] exists: 5. If _value_[""params""] exists:
1. If _value_[""params""] is a boolean: 1. If _value_[""params""] is a boolean:
1. If _value_[""params""] is true, then: 1. If _value_[""params""] is true, then:
skipping to change at page 7, line 16 skipping to change at page 7, line 22
2. Otherwise: 2. Otherwise:
1. Set _result_'s no-vary params to the empty list. 1. Set _result_'s no-vary params to the empty list.
2. Set _result_'s vary params to *wildcard*. 2. Set _result_'s vary params to *wildcard*.
2. Otherwise, if _value_[""params""] is an array: 2. Otherwise, if _value_[""params""] is an array:
1. If any item in _value_[""params""] is not a string, then 1. If any item in _value_[""params""] is not a string, then
return the default URL search variance. return the default URL variation config.
2. Set _result_'s no-vary params to the result of applying 2. Set _result_'s no-vary params to the result of applying
parse a key (Section 5.3) to each item in parse a key (Section 5.3) to each item in
_value_[""params""]. _value_[""params""].
3. Set _result_'s vary params to *wildcard*. 3. Set _result_'s vary params to *wildcard*.
3. Otherwise, return the default URL search variance. 3. Otherwise, return the default URL variation config.
6. If _value_[""except""] exists: 6. If _value_[""except""] exists:
1. If _value_[""params""] is not true, then return the default 1. If _value_[""params""] is not true, then return the default
URL search variance. URL variation config.
2. If _value_[""except""] is not an array, then return the 2. If _value_[""except""] is not an array, then return the
default URL search variance. default URL variation config.
3. If any item in _value_[""except""] is not a string, then 3. If any item in _value_[""except""] is not a string, then
return the default URL search variance. return the default URL variation config.
4. Set _result_'s vary params to the result of applying parse a 4. Set _result_'s vary params to the result of applying parse a
key (Section 5.3) to each item in _value_[""except""]. key (Section 5.3) to each item in _value_[""except""].
7. Return _result_. 7. Return _result_.
In general, this algorithm is strict and tends to return the In general, this algorithm is strict and tends to return the
default URL search variance whenever it sees something it doesn't default URL variation config whenever it sees something it doesn't
recognize. This is because the default URL search variance recognize. This is because the default URL variation config
behavior will just cause fewer cache hits, which is an acceptable behavior will just cause fewer cache hits, which is an acceptable
fallback behavior. fallback behavior.
However, unrecognized keys at the top level are ignored, to make However, unrecognized keys at the top level are ignored, to make
it easier to extend this specification in the future. To avoid it easier to extend this specification in the future. To avoid
misbehavior with existing client software, such extensions will misbehavior with existing client software, such extensions will
likely expand, rather than reduce, the set of requests that a likely expand, rather than reduce, the set of requests that a
cached response can match. cached response can match.
The input to this algorithm is generally obtained by parsing a The input to this algorithm is generally obtained by parsing a
structured field (Section 4.2 of [STRUCTURED-FIELDS]) using structured field (Section 4.2 of [STRUCTURED-FIELDS]) using
field_type "dictionary". field_type "dictionary".
5.2. Obtain a URL search variance 5.2. Obtain a URL variation config
To obtain a URL search variance given a response [2] _response_: To obtain a URL variation config given a response [2] _response_:
1. Let _fieldValue_ be the result of getting a structured field 1. Let _fieldValue_ be the result of getting a structured field
value [3] [FETCH] given `"No-Vary-Search"` and ""dictionary"" value [3] [FETCH] given `"No-Vary-Search"` and ""dictionary""
from _response_'s header list. from _response_'s header list.
2. Return the result of parsing a URL search variance (Section 5.1) 2. Return the result of parsing a URL variation config (Section 5.1)
given _fieldValue_. given _fieldValue_.
5.2.1. Examples 5.2.1. Examples
The following illustrates how various inputs are parsed, in terms of The following illustrates how various inputs are parsed, in terms of
their impacting on the resulting no-vary params and vary params: their impact on the resulting no-vary params and vary params:
+-----------------------------+-------------------------------------+ +-----------------------------+-------------------------------------+
| Input | Result | | Input | Result |
+-----------------------------+-------------------------------------+ +-----------------------------+-------------------------------------+
| "No-Vary-Search: params" | no-vary params: *wildcard* vary | | "No-Vary-Search: params" | no-vary params: *wildcard* vary |
| | params: (empty list) | | | params: (empty list) |
| | | | | |
| "No-Vary-Search: | no-vary params: << ""a"" >> vary | | "No-Vary-Search: | no-vary params: << ""a"" >> vary |
| params=("a")" | params: *wildcard* | | params=("a")" | params: *wildcard* |
| | | | | |
| "No-Vary-Search: params, | no-vary params: *wildcard* vary | | "No-Vary-Search: params, | no-vary params: *wildcard* vary |
| except=("x")" | params: << ""x"" >> | | except=("x")" | params: << ""x"" >> |
+-----------------------------+-------------------------------------+ +-----------------------------+-------------------------------------+
The following inputs are all invalid and will cause the default URL The following inputs are all invalid and will cause the default URL
search variance to be returned: variation config to be returned:
o "No-Vary-Search: unknown-key"
o "No-Vary-Search: key-order="not a boolean"" o "No-Vary-Search: key-order="not a boolean""
o "No-Vary-Search: params="not a boolean or inner list"" o "No-Vary-Search: params="not a boolean or inner list""
o "No-Vary-Search: params=(not-a-string)" o "No-Vary-Search: params=(not-a-string)"
o "No-Vary-Search: params=("a"), except=("x")" o "No-Vary-Search: params=("a"), except=("x")"
o "No-Vary-Search: params=(), except=()" o "No-Vary-Search: params=(), except=()"
o "No-Vary-Search: params=?0, except=("x")" o "No-Vary-Search: params=?0, except=("x")"
o "No-Vary-Search: params, except=(not-a-string)" o "No-Vary-Search: params, except=(not-a-string)"
skipping to change at page 11, line 15 skipping to change at page 11, line 15
+---------------------------------+---------------------------------+ +---------------------------------+---------------------------------+
| Input | Conventional form | | Input | Conventional form |
+---------------------------------+---------------------------------+ +---------------------------------+---------------------------------+
| "No-Vary-Search: params=?1" | "No-Vary-Search: params" | | "No-Vary-Search: params=?1" | "No-Vary-Search: params" |
| | | | | |
| "No-Vary-Search: key-order=?1" | "No-Vary-Search: key-order" | | "No-Vary-Search: key-order=?1" | "No-Vary-Search: key-order" |
| | | | | |
| "No-Vary-Search: params, key- | "No-Vary-Search: key-order, | | "No-Vary-Search: params, key- | "No-Vary-Search: key-order, |
| order, except=("x")" | params, except=("x")" | | order, except=("x")" | params, except=("x")" |
| | | | | |
| "No-Vary-Search: params=?0" | (omit the header) | | "No-Vary-Search: params=?0" | (omit the header field) |
| | | | | |
| "No-Vary-Search: params=()" | (omit the header) | | "No-Vary-Search: params=()" | (omit the header field) |
| | | | | |
| "No-Vary-Search: key-order=?0" | (omit the header) | | "No-Vary-Search: key-order=?0" | (omit the header field) |
+---------------------------------+---------------------------------+ +---------------------------------+---------------------------------+
5.3. Parse a key 5.3. Parse a key
To parse a key given an ASCII string _keyString_: To parse a key given an ASCII string _keyString_:
1. Let _keyBytes_ be the isomorphic encoding [4] [WHATWG-INFRA] of 1. Let _keyBytes_ be the isomorphic encoding [4] [WHATWG-INFRA] of
_keyString_. _keyString_.
2. Replace any 0x2B (+) in _keyBytes_ with 0x20 (SP). 2. Replace any 0x2B (+) in _keyBytes_ with 0x20 (SP).
skipping to change at page 12, line 8 skipping to change at page 12, line 8
_keyBytes_. _keyBytes_.
4. Let _keyStringDecoded_ be the UTF-8 decoding without BOM [6] 4. Let _keyStringDecoded_ be the UTF-8 decoding without BOM [6]
[WHATWG-ENCODING] of _keyBytesDecoded_. [WHATWG-ENCODING] of _keyBytesDecoded_.
5. Return _keyStringDecoded_. 5. Return _keyStringDecoded_.
5.3.1. Examples 5.3.1. Examples
The parse a key algorithm allows encoding non-ASCII key strings in The parse a key algorithm allows encoding non-ASCII key strings in
the ASCII structured header format, similar to how the application/x- the ASCII structured header field format, similar to how the
www-form-urlencoded [7] format [WHATWG-URL] allows encoding an entire application/x-www-form-urlencoded [7] format [WHATWG-URL] allows
entry list of keys and values in ASCII URL format. For example, encoding an entire entry list of keys and values in a URI (which is
restricted to ASCII characters). For example,
No-Vary-Search: params=("%C3%A9+%E6%B0%97") No-Vary-Search: params=("%C3%A9+%E6%B0%97")
will result in a URL search variance whose vary params are << ""e will result in a URL variation config whose vary params are << ""e
&#27671;"" >>. As explained in a later example, the canonicalization &#27671;"" >>. As explained in a later example, the canonicalization
process during equivalence testing means this will treat as process during equivalence testing means this will treat as
equivalent URL strings such as: equivalent URIs such as:
o "https://example.com/?e &#27671;=1" o "https://example.com/?e &#27671;=1"
o "https://example.com/?e+&#27671;=2" o "https://example.com/?e+&#27671;=2"
o "https://example.com/?%C3%A9%20&#27671;=3" o "https://example.com/?%C3%A9%20&#27671;=3"
o "https://example.com/?%C3%A9+%E6%B0%97=4" o "https://example.com/?%C3%A9+%E6%B0%97=4"
and so on, since they all are parsed [8] [WHATWG-URL] to having the and so on, since they all are parsed [8] [WHATWG-URL] to having the
same key ""e &#27671;"". same key ""e &#27671;"".
6. Comparing 6. Comparing
Two URLs [9] [WHATWG-URL] _urlA_ and _urlB_ are _equivalent modulo Two URLs [9] [WHATWG-URL] _urlA_ and _urlB_ are _equivalent modulo
search variance_ given a URL search variance _searchVariance_ if the variation config_ given a URL variation config _variationConfig_ if
following algorithm returns true: the following algorithm returns true:
1. If the scheme, username, password, host, port, or path of _urlA_ 1. If the scheme, username, password, host, port, or path of _urlA_
and _urlB_ differ, then return false. and _urlB_ differ, then return false.
2. If _searchVariance_ is equivalent to the default URL search 2. If _variationConfig_ is equivalent to the default URL variation
variance, then: config, then:
1. If _urlA_'s query equals _urlB_'s query, then return true. 1. If _urlA_'s query equals _urlB_'s query, then return true.
2. Return false. 2. Return false.
In this case, even URL pairs that might appear the same after In this case, even URL pairs that might appear the same after
running the application/x-www-form-urlencoded parser [10] running the application/x-www-form-urlencoded parser [10]
[WHATWG-URL] on their queries, such as "https://example.com/a" [WHATWG-URL] on their queries, such as "https://example.com/a"
and "https://example.com/a?", or "https://example.com/ and "https://example.com/a?", or "https://example.com/
foo?a=b&&&c" and "https://example.com/foo?a=b&c=", will be foo?a=b&&&c" and "https://example.com/foo?a=b&c=", will be
skipping to change at page 13, line 28 skipping to change at page 13, line 28
4. If _urlA_'s query is not null, then set _searchParamsA_ to the 4. If _urlA_'s query is not null, then set _searchParamsA_ to the
result of running the application/x-www-form-urlencoded parser result of running the application/x-www-form-urlencoded parser
[11] [WHATWG-URL] given the isomorphic encoding [12] [11] [WHATWG-URL] given the isomorphic encoding [12]
[WHATWG-INFRA] of _urlA_'s query. [WHATWG-INFRA] of _urlA_'s query.
5. If _urlB_'s query is not null, then set _searchParamsB_ to the 5. If _urlB_'s query is not null, then set _searchParamsB_ to the
result of running the application/x-www-form-urlencoded parser result of running the application/x-www-form-urlencoded parser
[13] [WHATWG-URL] given the isomorphic encoding [14] [13] [WHATWG-URL] given the isomorphic encoding [14]
[WHATWG-INFRA] of _urlB_'s query. [WHATWG-INFRA] of _urlB_'s query.
6. If _searchVariance_'s no-vary params is a list, then: 6. If _variationConfig_'s no-vary params is a list, then:
1. Set _searchParamsA_ to a list containing those items _pair_ 1. Set _searchParamsA_ to a list containing those items _pair_
in _searchParamsA_ where _searchVariance_'s no-vary params in _searchParamsA_ where _variationConfig_'s no-vary params
does not contain _pair_[0]. does not contain _pair_[0].
2. Set _searchParamsB_ to a list containing those items _pair_ 2. Set _searchParamsB_ to a list containing those items _pair_
in _searchParamsB_ where _searchVariance_'s no-vary params in _searchParamsB_ where _variationConfig_'s no-vary params
does not contain _pair_[0]. does not contain _pair_[0].
7. Otherwise, if _searchVariance_'s vary params is a list, then: 7. Otherwise, if _variationConfig_'s vary params is a list, then:
1. Set _searchParamsA_ to a list containing those items _pair_ 1. Set _searchParamsA_ to a list containing those items _pair_
in _searchParamsA_ where _searchVariance_'s vary params in _searchParamsA_ where _variationConfig_'s vary params
contains _pair_[0]. contains _pair_[0].
2. Set _searchParamsB_ to a list containing those items _pair_ 2. Set _searchParamsB_ to a list containing those items _pair_
in _searchParamsB_ where _searchVariance_'s vary params in _searchParamsB_ where _variationConfig_'s vary params
contains _pair_[0]. contains _pair_[0].
8. If _searchVariance_'s vary on key order is false, then: 8. If _variationConfig_'s vary on key order is false, then:
1. Let _keyLessThan_ be an algorithm taking as inputs two pairs 1. Let _keyLessThan_ be an algorithm taking as inputs two pairs
(_keyA_, _valueA_) and (_keyB_, _valueB_), which returns (_keyA_, _valueA_) and (_keyB_, _valueB_), which returns
whether _keyA_ is code unit less than [15] [WHATWG-INFRA] whether _keyA_ is code unit less than [15] [WHATWG-INFRA]
_keyB_. _keyB_.
2. Set _searchParamsA_ to the result of sorting _searchParamsA_ 2. Set _searchParamsA_ to the result of sorting _searchParamsA_
in ascending order with _keyLessThan_. in ascending order with _keyLessThan_.
3. Set _searchParamsB_ to the result of sorting _searchParamsB_ 3. Set _searchParamsB_ to the result of sorting _searchParamsB_
skipping to change at page 15, line 28 skipping to change at page 16, line 5
Due to how the application/x-www-form-urlencoded parser canonicalizes Due to how the application/x-www-form-urlencoded parser canonicalizes
query strings, there are some cases where query strings which do not query strings, there are some cases where query strings which do not
appear obviously equivalent, will end up being treated as equivalent appear obviously equivalent, will end up being treated as equivalent
after parsing. after parsing.
So, for example, given any non-default value for "No-Vary-Search", So, for example, given any non-default value for "No-Vary-Search",
such as "No-Vary-Search: key-order", we will have the following such as "No-Vary-Search: key-order", we will have the following
equivalences: equivalences:
https://example.com https://example.com/? +------------+----------------+-------------------------------------+
A null query is parsed the same as an empty string | First | Second Query | Explanation |
| Query | | |
https://example.com/?a=x https://example.com/?%61=%78 +------------+----------------+-------------------------------------+
Parsing performs percent-decoding | null | "?" | A null query is parsed the same as |
| | | an empty string |
https://example.com/?a=e https://example.com/?a=%C3%A9 | | | |
Parsing performs percent-decoding | "?a=x" | "?%61=%78" | Parsing performs percent-decoding |
| | | |
https://example.com/?a=%f6 https://example.com/?a=%ef%bf%bd | "?a=e" | "?a=%C3%A9" | Parsing performs percent-decoding |
Both values are parsed as U+FFFD (&#65533;) | | | |
| "?a=%f6" | "?a=%ef%bf%bd" | Both values are parsed as U+FFFD |
https://example.com/?a=x&&&& https://example.com/?a=x | | | (&#65533;) |
Parsing splits on "&" and discards empty strings | | | |
| "?a=x&&&&" | "?a=x" | Parsing splits on "&" and discards |
https://example.com/?a= https://example.com/?a | | | empty strings |
Both parse as having an empty string value for "a" | | | |
| "?a=" | "?a" | Both parse as having an empty |
https://example.com/?a=%20 https://example.com/?a=+ | | | string value for "a" |
https://example.com/?a= & | | | |
"+" and "%20" are both parsed as U+0020 SPACE | "?a=%20" | "?a= &" | "%20" is parsed as U+0020 SPACE |
| | | |
| "?a=+" | "?a= &" | "+" is parsed as U+0020 SPACE |
+------------+----------------+-------------------------------------+
7. Caching 7. Caching
If a cache [HTTP-CACHING] implements this specification, the If a cache [HTTP-CACHING] implements this specification, the
presented target URI requirement in Section 4 of [HTTP-CACHING] is presented target URI requirement in Section 4 of [HTTP-CACHING]:
replaced with:
o one of the following: the presented target URI (Section 7.1 of [HTTP]) and that of the
stored response match, and
* the presented target URI (Section 7.1 of [HTTP]) and that of is replaced with:
the stored response match, or
* the presented target URI and that of the stored response are the presented target URI (Section 7.1 of [HTTP]) and that of the
equivalent modulo search variance (Section 6), given the stored response match or are equivalent modulo URL variation
variance obtained (Section 5.2) from the stored response. config, and
Cache implementations MAY fail to reuse a stored response whose Cache implementations MAY fail to reuse a stored response whose
target URI matches _only_ modulo URL search variance, if the cache target URI matches _only_ modulo URL variation config, if the cache
has more recently stored a response which: has more recently stored a response which:
o has a target URI which is equal to the presented target URI, o has a target URI which is equal to the presented target URI,
excluding the query, and excluding the query, and
o has a non-empty value for the "No-Vary-Search" field, and o has a non-empty value for the "No-Vary-Search" field, and
o has a "No-Vary-Search" field value different from the stored o has a "No-Vary-Search" field value different from the stored
response being considered for reuse. response being considered for reuse.
skipping to change at page 17, line 35 skipping to change at page 18, line 5
4. Let simplifiedURL be the result of simplifying 4. Let simplifiedURL be the result of simplifying
presentedTargetURI according to lastNVS (by removing query presentedTargetURI according to lastNVS (by removing query
parameters which are not significant, and stable sorting parameters which are not significant, and stable sorting
parameters by key, if key order is to be be ignored). parameters by key, if key order is to be be ignored).
5. Let nvsMatch be cache[simplifiedURL]. If it does not exist, 5. Let nvsMatch be cache[simplifiedURL]. If it does not exist,
return null. (It is assumed that this was written when return null. (It is assumed that this was written when
storing in the cache, in addition to the exact URL.) storing in the cache, in addition to the exact URL.)
6. Let searchVariance be obtained (Section 5.2) from nvsMatch. 6. Let variationConfig be obtained (Section 5.2) from nvsMatch.
7. If nvsMatch's target URI and presentedTargetURI are not 7. If nvsMatch's target URI and presentedTargetURI are not
equivalent modulo search variance (Section 6) given equivalent modulo URL variation config (Section 6) given
searchVariance, then return null. variationConfig, then return null.
8. If nvsMatch is a stored response that can be reused, return 8. If nvsMatch is a stored response that can be reused, return
it. Otherwise, return null. it. Otherwise, return null.
To aid cache implementation efficiency, servers SHOULD NOT send To aid cache implementation efficiency, servers SHOULD NOT send
different non-empty values for the "No-Vary-Search" field in response different non-empty values for the "No-Vary-Search" field in response
to requests for a given pathname over time, unless there is a need to to requests for a given pathname over time, unless there is a need to
update how they handle the query component. Doing so would cause update how they handle the query component. Doing so would cause
cache implementations that use a strategy like the above to miss some cache implementations that use a strategy like the above to miss some
stored responses that could otherwise have been reused. stored responses that could otherwise have been reused.
skipping to change at page 18, line 31 skipping to change at page 18, line 33
The main risk to be aware of is the impact of mismatched URLs. In The main risk to be aware of is the impact of mismatched URLs. In
particular, this could cause the user to see a response that was particular, this could cause the user to see a response that was
originally fetched from a URL different from the one displayed when originally fetched from a URL different from the one displayed when
they hovered a link, or the URL displayed in the URL bar. they hovered a link, or the URL displayed in the URL bar.
However, since the impact is limited to query parameters, this does However, since the impact is limited to query parameters, this does
not cross the relevant security boundary, which is the origin [16] not cross the relevant security boundary, which is the origin [16]
[HTML]. (Or perhaps just the host [17], from the perspective of web [HTML]. (Or perhaps just the host [17], from the perspective of web
browser security UI [18]. [WHATWG-URL]) Indeed, we have already browser security UI [18]. [WHATWG-URL]) Indeed, we have already
given origins complete control over how they present the (URL, given origins complete control over how they present the (URL,
reponse body) pair, including on the client side via technology such response body) pair, including on the client side via technology such
as history.replaceState() [19] or service workers. as history.replaceState() [19] or service workers.
9. Privacy Considerations 9. Privacy Considerations
This proposal is adjacent to the highly-privacy-relevant space of This proposal is adjacent to the highly-privacy-relevant space of
navigational tracking [20], which often uses query parameters to pass navigational tracking [20], which often uses query parameters to pass
along user identifiers. However, we believe this proposal itself along user identifiers. However, we believe this proposal itself
does not have privacy impacts. It does not interfere with existing does not have privacy impacts. It does not interfere with existing
navigational tracking mitigations [21], or any known future ones navigational tracking mitigations [21], or any known future ones
being contemplated. Indeed, if a page were to encode user being contemplated. Indeed, if a page were to encode user
identifiers in its URL, the only ability this proposal gives is to identifiers in its URI, the only ability this proposal gives is to
_reduce_ such user tracking by preventing server processing of such _reduce_ such user tracking by preventing server processing of such
user IDs (since the server is bypassed in favor of the cache). user IDs (since the server is bypassed in favor of the cache).
[NAV-TRACKING-MITIGATIONS] [NAV-TRACKING-MITIGATIONS]
10. IANA Considerations 10. IANA Considerations
IANA should do the following:
10.1. HTTP Field Names 10.1. HTTP Field Names
Enter the following into the Hypertext Transfer Protocol (HTTP) Field IANA is requested to enter the following into the Hypertext Transfer
Name Registry: Protocol (HTTP) Field Name Registry
(https://www.iana.org/assignments/http-fields/http-fields.xhtml
[22]):
Field Name "No-Vary-Search" Field Name: "No-Vary-Search"
Status permanent Status: permanent
Structured Type Dictionary Structured Type: Dictionary
Reference this document Reference: this document
Comments (none) Comments: (none)
11. References 11. References
11.1. Normative References 11.1. Normative References
[FETCH] van Kesteren, A., "Fetch Living Standard", n.d., [FETCH] van Kesteren, A., "Fetch Living Standard", n.d.,
<https://fetch.spec.whatwg.org/>. <https://fetch.spec.whatwg.org/>.
WHATWG WHATWG
skipping to change at page 20, line 7 skipping to change at page 20, line 11
Requirement Levels", BCP 14, RFC 2119, Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997, DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/rfc2119>. <https://www.rfc-editor.org/info/rfc2119>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
May 2017, <https://www.rfc-editor.org/info/rfc8174>. May 2017, <https://www.rfc-editor.org/info/rfc8174>.
[STRUCTURED-FIELDS] [STRUCTURED-FIELDS]
Nottingham, M. and P. Kamp, "Structured Field Values for Nottingham, M. and P. Kamp, "Structured Field Values for
HTTP", RFC 8941, DOI 10.17487/RFC8941, February 2021, HTTP", RFC 9651, DOI 10.17487/RFC9651, September 2024,
<https://www.rfc-editor.org/info/rfc8941>. <https://www.rfc-editor.org/info/rfc9651>.
[URI] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
Resource Identifier (URI): Generic Syntax", STD 66,
RFC 3986, DOI 10.17487/RFC3986, January 2005,
<https://www.rfc-editor.org/info/rfc3986>.
[WHATWG-ENCODING] [WHATWG-ENCODING]
van Kesteren, A., "Encoding Living Standard", n.d., van Kesteren, A., "Encoding Living Standard", n.d.,
<https://encoding.spec.whatwg.org/>. <https://encoding.spec.whatwg.org/>.
WHATWG WHATWG
[WHATWG-INFRA] [WHATWG-INFRA]
van Kesteren, A. and D. Denicola, "Infra Living Standard", van Kesteren, A. and D. Denicola, "Infra Living Standard",
n.d., <https://infra.spec.whatwg.org/>. n.d., <https://infra.spec.whatwg.org/>.
skipping to change at page 21, line 43 skipping to change at page 22, line 5
[19] https://html.spec.whatwg.org/multipage/nav-history- [19] https://html.spec.whatwg.org/multipage/nav-history-
apis.html#dom-history-replacestate apis.html#dom-history-replacestate
[20] https://privacycg.github.io/nav-tracking- [20] https://privacycg.github.io/nav-tracking-
mitigations/#terminology mitigations/#terminology
[21] https://privacycg.github.io/nav-tracking-mitigations/#deployed- [21] https://privacycg.github.io/nav-tracking-mitigations/#deployed-
mitigations mitigations
[22] https://www.iana.org/assignments/http-fields/http-fields.xhtml
Index Index
D D
default URL search variance 5-9, 12 default URL variation config 5-9, 12
E E
equivalent modulo search variance 12 equivalent modulo variation config 12
O O
obtain a URL search variance 5, 9 obtain a URL variation config 5-6, 9
P P
parse a URL search variance 6, 9 parse a URL variation config 6, 9
parse a key 7-8, 11-12 parse a key 7-8, 11-12
Acknowledgments Acknowledgments
This document benefited from valuable reviews and suggestions by: This document benefited from valuable reviews and suggestions by:
o Adam Rice o Adam Rice
o Julian Reschke o Julian Reschke
skipping to change at line 814 skipping to change at page 23, line 16
Domenic Denicola Domenic Denicola
Google LLC Google LLC
Email: d@domenic.me Email: d@domenic.me
Jeremy Roman Jeremy Roman
Google LLC Google LLC
Email: jbroman@chromium.org Email: jbroman@chromium.org
Nidhi Jaju (editor)
Google LLC
Email: nidhijaju@chromium.org
 End of changes. 76 change blocks. 
137 lines changed or deleted 157 lines changed or added

This html diff was produced by rfcdiff 1.48. The latest version is available from http://tools.ietf.org/tools/rfcdiff/