idnits 2.17.00 (12 Aug 2021) /tmp/idnits3848/draft-ietf-httpbis-variants-06.txt: Checking boilerplate required by RFC 5378 and the IETF Trust (see https://trustee.ietf.org/license-info): ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/1id-guidelines.txt: ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/checklist : ---------------------------------------------------------------------------- ** The abstract seems to contain references ([2], [3], [4], [1]), which it shouldn't. Please replace those with straight textual mentions of the documents in question. -- The draft header indicates that this document updates RFC7234, but the abstract doesn't seem to mention this, which it should. Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the IETF Trust and authors Copyright Line does not match the current year == Line 364 has weird spacing: '...: (gzip fr)...' (Using the creation date from RFC7234, updated by this document, for RFC5378 checks: 2007-12-21) -- The document seems to lack a disclaimer for pre-RFC5378 work, but may have content which was first submitted before 10 November 2008. If you have contacted all the original authors and they are all willing to grant the BCP78 rights to the IETF Trust, then this is fine, and you can ignore this comment. If not, you may need to add the pre-RFC5378 disclaimer. (See the Legal Provisions document at https://trustee.ietf.org/license-info for more information.) -- The document date (November 2, 2019) is 924 days in the past. Is this intentional? Checking references for intended status: Proposed Standard ---------------------------------------------------------------------------- (See RFCs 3967 and 4897 for information about using normative references to lower-maturity documents in RFCs) -- Looks like a reference, but probably isn't: '1' on line 839 -- Looks like a reference, but probably isn't: '2' on line 841 -- Looks like a reference, but probably isn't: '3' on line 843 -- Looks like a reference, but probably isn't: '4' on line 845 == Outdated reference: draft-ietf-httpbis-header-structure has been published as RFC 8941 == Outdated reference: draft-ietf-httpbis-client-hints has been published as RFC 8942 Summary: 1 error (**), 0 flaws (~~), 4 warnings (==), 7 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 2 HTTP M. Nottingham 3 Internet-Draft Fastly 4 Updates: 7234 (if approved) November 2, 2019 5 Intended status: Standards Track 6 Expires: May 5, 2020 8 HTTP Representation Variants 9 draft-ietf-httpbis-variants-06 11 Abstract 13 This specification introduces an alternative way to select a HTTP 14 response from a cache based upon its request headers, using the HTTP 15 "Variants" and "Variant-Key" response header fields. Its aim is to 16 make HTTP proactive content negotiation more cache-friendly. 18 Note to Readers 20 _RFC EDITOR: please remove this section before publication_ 22 Discussion of this draft takes place on the HTTP working group 23 mailing list (ietf-http-wg@w3.org), which is archived at 24 https://lists.w3.org/Archives/Public/ietf-http-wg/ [1]. 26 Working Group information can be found at https://httpwg.github.io/ 27 [2]; source code and issues list for this draft can be found at 28 https://github.com/httpwg/http-extensions/labels/variants [3]. 30 There is a prototype implementation of the algorithms herein at 31 https://github.com/mnot/variants-toy [4]. 33 Status of This Memo 35 This Internet-Draft is submitted in full conformance with the 36 provisions of BCP 78 and BCP 79. 38 Internet-Drafts are working documents of the Internet Engineering 39 Task Force (IETF). Note that other groups may also distribute 40 working documents as Internet-Drafts. The list of current Internet- 41 Drafts is at https://datatracker.ietf.org/drafts/current/. 43 Internet-Drafts are draft documents valid for a maximum of six months 44 and may be updated, replaced, or obsoleted by other documents at any 45 time. It is inappropriate to use Internet-Drafts as reference 46 material or to cite them other than as "work in progress." 48 This Internet-Draft will expire on May 5, 2020. 50 Copyright Notice 52 Copyright (c) 2019 IETF Trust and the persons identified as the 53 document authors. All rights reserved. 55 This document is subject to BCP 78 and the IETF Trust's Legal 56 Provisions Relating to IETF Documents 57 (https://trustee.ietf.org/license-info) in effect on the date of 58 publication of this document. Please review these documents 59 carefully, as they describe your rights and restrictions with respect 60 to this document. Code Components extracted from this document must 61 include Simplified BSD License text as described in Section 4.e of 62 the Trust Legal Provisions and are provided without warranty as 63 described in the Simplified BSD License. 65 Table of Contents 67 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 68 1.1. Notational Conventions . . . . . . . . . . . . . . . . . 5 69 2. The "Variants" HTTP Header Field . . . . . . . . . . . . . . 5 70 2.1. Relationship to Vary . . . . . . . . . . . . . . . . . . 7 71 3. The "Variant-Key" HTTP Header Field . . . . . . . . . . . . . 7 72 4. Cache Behaviour . . . . . . . . . . . . . . . . . . . . . . . 9 73 4.1. Compute Possible Keys . . . . . . . . . . . . . . . . . . 10 74 4.2. Check Vary . . . . . . . . . . . . . . . . . . . . . . . 11 75 4.3. Example of Cache Behaviour . . . . . . . . . . . . . . . 11 76 4.3.1. A Variant Missing From the Cache . . . . . . . . . . 12 77 4.3.2. Variants That Don't Overlap the Client's Request . . 13 78 5. Origin Server Behaviour . . . . . . . . . . . . . . . . . . . 13 79 5.1. Examples . . . . . . . . . . . . . . . . . . . . . . . . 14 80 5.1.1. Single Variant . . . . . . . . . . . . . . . . . . . 14 81 5.1.2. Multiple Variants . . . . . . . . . . . . . . . . . . 15 82 5.1.3. Partial Coverage . . . . . . . . . . . . . . . . . . 15 83 6. Defining Content Negotiation Using Variants . . . . . . . . . 16 84 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 16 85 8. Security Considerations . . . . . . . . . . . . . . . . . . . 17 86 9. References . . . . . . . . . . . . . . . . . . . . . . . . . 17 87 9.1. Normative References . . . . . . . . . . . . . . . . . . 17 88 9.2. Informative References . . . . . . . . . . . . . . . . . 18 89 9.3. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 18 90 Appendix A. Variants for Existing Content Negotiation Mechanisms 19 91 A.1. Accept . . . . . . . . . . . . . . . . . . . . . . . . . 19 92 A.2. Accept-Encoding . . . . . . . . . . . . . . . . . . . . . 20 93 A.3. Accept-Language . . . . . . . . . . . . . . . . . . . . . 20 94 A.4. Cookie . . . . . . . . . . . . . . . . . . . . . . . . . 21 95 Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . 22 96 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 23 98 1. Introduction 100 HTTP proactive content negotiation ([RFC7231], Section 3.4.1) is 101 seeing renewed interest, both for existing request headers like 102 Accept-Language and for newer ones (for example, see 103 [I-D.ietf-httpbis-client-hints]). 105 Successfully reusing negotiated responses that have been stored in a 106 HTTP cache requires establishment of a secondary cache key 107 ([RFC7234], Section 4.1). Currently, the Vary header ([RFC7231], 108 Section 7.1.4) does this by nominating a set of request headers. 109 Their values collectively form the secondary cache key for a given 110 response. 112 HTTP's caching model allows a certain amount of latitude in 113 normalising those request header field values, so as to increase the 114 chances of a cache hit while still respecting the semantics of that 115 header. However, normalisation is not formally defined, leading to 116 infrequent implementation in cache, and divergence of behaviours when 117 it is. 119 Even when the headers' semantics are understood, a cache does not 120 know enough about the possible alternative representations available 121 on the origin server to make an appropriate decision. 123 For example, if a cache has stored the following request/response 124 pair: 126 GET /foo HTTP/1.1 127 Host: www.example.com 128 Accept-Language: en;q=0.5, fr;q=1.0 130 HTTP/1.1 200 OK 131 Content-Type: text/html 132 Content-Language: en 133 Vary: Accept-Language 134 Transfer-Encoding: chunked 136 [English content] 138 Provided that the cache has full knowledge of the semantics of 139 Accept-Language and Content-Language, it will know that an English 140 representation is available and might be able to infer that a French 141 representation is not available. But, it does not know (for example) 142 whether a Japanese representation is available without making another 143 request, incurring possibly unnecessary latency. 145 This specification introduces the HTTP Variants response header field 146 (Section 2) to enumerate the available variant representations on the 147 origin server, to provide clients and caches with enough information 148 to properly satisfy requests - either by selecting a response from 149 cache or by forwarding the request towards the origin - by following 150 the algorithm defined in Section 4. 152 Its companion Variant-Key response header field (Section 3) indicates 153 the applicable key(s) that the response is associated with, so that 154 it can be reliably reused in the future. Effectively, it allows the 155 specification of a request header field to define how it affects the 156 secondary cache key. 158 When this specification is in use, the example above might become: 160 GET /foo HTTP/1.1 161 Host: www.example.com 162 Accept-Language: en;q=0.5, fr;q=1.0 164 HTTP/1.1 200 OK 165 Content-Type: text/html 166 Content-Language: en 167 Vary: Accept-Language 168 Variants: Accept-Language;de;en;jp 169 Variant-Key: en 170 Transfer-Encoding: chunked 172 [English content] 174 Proactive content negotiation mechanisms that wish to be used with 175 Variants need to define how to do so explicitly; see Section 6. As a 176 result, it is best suited for negotiation over request headers that 177 are well-understood. 179 Variants also works best when content negotiation takes place over a 180 constrained set of representations; since each variant needs to be 181 listed in the header field, it is ill-suited for open-ended sets of 182 representations. 184 Variants can be seen as a simpler version of the Alternates header 185 field introduced by [RFC2295]; unlike that mechanism, Variants does 186 not require specification of each combination of attributes, and does 187 not assume that each combination has a unique URL. 189 1.1. Notational Conventions 191 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 192 "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and 193 "OPTIONAL" in this document are to be interpreted as described in BCP 194 14 [RFC2119] [RFC8174] when, and only when, they appear in all 195 capitals, as shown here. 197 This specification uses the Augmented Backus-Naur Form (ABNF) 198 notation of [RFC5234] but relies on Structured Headers from 199 [I-D.ietf-httpbis-header-structure] for parsing. 201 Additionally, it uses the "field-name" rule from [RFC7230], "type", 202 "subtype", "content-coding" and "language-range" from [RFC7231], and 203 "cookie-name" from [RFC6265]. 205 2. The "Variants" HTTP Header Field 207 The Variants HTTP response header field indicates what 208 representations are available for a given resource at the time that 209 the response is produced, by enumerating the request header fields 210 that it varies on, along with a representation of the values that are 211 available for each. 213 Variants is a Structured Header Dictionary (Section 3.2 of 214 [I-D.ietf-httpbis-header-structure]). Its ABNF is: 216 Variants = sh-dict 218 Each member-name represents the field-name of a request header that 219 is part of the secondary cache key; each member-value is an inner- 220 list of strings or tokens that convey representations of potential 221 values for that header field, hereafter referred to as "available- 222 values". 224 If Structured Header parsing fails or a member's value does have the 225 structure outlined above, the client MUST treat the representation as 226 having no Variants header field. 228 Note that an available-value that is a token is interpreted as a 229 string containing the same characters, and vice versa. 231 So, given this example header field: 233 Variants: Accept-Encoding=(gzip) 234 a recipient can infer that the only content-coding available for that 235 resource is "gzip" (along with the "identity" non-encoding; see 236 Appendix A.2). 238 Given: 240 Variants: accept-encoding=() 242 a recipient can infer that no content-codings (beyond identity) are 243 supported. Note that as always, field-name is case-insensitive. 245 A more complex example: 247 Variants: Accept-Encoding=(gzip br), Accept-Language=(en fr) 249 Here, recipients can infer that two content-codings in addition to 250 "identity" are available, as well as two content languages. Note 251 that, as with all Structured Header dictionaries, they might occur in 252 the same header field or separately, like this: 254 Variants: Accept-Encoding=(gzip brotli) 255 Variants: Accept-Language=(en fr) 257 The ordering of available-values is significant, as it might be used 258 by the header's algorithm for selecting a response (in this example, 259 the first language is the default; see Appendix A.3). 261 The ordering of the request header fields themselves indicates 262 descending application of preferences; in the example above, a cache 263 that has all of the possible permutations stored will honour the 264 client's preferences for Accept-Encoding before honouring Accept- 265 Language. 267 Origin servers SHOULD consistently send Variant header fields on all 268 cacheable (as per [RFC7234], Section 3) responses for a resource, 269 since its absence will trigger caches to fall back to Vary 270 processing. 272 Likewise, servers MUST send the Variant-Key response header field 273 when sending Variants, since its absence means that the stored 274 response will not be reused when this specification is implemented. 276 _RFC EDITOR: Please remove the next paragraph before publication._ 278 Implementations of drafts of this specification MUST implement an 279 HTTP header field named "Variants-##" instead of the "Variants" 280 header field specified by the final RFC, with "##" replaced by the 281 draft number being implemented. For example, implementations of 282 draft-ietf-httpbis-variants-05 would implement "Variants-05". 284 2.1. Relationship to Vary 286 This specification updates [RFC7234] to allow caches that implement 287 it to ignore request header fields in the Vary header for the 288 purposes of secondary cache key calculation ([RFC7234], Section 4.1) 289 when their semantics are implemented as per this specification and 290 their corresponding response header field is listed in Variants. 292 If any member of the Vary header does not have a corresponding 293 variant that is understood by the implementation, it is still subject 294 to the requirements there. 296 See Section 5.1.3 for an example. 298 In practice, implementation of Vary varies considerably. As a 299 result, cache efficiency might drop considerably when Variants does 300 not contain all of the headers referenced by Vary, because some 301 implementations might choose to disable Variants processing when this 302 is the case. 304 3. The "Variant-Key" HTTP Header Field 306 The Variant-Key HTTP response header field identifies one or more 307 sets of available-values that identify the secondary cache key(s) 308 that the response it occurs within are associated with. 310 Variant-Key is a Structured Header List (Section 3.1 of 311 [I-D.ietf-httpbis-header-structure]) whose members are inner-lists of 312 strings or tokens. Its ABNF is: 314 Variant-Key = sh-list 316 Each member MUST be an inner-list, and MUST itself have the same 317 number of members as there are members of the representation's 318 Variants header field. If not, the client MUST treat the 319 representation as having no Variant-Key header field. 321 Each member identifies a list of available-values corresponding to 322 the header field-names in the Variants header field, thereby 323 identifying a secondary cache key that can be used with this 324 response. These available-values do not need to explicitly appear in 325 the Variants header field; they can be interpreted by the algorithm 326 specific to processing that field. For example, Accept-Encoding 327 defines an implicit "identity" available-value (Appendix A.2). 329 Each inner-list member is treated as identifying an available-value 330 for the corresponding variant-axis' field-name. Any list-member that 331 is a token is interpreted as a string containing the same characters. 333 For example: 335 Variants: Accept-Encoding=(gzip br), Accept-Language=(en fr) 336 Variant-Key: (gzip fr) 338 This header pair indicates that the representation has a "gzip" 339 content-coding and "fr" content-language. 341 If the response can be used to satisfy more than one request, they 342 can be listed in additional members. For example: 344 Variants: Accept-Encoding=(gzip br), Accept-Language=(en fr) 345 Variant-Key: (gzip fr), ("identity" fr) 347 indicates that this response can be used for requests whose Accept- 348 Encoding algorithm selects "gzip" or "identity", as long as the 349 Accept-Language algorithm selects "fr" - perhaps because there is no 350 gzip-compressed French representation. 352 When more than one Variant-Key value is in a response, the first one 353 present MUST correspond to the request that caused that response to 354 be generated. For example: 356 Variants: Accept-Encoding=(gzip br), Accept-Language=(en fr) 357 Variant-Key: (gzip fr), (identity fr), (br fr oops) 359 is treated as if the Variant-Key header were completely absent, which 360 will tend to disable caching for the representation that contains it. 362 Note that in 364 Variant-Key: (gzip fr) 365 Variant-Key: ("gzip " fr) 367 The whitespace after "gzip" in the first header field value is 368 excluded by the parsing algorithm, but the whitespace in the second 369 header field value is included by the string parsing algorithm. This 370 will likely cause the second header field value to fail to match 371 client requests. 373 _RFC EDITOR: Please remove the next paragraph before publication._ 375 Implementations of drafts of this specification MUST implement an 376 HTTP header field named "Variant-Key-##" instead of the "Variant-Key" 377 header field specified by the final RFC, with "##" replaced by the 378 draft number being implemented. For example, implementations of 379 draft-ietf-httpbis-variants-05 would implement "Variant-Key-05". 381 4. Cache Behaviour 383 Caches that implement the Variants header field and the relevant 384 semantics of the field-names it contains can use that knowledge to 385 either select an appropriate stored representation, or forward the 386 request if no appropriate representation is stored. 388 They do so by running this algorithm (or its functional equivalent) 389 upon receiving a request: 391 Given incoming-request (a mapping of field-names to field-values, 392 after being combined as allowed by Section 3.2.2 of [RFC7230]), and 393 stored-responses (a list of stored responses suitable for reuse as 394 defined in Section 4 of [RFC7234], excepting the requirement to 395 calculate a secondary cache key): 397 1. If stored-responses is empty, return an empty list. 399 2. Order stored-responses by the "Date" header field, most recent to 400 least recent. 402 3. Let sorted-variants be an empty list. 404 4. If the freshest member of stored-responses (as per [RFC7234], 405 Section 4.2) has one or more "Variants" header field(s) that 406 successfully parse according to Section 2: 408 1. Select one member of stored-responses with a "Variants" 409 header field-value(s) that successfully parses according to 410 Section 2 and let variants-header be this parsed value. This 411 SHOULD be the most recent response, but MAY be from an older 412 one as long as it is still fresh. 414 2. For each variant-axis in variants-header: 416 1. If variant-axis' field-name corresponds to the request 417 header field identified by a content negotiation 418 mechanism that the implementation supports: 420 1. Let request-value be the field-value associated with 421 field-name in incoming-request, or null if field-name 422 is not in incoming-request. 424 2. Let sorted-values be the result of running the 425 algorithm defined by the content negotiation 426 mechanism with request-value and variant-axis' 427 available-values. 429 3. Append sorted-values to sorted-variants. 431 At this point, sorted-variants will be a list of lists, each 432 member of the top-level list corresponding to a variant-axis 433 in the Variants header field-value, containing zero or more 434 items indicating available-values that are acceptable to the 435 client, in order of preference, greatest to least. 437 5. Return result of running Compute Possible Keys (Section 4.1) on 438 sorted-variants, an empty list and an empty list. 440 This returns a list of lists of strings suitable for comparing to the 441 parsed Variant-Keys (Section 3) that represent possible responses on 442 the server that can be used to satisfy the request, in preference 443 order, provided that their secondary cache key (after removing the 444 headers covered by Variants) matches. Section 4.2 illustrates one 445 way to do this. 447 4.1. Compute Possible Keys 449 This algorithm computes the cross-product of the elements of key- 450 facets. 452 Given key-facets (a list of lists of strings), and key-stub (a list 453 of strings representing a partial key), and possible-keys (a list of 454 lists of strings): 456 1. Let values be the first member of key-facets. 458 2. Let remaining-facets be a copy of all of the members of key- 459 facets except the first. 461 3. For each value in values: 463 1. Let this-key be a copy of key-stub. 465 2. Append value to this-key. 467 3. If remaining-facets is empty, append this-key to possible- 468 keys. 470 4. Otherwise, run Compute Possible Keys on remaining-facets, 471 this-key and possible-keys. 473 4. Return possible-keys. 475 4.2. Check Vary 477 This algorithm is an example of how an implementation can meet the 478 requirement to apply the members of the Vary header field that are 479 not covered by Variants. 481 Given incoming-request (a mapping of field-names to field-values, 482 after being combined as allowed by Section 3.2.2 of [RFC7230]), and 483 stored-response (a stored response): 485 1. Let filtered-vary be the field-value(s) of stored-response's 486 "Vary" header field. 488 2. Let processed-variants be a list containing the request header 489 fields that identify the content negotiation mechanisms supported 490 by the implementation. 492 3. Remove any member of filtered-vary that is a case-insensitive 493 match for a member of processed-variants. 495 4. If the secondary cache key (as calculated in [RFC7234], 496 Section 4.1) for stored_response matches incoming-request, using 497 filtered-vary for the value of the "Vary" response header, return 498 True. 500 5. Return False. 502 This returns a Boolean that indicates whether stored-response can be 503 used to satisfy the request. 505 Note that implementation of the Vary header field varies in practice, 506 and the algorithm above illustrates only one way to apply it. It is 507 equally viable to forward the request if there is a request header 508 listed in Vary but not Variants. 510 4.3. Example of Cache Behaviour 512 For example, if the selected variants-header was: 514 Variants: Accept-Language=(en fr de), Accept-Encoding=(gzip br) 516 and the request contained the headers: 518 Accept-Language: fr;q=1.0, en;q=0.1 519 Accept-Encoding: gzip 520 Then the sorted-variants would be: 522 [ 523 ["fr", "en"] // prefers French, will accept English 524 ["gzip", "identity"] // prefers gzip encoding, will accept identity 525 ] 527 Which means that the result of the Cache Behaviour algorithm would 528 be: 530 [ 531 ["fr", "gzip"], 532 ["fr", "identity"], 533 ["en", "gzip"], 534 ["en", "identity"] 535 ] 537 Representing a first preference of a French, gzip'd response. Thus, 538 if a cache has a response with: 540 Variant-Key: (fr gzip) 542 it could be used to satisfy the first preference. If not, responses 543 corresponding to the other keys could be returned, or the request 544 could be forwarded towards the origin. 546 4.3.1. A Variant Missing From the Cache 548 If the selected variants-header was: 550 Variants: Accept-Language=(en fr de) 552 And a request comes in with the following headers: 554 Accept-Language: de;q=1.0, es;q=0.8 556 Then sorted-variants in Cache Behaviour is: 558 [ 559 ["de"] // prefers German; will not accept English 560 ] 562 If the cache contains responses with the following Variant-Keys: 564 Variant-Key: (fr) 565 Variant-Key: (en) 566 Then the cache needs to forward the request to the origin server, 567 since Variants indicates that "de" is available, and that is 568 acceptable to the client. 570 4.3.2. Variants That Don't Overlap the Client's Request 572 If the selected variants-header was: 574 Variants: Accept-Language=(en fr de) 576 And a request comes in with the following headers: 578 Accept-Language: es;q=1.0, ja;q=0.8 580 Then sorted-variants in Cache Behaviour are: 582 [ 583 ["en"] 584 ] 586 This allows the cache to return a "Variant-Key: en" response even 587 though it's not in the set the client prefers. 589 5. Origin Server Behaviour 591 Origin servers that wish to take advantage of Variants will need to 592 generate both the Variants (Section 2) and Variant-Key (Section 3) 593 header fields in all cacheable responses for a given resource. If 594 either is omitted and the response is stored, it will have the effect 595 of disabling caching for that resource until it is no longer stored 596 (e.g., it expires, or is evicted). 598 Likewise, origin servers will need to assure that the members of both 599 header field values are in the same order and have the same length, 600 since discrepancies will cause caches to avoid using the responses 601 they occur in. 603 The value of the Variants header should be relatively stable for a 604 given resource over time; when it changes, it can have the effect of 605 invalidating previously stored responses. 607 As per Section 2.1, the Vary header is required to be set 608 appropriately when Variants is in use, so that caches that do not 609 implement this specification still operate correctly. 611 Origin servers are advised to carefully consider which content 612 negotiation mechanisms to enumerate in Variants; if a mechanism is 613 not supported by a receiving cache, it will "downgrade" to Vary 614 handling, which can negatively impact cache efficiency. 616 5.1. Examples 618 The operation of Variants is illustrated by the examples below. 620 5.1.1. Single Variant 622 Given a request/response pair: 624 GET /clancy HTTP/1.1 625 Host: www.example.com 626 Accept-Language: en;q=1.0, fr;q=0.5 628 HTTP/1.1 200 OK 629 Content-Type: image/gif 630 Content-Language: en 631 Cache-Control: max-age=3600 632 Variants: Accept-Language=(en de) 633 Variant-Key: (en) 634 Vary: Accept-Language 635 Transfer-Encoding: chunked 637 Upon receipt of this response, the cache knows that two 638 representations of this resource are available, one with a language 639 of "en", and another whose language is "de". 641 Subsequent requests (while this response is fresh) will cause the 642 cache to either reuse this response or forward the request, depending 643 on what the selection algorithm determines. 645 So, if a request with "en" in Accept-Language is received and its 646 q-value indicates that it is acceptable, the stored response is used. 647 A request that indicates that "de" is acceptable will be forwarded to 648 the origin, thereby populating the cache. A cache receiving a 649 request that indicates both languages are acceptable will use the 650 q-value to make a determination of what response to return. 652 A cache receiving a request that does not list either language as 653 acceptable (or does not contain an Accept-Language at all) will 654 return the "en" representation (possibly fetching it from the 655 origin), since it is listed first in the Variants list. 657 Note that Accept-Language is listed in Vary, to assure backwards- 658 compatibility with caches that do not support Variants. 660 5.1.2. Multiple Variants 662 A more complicated request/response pair: 664 GET /murray HTTP/1.1 665 Host: www.example.net 666 Accept-Language: en;q=1.0, fr;q=0.5 667 Accept-Encoding: gzip, br 669 HTTP/1.1 200 OK 670 Content-Type: image/gif 671 Content-Language: en 672 Content-Encoding: br 673 Variants: Accept-Language=(en jp de) 674 Variants: Accept-Encoding=(br gzip) 675 Variant-Key: (en br) 676 Vary: Accept-Language, Accept-Encoding 677 Transfer-Encoding: chunked 679 Here, the cache knows that there are two axes that the response 680 varies upon; language and encoding. Thus, there are a total of nine 681 possible representations for the resource (including the identity 682 encoding), and the cache needs to consider the selection algorithms 683 for both axes. 685 Upon a subsequent request, if both selection algorithms return a 686 stored representation, it can be served from cache; otherwise, the 687 request will need to be forwarded to origin. 689 5.1.3. Partial Coverage 691 Now, consider the previous example, but where only one of the Vary'd 692 axes (encoding) is listed in Variants: 694 GET /bar HTTP/1.1 695 Host: www.example.net 696 Accept-Language: en;q=1.0, fr;q=0.5 697 Accept-Encoding: gzip, br 698 HTTP/1.1 200 OK 699 Content-Type: image/gif 700 Content-Language: en 701 Content-Encoding: br 702 Variants: Accept-Encoding=(br gzip) 703 Variant-Key: (br) 704 Vary: Accept-Language, Accept-Encoding 705 Transfer-Encoding: chunked 707 Here, the cache will need to calculate a secondary cache key as per 708 [RFC7234], Section 4.1 - but considering only Accept-Language to be 709 in its field-value - and then continue processing Variants for the 710 set of stored responses that the algorithm described there selects. 712 6. Defining Content Negotiation Using Variants 714 To be usable with Variants, proactive content negotiation mechanisms 715 need to be specified to take advantage of it. Specifically, they: 717 o MUST define a request header field that advertises the clients 718 preferences or capabilities, whose field-name SHOULD begin with 719 "Accept-". 721 o MUST define the syntax of an available-value that will occur in 722 Variants and Variant-Key. 724 o MUST define an algorithm for selecting a result. It MUST return a 725 list of available-values that are suitable for the request, in 726 order of preference, given the value of the request header 727 nominated above (or null if the request header is absent) and an 728 available-values list from the Variants header. If the result is 729 an empty list, it implies that the cache cannot satisfy the 730 request. 732 Appendix A fulfils these requirements for some existing proactive 733 content negotiation mechanisms in HTTP. 735 7. IANA Considerations 737 This specification registers the following entry in the Permanent 738 Message Header Field Names registry established by [RFC3864]: 740 o Header field name: Variants 742 o Applicable protocol: http 744 o Status: standard 745 o Author/Change Controller: IETF 747 o Specification document(s): [this document] 749 o Related information: 751 This specification registers the following entry in the Permanent 752 Message Header Field Names registry established by [RFC3864]: 754 o Header field name: Variant-Key 756 o Applicable protocol: http 758 o Status: standard 760 o Author/Change Controller: IETF 762 o Specification document(s): [this document] 764 o Related information: 766 8. Security Considerations 768 If the number or advertised characteristics of the representations 769 available for a resource are considered sensitive, the Variants 770 header by its nature will leak them. 772 Note that the Variants header is not a commitment to make 773 representations of a certain nature available; the runtime behaviour 774 of the server always overrides hints like Variants. 776 9. References 778 9.1. Normative References 780 [I-D.ietf-httpbis-header-structure] 781 Nottingham, M. and P. Kamp, "Structured Headers for HTTP", 782 draft-ietf-httpbis-header-structure-13 (work in progress), 783 August 2019. 785 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 786 Requirement Levels", BCP 14, RFC 2119, 787 DOI 10.17487/RFC2119, March 1997, 788 . 790 [RFC4647] Phillips, A. and M. Davis, "Matching of Language Tags", 791 BCP 47, RFC 4647, DOI 10.17487/RFC4647, September 2006, 792 . 794 [RFC5234] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax 795 Specifications: ABNF", STD 68, RFC 5234, 796 DOI 10.17487/RFC5234, January 2008, 797 . 799 [RFC6265] Barth, A., "HTTP State Management Mechanism", RFC 6265, 800 DOI 10.17487/RFC6265, April 2011, 801 . 803 [RFC7230] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer 804 Protocol (HTTP/1.1): Message Syntax and Routing", 805 RFC 7230, DOI 10.17487/RFC7230, June 2014, 806 . 808 [RFC7231] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer 809 Protocol (HTTP/1.1): Semantics and Content", RFC 7231, 810 DOI 10.17487/RFC7231, June 2014, 811 . 813 [RFC7234] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, 814 Ed., "Hypertext Transfer Protocol (HTTP/1.1): Caching", 815 RFC 7234, DOI 10.17487/RFC7234, June 2014, 816 . 818 [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 819 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, 820 May 2017, . 822 9.2. Informative References 824 [I-D.ietf-httpbis-client-hints] 825 Grigorik, I., "HTTP Client Hints", draft-ietf-httpbis- 826 client-hints-07 (work in progress), March 2019. 828 [RFC2295] Holtman, K. and A. Mutz, "Transparent Content Negotiation 829 in HTTP", RFC 2295, DOI 10.17487/RFC2295, March 1998, 830 . 832 [RFC3864] Klyne, G., Nottingham, M., and J. Mogul, "Registration 833 Procedures for Message Header Fields", BCP 90, RFC 3864, 834 DOI 10.17487/RFC3864, September 2004, 835 . 837 9.3. URIs 839 [1] https://lists.w3.org/Archives/Public/ietf-http-wg/ 841 [2] https://httpwg.github.io/ 843 [3] https://github.com/httpwg/http-extensions/labels/variants 845 [4] https://github.com/mnot/variants-toy 847 Appendix A. Variants for Existing Content Negotiation Mechanisms 849 This appendix defines the required information to use existing 850 proactive content negotiation mechanisms (as defined in [RFC7231], 851 Section 5.3) with the Variants header field. 853 A.1. Accept 855 This section defines variant handling for the Accept request header 856 (section 5.3.2 of [RFC7231]). 858 The syntax of an available-value for Accept is: 860 accept-available-value = type "/" subtype 862 To perform content negotiation for Accept given a request-value and 863 available-values: 865 1. Let preferred-available be an empty list. 867 2. Let preferred-types be a list of the types in the request-value 868 (or the empty list if request-value is null), ordered by their 869 weight, highest to lowest, as per Section 5.3.2 of [RFC7231] 870 (omitting any coding with a weight of 0). If a type lacks an 871 explicit weight, an implementation MAY assign one. 873 3. For each preferred-type in preferred-types: 875 1. If any member of available-values matches preferred-type, 876 using the media-range matching mechanism specified in 877 Section 5.3.2 of [RFC7231] (which is case-insensitive), 878 append those members of available-values to preferred- 879 available (preserving the precedence order implied by the 880 media ranges' specificity). 882 4. If preferred-available is empty, append the first member of 883 available-values to preferred-available. This makes the first 884 available-value the default when none of the client's preferences 885 are available. 887 5. Return preferred-available. 889 Note that this algorithm explicitly ignores extension parameters on 890 media types (e.g., "charset"). 892 A.2. Accept-Encoding 894 This section defines variant handling for the Accept-Encoding request 895 header (section 5.3.4 of [RFC7231]). 897 The syntax of an available-value for Accept-Encoding is: 899 accept-encoding-available-value = content-coding / "identity" 901 To perform content negotiation for Accept-Encoding given a request- 902 value and available-values: 904 1. Let preferred-available be an empty list. 906 2. Let preferred-codings be a list of the codings in the request- 907 value (or the empty list if request-value is null), ordered by 908 their weight, highest to lowest, as per Section 5.3.1 of 909 [RFC7231] (omitting any coding with a weight of 0). If a coding 910 lacks an explicit weight, an implementation MAY assign one. 912 3. If "identity" is not a member of preferred-codings, append 913 "identity". 915 4. Append "identity" to available-values. 917 5. For each preferred-coding in preferred-codings: 919 1. If there is a case-insensitive, character-for-character match 920 for preferred-coding in available-values, append that member 921 of available-values to preferred-available. 923 6. Return preferred-available. 925 Note that the unencoded variant needs to have a Variant-Key header 926 field with a value of "identity" (as defined in Section 5.3.4 of 927 [RFC7231]). 929 A.3. Accept-Language 931 This section defines variant handling for the Accept-Language request 932 header (section 5.3.5 of [RFC7231]). 934 The syntax of an available-value for Accept-Language is: 936 accept-encoding-available-value = language-range 938 To perform content negotiation for Accept-Language given a request- 939 value and available-values: 941 1. Let preferred-available be an empty list. 943 2. Let preferred-langs be a list of the language-ranges in the 944 request-value (or the empty list if request-value is null), 945 ordered by their weight, highest to lowest, as per Section 5.3.1 946 of [RFC7231] (omitting any language-range with a weight of 0). 947 If a language-range lacks a weight, an implementation MAY assign 948 one. 950 3. For each preferred-lang in preferred-langs: 952 1. If any member of available-values matches preferred-lang, 953 using either the Basic or Extended Filtering scheme defined 954 in Section 3.3 of [RFC4647], append those members of 955 available-values to preferred-available (preserving their 956 order). 958 4. If preferred-available is empty, append the first member of 959 available-values to preferred-available. This makes the first 960 available-value the default when none of the client's preferences 961 are available. 963 5. Return preferred-available. 965 A.4. Cookie 967 This section defines variant handling for the Cookie request header 968 ([RFC6265]). 970 This syntax of an available-value for Cookie is: 972 cookie-available-value = cookie-name 974 To perform content negotiation for Cookie given a request-value and 975 available-values: 977 1. Let cookies-available be an empty list. 979 2. For each available-value of available-values: 981 1. Parse request-value as a Cookie header field [RFC6265] and 982 let request-cookie-value be the cookie-value corresponding to 983 a cookie with a cookie-name that matches available-value. If 984 no match is found, continue to the next available-value. 986 2. append request-cookie-value to cookies-available. 988 3. Return cookies-available. 990 A simple example is allowing a page designed for users that aren't 991 logged in (denoted by the "logged_in" cookie-name) to be cached: 993 Variants: Cookie=(logged_in) 994 Variant-Key: (0) 995 Vary: Cookie 997 Here, a cache that implements Variants will only use this response to 998 satisfy requests with "Cookie: logged_in=0". Caches that don't 999 implement Variants will vary the response on all Cookie headers. 1001 Or, consider this example: 1003 Variants: Cookie=(user_priority) 1004 Variant-Key: (silver), ("bronze") 1005 Vary: Cookie 1007 Here, the "user_priority" cookie-name allows requests from "gold" 1008 users to be separated from "silver" and "bronze" ones; this response 1009 is only served to the latter two. 1011 It is possible to target a response to a single user; for example: 1013 Variants: Cookie=(user_id) 1014 Variant-Key: (some_person) 1015 Vary: Cookie 1017 Here, only the "some_person" "user_id" will have this response served 1018 to them again. 1020 Note that if more than one cookie-name serves as a cache key, they'll 1021 need to be listed in separate Variants members, like this: 1023 Variants: Cookie=(user_priority), Cookie=(user_region) 1024 Variant-Key: (gold europe) 1025 Vary: Cookie 1027 Acknowledgements 1029 This protocol is conceptually similar to, but simpler than, 1030 Transparent Content Negotiation [RFC2295]. Thanks to its authors for 1031 their inspiration. 1033 It is also a generalisation of a Fastly VCL feature designed by 1034 Rogier 'DocWilco' Mulhuijzen. 1036 Thanks to Hooman Beheshti, Ilya Grigorik, Leif Hedstrom, and Jeffrey 1037 Yasskin for their review and input. 1039 Author's Address 1041 Mark Nottingham 1042 Fastly 1044 Email: mnot@mnot.net 1045 URI: https://www.mnot.net/