| draft-ietf-quic-qpack-14.txt | draft-ietf-quic-qpack-15.txt | |||
|---|---|---|---|---|
| QUIC C. Krasic | QUIC C. Krasic | |||
| Internet-Draft Netflix | Internet-Draft Netflix | |||
| Intended status: Standards Track M. Bishop | Intended status: Standards Track M. Bishop | |||
| Expires: 24 August 2020 Akamai Technologies | Expires: 21 November 2020 Akamai Technologies | |||
| A. Frindell, Ed. | A. Frindell, Ed. | |||
| 21 February 2020 | 20 May 2020 | |||
| QPACK: Header Compression for HTTP/3 | QPACK: Header Compression for HTTP/3 | |||
| draft-ietf-quic-qpack-14 | draft-ietf-quic-qpack-15 | |||
| Abstract | Abstract | |||
| This specification defines QPACK, a compression format for | This specification defines QPACK, a compression format for | |||
| efficiently representing HTTP header fields, to be used in HTTP/3. | efficiently representing HTTP fields, to be used in HTTP/3. This is | |||
| This is a variation of HPACK header compression that seeks to reduce | a variation of HPACK compression that seeks to reduce head-of-line | |||
| head-of-line blocking. | blocking. | |||
| Note to Readers | Note to Readers | |||
| Discussion of this draft takes place on the QUIC working group | Discussion of this draft takes place on the QUIC working group | |||
| mailing list (quic@ietf.org), which is archived at | mailing list (quic@ietf.org (mailto:quic@ietf.org)), which is | |||
| https://mailarchive.ietf.org/arch/search/?email_list=quic | archived at https://mailarchive.ietf.org/arch/ | |||
| (https://mailarchive.ietf.org/arch/search/?email_list=quic). | search/?email_list=quic. | |||
| Working Group information can be found at https://github.com/quicwg | Working Group information can be found at https://github.com/quicwg; | |||
| (https://github.com/quicwg); source code and issues list for this | source code and issues list for this draft can be found at | |||
| draft can be found at https://github.com/quicwg/base-drafts/labels/- | https://github.com/quicwg/base-drafts/labels/-qpack. | |||
| qpack (https://github.com/quicwg/base-drafts/labels/-qpack). | ||||
| Status of This Memo | Status of This Memo | |||
| This Internet-Draft is submitted in full conformance with the | This Internet-Draft is submitted in full conformance with the | |||
| provisions of BCP 78 and BCP 79. | provisions of BCP 78 and BCP 79. | |||
| 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 24 August 2020. | This Internet-Draft will expire on 21 November 2020. | |||
| Copyright Notice | Copyright Notice | |||
| Copyright (c) 2020 IETF Trust and the persons identified as the | Copyright (c) 2020 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 (https://trustee.ietf.org/ | Provisions Relating to IETF Documents (https://trustee.ietf.org/ | |||
| license-info) in effect on the date of publication of this document. | license-info) in effect on the date of publication of this document. | |||
| Please review these documents carefully, as they describe your rights | Please review these documents carefully, as they describe your rights | |||
| skipping to change at page 2, line 26 ¶ | skipping to change at page 2, line 26 ¶ | |||
| as described in Section 4.e of the Trust Legal Provisions and are | as described in Section 4.e of the Trust Legal Provisions and are | |||
| provided without warranty as described in the Simplified BSD License. | provided without warranty as described in the Simplified BSD License. | |||
| Table of Contents | Table of Contents | |||
| 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 | 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 | |||
| 1.1. Conventions and Definitions . . . . . . . . . . . . . . . 4 | 1.1. Conventions and Definitions . . . . . . . . . . . . . . . 4 | |||
| 1.2. Notational Conventions . . . . . . . . . . . . . . . . . 5 | 1.2. Notational Conventions . . . . . . . . . . . . . . . . . 5 | |||
| 2. Compression Process Overview . . . . . . . . . . . . . . . . 5 | 2. Compression Process Overview . . . . . . . . . . . . . . . . 5 | |||
| 2.1. Encoder . . . . . . . . . . . . . . . . . . . . . . . . . 5 | 2.1. Encoder . . . . . . . . . . . . . . . . . . . . . . . . . 5 | |||
| 2.1.1. Reference Tracking . . . . . . . . . . . . . . . . . 6 | 2.1.1. Limits on Dynamic Table Insertions . . . . . . . . . 6 | |||
| 2.1.2. Limits on Dynamic Table Insertions . . . . . . . . . 6 | 2.1.2. Blocked Streams . . . . . . . . . . . . . . . . . . . 7 | |||
| 2.1.3. Blocked Streams . . . . . . . . . . . . . . . . . . . 7 | 2.1.3. Avoiding Flow Control Deadlocks . . . . . . . . . . . 8 | |||
| 2.1.4. Avoiding Flow Control Deadlocks . . . . . . . . . . . 8 | 2.1.4. Known Received Count . . . . . . . . . . . . . . . . 8 | |||
| 2.1.5. Known Received Count . . . . . . . . . . . . . . . . 8 | ||||
| 2.2. Decoder . . . . . . . . . . . . . . . . . . . . . . . . . 9 | 2.2. Decoder . . . . . . . . . . . . . . . . . . . . . . . . . 9 | |||
| 2.2.1. Blocked Decoding . . . . . . . . . . . . . . . . . . 9 | 2.2.1. Blocked Decoding . . . . . . . . . . . . . . . . . . 9 | |||
| 2.2.2. State Synchronization . . . . . . . . . . . . . . . . 9 | 2.2.2. State Synchronization . . . . . . . . . . . . . . . . 9 | |||
| 2.2.3. Invalid References . . . . . . . . . . . . . . . . . 10 | 2.2.3. Invalid References . . . . . . . . . . . . . . . . . 11 | |||
| 3. Header Tables . . . . . . . . . . . . . . . . . . . . . . . . 11 | 3. Reference Tables . . . . . . . . . . . . . . . . . . . . . . 11 | |||
| 3.1. Static Table . . . . . . . . . . . . . . . . . . . . . . 11 | 3.1. Static Table . . . . . . . . . . . . . . . . . . . . . . 11 | |||
| 3.2. Dynamic Table . . . . . . . . . . . . . . . . . . . . . . 11 | 3.2. Dynamic Table . . . . . . . . . . . . . . . . . . . . . . 11 | |||
| 3.2.1. Dynamic Table Size . . . . . . . . . . . . . . . . . 11 | 3.2.1. Dynamic Table Size . . . . . . . . . . . . . . . . . 12 | |||
| 3.2.2. Dynamic Table Capacity and Eviction . . . . . . . . . 12 | 3.2.2. Dynamic Table Capacity and Eviction . . . . . . . . . 12 | |||
| 3.2.3. Maximum Dynamic Table Capacity . . . . . . . . . . . 12 | 3.2.3. Maximum Dynamic Table Capacity . . . . . . . . . . . 13 | |||
| 3.2.4. Absolute Indexing . . . . . . . . . . . . . . . . . . 13 | 3.2.4. Absolute Indexing . . . . . . . . . . . . . . . . . . 13 | |||
| 3.2.5. Relative Indexing . . . . . . . . . . . . . . . . . . 13 | 3.2.5. Relative Indexing . . . . . . . . . . . . . . . . . . 13 | |||
| 3.2.6. Post-Base Indexing . . . . . . . . . . . . . . . . . 14 | 3.2.6. Post-Base Indexing . . . . . . . . . . . . . . . . . 14 | |||
| 4. Wire Format . . . . . . . . . . . . . . . . . . . . . . . . . 14 | 4. Wire Format . . . . . . . . . . . . . . . . . . . . . . . . . 15 | |||
| 4.1. Primitives . . . . . . . . . . . . . . . . . . . . . . . 15 | 4.1. Primitives . . . . . . . . . . . . . . . . . . . . . . . 15 | |||
| 4.1.1. Prefixed Integers . . . . . . . . . . . . . . . . . . 15 | 4.1.1. Prefixed Integers . . . . . . . . . . . . . . . . . . 15 | |||
| 4.1.2. String Literals . . . . . . . . . . . . . . . . . . . 15 | 4.1.2. String Literals . . . . . . . . . . . . . . . . . . . 15 | |||
| 4.2. Encoder and Decoder Streams . . . . . . . . . . . . . . . 15 | 4.2. Encoder and Decoder Streams . . . . . . . . . . . . . . . 16 | |||
| 4.3. Encoder Instructions . . . . . . . . . . . . . . . . . . 16 | 4.3. Encoder Instructions . . . . . . . . . . . . . . . . . . 17 | |||
| 4.3.1. Set Dynamic Table Capacity . . . . . . . . . . . . . 16 | 4.3.1. Set Dynamic Table Capacity . . . . . . . . . . . . . 17 | |||
| 4.3.2. Insert With Name Reference . . . . . . . . . . . . . 17 | 4.3.2. Insert With Name Reference . . . . . . . . . . . . . 17 | |||
| 4.3.3. Insert Without Name Reference . . . . . . . . . . . . 17 | 4.3.3. Insert Without Name Reference . . . . . . . . . . . . 18 | |||
| 4.3.4. Duplicate . . . . . . . . . . . . . . . . . . . . . . 18 | 4.3.4. Duplicate . . . . . . . . . . . . . . . . . . . . . . 18 | |||
| 4.4. Decoder Instructions . . . . . . . . . . . . . . . . . . 18 | ||||
| 4.4.1. Header Acknowledgement . . . . . . . . . . . . . . . 18 | 4.4. Decoder Instructions . . . . . . . . . . . . . . . . . . 19 | |||
| 4.4.2. Stream Cancellation . . . . . . . . . . . . . . . . . 19 | 4.4.1. Section Acknowledgement . . . . . . . . . . . . . . . 19 | |||
| 4.4.3. Insert Count Increment . . . . . . . . . . . . . . . 19 | 4.4.2. Stream Cancellation . . . . . . . . . . . . . . . . . 20 | |||
| 4.5. Header Block Representations . . . . . . . . . . . . . . 20 | 4.4.3. Insert Count Increment . . . . . . . . . . . . . . . 20 | |||
| 4.5.1. Header Block Prefix . . . . . . . . . . . . . . . . . 20 | 4.5. Field Line Representations . . . . . . . . . . . . . . . 20 | |||
| 4.5.2. Indexed Header Field . . . . . . . . . . . . . . . . 23 | 4.5.1. Encoded Field Section Prefix . . . . . . . . . . . . 21 | |||
| 4.5.3. Indexed Header Field With Post-Base Index . . . . . . 23 | 4.5.2. Indexed Field Line . . . . . . . . . . . . . . . . . 23 | |||
| 4.5.4. Literal Header Field With Name Reference . . . . . . 24 | 4.5.3. Indexed Field Line With Post-Base Index . . . . . . . 24 | |||
| 4.5.5. Literal Header Field With Post-Base Name Reference . 25 | 4.5.4. Literal Field Line With Name Reference . . . . . . . 24 | |||
| 4.5.6. Literal Header Field Without Name Reference . . . . . 25 | 4.5.5. Literal Field Line With Post-Base Name Reference . . 25 | |||
| 4.5.6. Literal Field Line Without Name Reference . . . . . . 25 | ||||
| 5. Configuration . . . . . . . . . . . . . . . . . . . . . . . . 26 | 5. Configuration . . . . . . . . . . . . . . . . . . . . . . . . 26 | |||
| 6. Error Handling . . . . . . . . . . . . . . . . . . . . . . . 26 | 6. Error Handling . . . . . . . . . . . . . . . . . . . . . . . 26 | |||
| 7. Security Considerations . . . . . . . . . . . . . . . . . . . 26 | 7. Security Considerations . . . . . . . . . . . . . . . . . . . 27 | |||
| 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 27 | 7.1. Probing Dynamic Table State . . . . . . . . . . . . . . . 27 | |||
| 8.1. Settings Registration . . . . . . . . . . . . . . . . . . 27 | 7.2. Applicability to QPACK and HTTP . . . . . . . . . . . . . 28 | |||
| 8.2. Stream Type Registration . . . . . . . . . . . . . . . . 27 | 7.3. Mitigation . . . . . . . . . . . . . . . . . . . . . . . 28 | |||
| 8.3. Error Code Registration . . . . . . . . . . . . . . . . . 27 | 7.4. Never Indexed Literals . . . . . . . . . . . . . . . . . 29 | |||
| 9. References . . . . . . . . . . . . . . . . . . . . . . . . . 28 | 7.5. Static Huffman Encoding . . . . . . . . . . . . . . . . . 30 | |||
| 9.1. Normative References . . . . . . . . . . . . . . . . . . 28 | 7.6. Memory Consumption . . . . . . . . . . . . . . . . . . . 30 | |||
| 9.2. Informative References . . . . . . . . . . . . . . . . . 28 | 7.7. Implementation Limits . . . . . . . . . . . . . . . . . . 31 | |||
| Appendix A. Static Table . . . . . . . . . . . . . . . . . . . . 29 | 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 31 | |||
| Appendix B. Sample One Pass Encoding Algorithm . . . . . . . . . 33 | 8.1. Settings Registration . . . . . . . . . . . . . . . . . . 31 | |||
| Appendix C. Change Log . . . . . . . . . . . . . . . . . . . . . 34 | 8.2. Stream Type Registration . . . . . . . . . . . . . . . . 32 | |||
| C.1. Since draft-ietf-quic-qpack-13 . . . . . . . . . . . . . 35 | 8.3. Error Code Registration . . . . . . . . . . . . . . . . . 32 | |||
| C.2. Since draft-ietf-quic-qpack-12 . . . . . . . . . . . . . 35 | 9. References . . . . . . . . . . . . . . . . . . . . . . . . . 33 | |||
| C.3. Since draft-ietf-quic-qpack-11 . . . . . . . . . . . . . 35 | 9.1. Normative References . . . . . . . . . . . . . . . . . . 33 | |||
| C.4. Since draft-ietf-quic-qpack-10 . . . . . . . . . . . . . 35 | 9.2. Informative References . . . . . . . . . . . . . . . . . 34 | |||
| C.5. Since draft-ietf-quic-qpack-09 . . . . . . . . . . . . . 35 | Appendix A. Static Table . . . . . . . . . . . . . . . . . . . . 34 | |||
| C.6. Since draft-ietf-quic-qpack-08 . . . . . . . . . . . . . 35 | Appendix B. Sample One Pass Encoding Algorithm . . . . . . . . . 39 | |||
| C.7. Since draft-ietf-quic-qpack-06 . . . . . . . . . . . . . 35 | Appendix C. Change Log . . . . . . . . . . . . . . . . . . . . . 40 | |||
| C.8. Since draft-ietf-quic-qpack-05 . . . . . . . . . . . . . 35 | C.1. Since draft-ietf-quic-qpack-14 . . . . . . . . . . . . . 40 | |||
| C.9. Since draft-ietf-quic-qpack-04 . . . . . . . . . . . . . 36 | C.2. Since draft-ietf-quic-qpack-13 . . . . . . . . . . . . . 41 | |||
| C.10. Since draft-ietf-quic-qpack-03 . . . . . . . . . . . . . 36 | C.3. Since draft-ietf-quic-qpack-12 . . . . . . . . . . . . . 41 | |||
| C.11. Since draft-ietf-quic-qpack-02 . . . . . . . . . . . . . 36 | C.4. Since draft-ietf-quic-qpack-11 . . . . . . . . . . . . . 41 | |||
| C.12. Since draft-ietf-quic-qpack-01 . . . . . . . . . . . . . 36 | C.5. Since draft-ietf-quic-qpack-10 . . . . . . . . . . . . . 41 | |||
| C.13. Since draft-ietf-quic-qpack-00 . . . . . . . . . . . . . 36 | C.6. Since draft-ietf-quic-qpack-09 . . . . . . . . . . . . . 41 | |||
| C.14. Since draft-ietf-quic-qcram-00 . . . . . . . . . . . . . 37 | C.7. Since draft-ietf-quic-qpack-08 . . . . . . . . . . . . . 41 | |||
| Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 37 | C.8. Since draft-ietf-quic-qpack-06 . . . . . . . . . . . . . 41 | |||
| Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 37 | C.9. Since draft-ietf-quic-qpack-05 . . . . . . . . . . . . . 41 | |||
| C.10. Since draft-ietf-quic-qpack-04 . . . . . . . . . . . . . 41 | ||||
| C.11. Since draft-ietf-quic-qpack-03 . . . . . . . . . . . . . 42 | ||||
| C.12. Since draft-ietf-quic-qpack-02 . . . . . . . . . . . . . 42 | ||||
| C.13. Since draft-ietf-quic-qpack-01 . . . . . . . . . . . . . 42 | ||||
| C.14. Since draft-ietf-quic-qpack-00 . . . . . . . . . . . . . 42 | ||||
| C.15. Since draft-ietf-quic-qcram-00 . . . . . . . . . . . . . 43 | ||||
| Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 43 | ||||
| Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 44 | ||||
| 1. Introduction | 1. Introduction | |||
| The QUIC transport protocol [QUIC-TRANSPORT] is designed to support | The QUIC transport protocol [QUIC-TRANSPORT] is designed to support | |||
| HTTP semantics, and its design subsumes many of the features of | HTTP semantics, and its design subsumes many of the features of | |||
| HTTP/2 [RFC7540]. HTTP/2 uses HPACK [RFC7541] for header | HTTP/2 [RFC7540]. HTTP/2 uses HPACK [RFC7541] for compression of the | |||
| compression. If HPACK were used for HTTP/3 [HTTP3], it would induce | header and trailer sections. If HPACK were used for HTTP/3 [HTTP3], | |||
| head-of-line blocking due to built-in assumptions of a total ordering | it would induce head-of-line blocking for field sections due to | |||
| across frames on all streams. | built-in assumptions of a total ordering across frames on all | |||
| streams. | ||||
| QPACK reuses core concepts from HPACK, but is redesigned to allow | QPACK reuses core concepts from HPACK, but is redesigned to allow | |||
| correctness in the presence of out-of-order delivery, with | correctness in the presence of out-of-order delivery, with | |||
| flexibility for implementations to balance between resilience against | flexibility for implementations to balance between resilience against | |||
| head-of-line blocking and optimal compression ratio. The design | head-of-line blocking and optimal compression ratio. The design | |||
| goals are to closely approach the compression ratio of HPACK with | goals are to closely approach the compression ratio of HPACK with | |||
| substantially less head-of-line blocking under the same loss | substantially less head-of-line blocking under the same loss | |||
| conditions. | conditions. | |||
| 1.1. Conventions and Definitions | 1.1. 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 BCP | "OPTIONAL" in this document are to be interpreted as described in | |||
| 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. | |||
| Definitions of terms that are used in this document: | Definitions of terms that are used in this document: | |||
| Header field: A name-value pair sent as part of an HTTP message. | HTTP fields: Metadata sent as part of an HTTP message. The term | |||
| encompasses both header and trailer fields. Colloquially, the | ||||
| term "headers" has often been used to refer to HTTP header fields | ||||
| and trailer fields; this document uses "fields" for generality. | ||||
| Header list: An ordered collection of header fields associated with | HTTP field line: A name-value pair sent as part of an HTTP field | |||
| an HTTP message. A header list can contain multiple header fields | section. See Section 4 of [SEMANTICS]. | |||
| with the same name. It can also contain duplicate header fields. | ||||
| Header block: The compressed representation of a header list. | HTTP field value: Data associated with a field name, composed from | |||
| all field line values with that field name in that section, | ||||
| concatenated together and separated with commas. | ||||
| Encoder: An implementation which transforms a header list into a | Field section: An ordered collection of HTTP field lines associated | |||
| header block. | with an HTTP message. A field section can contain multiple field | |||
| lines with the same name. It can also contain duplicate field | ||||
| lines. An HTTP message can include both header field and trailer | ||||
| field sections. | ||||
| Decoder: An implementation which transforms a header block into a | Representation: An instruction which represents a field line, | |||
| header list. | possibly by reference to the dynamic and static tables. | |||
| Encoder: An implementation which encodes field sections. | ||||
| Decoder: An implementation which decodes encoded field sections. | ||||
| Absolute Index: A unique index for each entry in the dynamic table. | Absolute Index: A unique index for each entry in the dynamic table. | |||
| Base: A reference point for relative and post-base indices. | Base: A reference point for relative and post-base indices. | |||
| References to dynamic table entries in header blocks are relative | Representations which reference dynamic table entries are relative | |||
| to a Base. | to a Base. | |||
| Insert Count: The total number of entries inserted in the dynamic | Insert Count: The total number of entries inserted in the dynamic | |||
| table. | table. | |||
| QPACK is a name, not an acronym. | QPACK is a name, not an acronym. | |||
| 1.2. Notational Conventions | 1.2. Notational Conventions | |||
| Diagrams use the format described in Section 3.1 of [RFC2360], with | Diagrams use the format described in Section 3.1 of [RFC2360], with | |||
| skipping to change at page 5, line 25 ¶ | skipping to change at page 5, line 35 ¶ | |||
| x (A) Indicates that x is A bits long | x (A) Indicates that x is A bits long | |||
| x (A+) Indicates that x uses the prefixed integer encoding defined | x (A+) Indicates that x uses the prefixed integer encoding defined | |||
| in Section 4.1.1, beginning with an A-bit prefix. | in Section 4.1.1, beginning with an A-bit prefix. | |||
| x ... Indicates that x is variable-length and extends to the end of | x ... Indicates that x is variable-length and extends to the end of | |||
| the region. | the region. | |||
| 2. Compression Process Overview | 2. Compression Process Overview | |||
| Like HPACK, QPACK uses two tables for associating header fields to | Like HPACK, QPACK uses two tables for associating field lines | |||
| indices. The static table (Section 3.1) is predefined and contains | ("headers") to indices. The static table (Section 3.1) is predefined | |||
| common header fields (some of them with an empty value). The dynamic | and contains common header field lines (some of them with an empty | |||
| table (Section 3.2) is built up over the course of the connection and | value). The dynamic table (Section 3.2) is built up over the course | |||
| can be used by the encoder to index header fields in the encoded | of the connection and can be used by the encoder to index both header | |||
| header lists. | and trailer field lines in the encoded field sections. | |||
| QPACK defines unidirectional streams for sending instructions from | QPACK defines unidirectional streams for sending instructions from | |||
| encoder to decoder and vice versa. | encoder to decoder and vice versa. | |||
| 2.1. Encoder | 2.1. Encoder | |||
| An encoder converts a header list into a header block by emitting | An encoder converts a header or trailer field section into a series | |||
| either an indexed or a literal representation for each header field | of representations by emitting either an indexed or a literal | |||
| in the list; see Section 4.5. Indexed representations achieve high | representation for each field line in the list; see Section 4.5. | |||
| compression by replacing the literal name and possibly the value with | Indexed representations achieve high compression by replacing the | |||
| an index to either the static or dynamic table. References to the | literal name and possibly the value with an index to either the | |||
| static table and literal representations do not require any dynamic | static or dynamic table. References to the static table and literal | |||
| state and never risk head-of-line blocking. References to the | representations do not require any dynamic state and never risk head- | |||
| dynamic table risk head-of-line blocking if the encoder has not | of-line blocking. References to the dynamic table risk head-of-line | |||
| received an acknowledgement indicating the entry is available at the | blocking if the encoder has not received an acknowledgement | |||
| decoder. | indicating the entry is available at the decoder. | |||
| An encoder MAY insert any entry in the dynamic table it chooses; it | An encoder MAY insert any entry in the dynamic table it chooses; it | |||
| is not limited to header fields it is compressing. | is not limited to field lines it is compressing. | |||
| QPACK preserves the ordering of header fields within each header | QPACK preserves the ordering of field lines within each field | |||
| list. An encoder MUST emit header field representations in the order | section. An encoder MUST emit field representations in the order | |||
| they appear in the input header list. | they appear in the input field section. | |||
| QPACK is designed to contain the more complex state tracking to the | QPACK is designed to contain the more complex state tracking to the | |||
| encoder, while the decoder is relatively simple. | encoder, while the decoder is relatively simple. | |||
| 2.1.1. Reference Tracking | 2.1.1. Limits on Dynamic Table Insertions | |||
| An encoder MUST ensure that a header block which references a dynamic | ||||
| table entry is not processed by the decoder after the referenced | ||||
| entry has been evicted. Hence the encoder needs to retain | ||||
| information about each compressed header block that references the | ||||
| dynamic table until that header block is acknowledged by the decoder; | ||||
| see Section 4.4.1. | ||||
| 2.1.2. Limits on Dynamic Table Insertions | ||||
| Inserting entries into the dynamic table might not be possible if the | Inserting entries into the dynamic table might not be possible if the | |||
| table contains entries which cannot be evicted. | table contains entries which cannot be evicted. | |||
| A dynamic table entry cannot be evicted immediately after insertion, | A dynamic table entry cannot be evicted immediately after insertion, | |||
| even if it has never been referenced. Once the insertion of a | even if it has never been referenced. Once the insertion of a | |||
| dynamic table entry has been acknowledged and there are no | dynamic table entry has been acknowledged and there are no | |||
| outstanding unacknowledged references to the entry, the entry becomes | outstanding references to the entry in unacknowledged | |||
| evictable. | representations, the entry becomes evictable. Note that references | |||
| on the encoder stream never preclude the eviction of an entry, | ||||
| because those references are guaranteed to be processed before the | ||||
| instruction evicting the entry. | ||||
| If the dynamic table does not contain enough room for a new entry | If the dynamic table does not contain enough room for a new entry | |||
| without evicting other entries, and the entries which would be | without evicting other entries, and the entries which would be | |||
| evicted are not evictable, the encoder MUST NOT insert that entry | evicted are not evictable, the encoder MUST NOT insert that entry | |||
| into the dynamic table (including duplicates of existing entries). | into the dynamic table (including duplicates of existing entries). | |||
| In order to avoid this, an encoder that uses the dynamic table has to | In order to avoid this, an encoder that uses the dynamic table has to | |||
| keep track of whether each entry is currently evictable or not. | keep track of each dynamic table entry referenced by each field | |||
| section until those representations are acknowledged by the decoder; | ||||
| see Section 4.4.1. | ||||
| 2.1.2.1. Avoiding Prohibited Insertions | 2.1.1.1. Avoiding Prohibited Insertions | |||
| To ensure that the encoder is not prevented from adding new entries, | To ensure that the encoder is not prevented from adding new entries, | |||
| the encoder can avoid referencing entries that are close to eviction. | the encoder can avoid referencing entries that are close to eviction. | |||
| Rather than reference such an entry, the encoder can emit a Duplicate | Rather than reference such an entry, the encoder can emit a Duplicate | |||
| instruction (Section 4.3.4), and reference the duplicate instead. | instruction (Section 4.3.4), and reference the duplicate instead. | |||
| Determining which entries are too close to eviction to reference is | Determining which entries are too close to eviction to reference is | |||
| an encoder preference. One heuristic is to target a fixed amount of | an encoder preference. One heuristic is to target a fixed amount of | |||
| available space in the dynamic table: either unused space or space | available space in the dynamic table: either unused space or space | |||
| that can be reclaimed by evicting non-blocking entries. To achieve | that can be reclaimed by evicting non-blocking entries. To achieve | |||
| this, the encoder can maintain a draining index, which is the | this, the encoder can maintain a draining index, which is the | |||
| smallest absolute index (Section 3.2.4) in the dynamic table that it | smallest absolute index (Section 3.2.4) in the dynamic table that it | |||
| will emit a reference for. As new entries are inserted, the encoder | will emit a reference for. As new entries are inserted, the encoder | |||
| increases the draining index to maintain the section of the table | increases the draining index to maintain the section of the table | |||
| that it will not reference. If the encoder does not create new | that it will not reference. If the encoder does not create new | |||
| references to entries with an absolute index lower than the draining | references to entries with an absolute index lower than the draining | |||
| index, the number of unacknowledged references to those entries will | index, the number of unacknowledged references to those entries will | |||
| eventually become zero, allowing them to be evicted. | eventually become zero, allowing them to be evicted. | |||
| +----------+---------------------------------+--------+ | +--------+---------------------------------+----------+ | |||
| | Draining | Referenceable | Unused | | | Unused | Referenceable | Draining | | |||
| | Entries | Entries | Space | | | Space | Entries | Entries | | |||
| +----------+---------------------------------+--------+ | +--------+---------------------------------+----------+ | |||
| ^ ^ ^ | ^ ^ ^ | |||
| | | | | | | | | |||
| Dropping Draining Index Insertion Point | Insertion Point Draining Index Dropping | |||
| Point | Point | |||
| Figure 1: Draining Dynamic Table Entries | Figure 1: Draining Dynamic Table Entries | |||
| 2.1.3. Blocked Streams | 2.1.2. Blocked Streams | |||
| Because QUIC does not guarantee order between data on different | Because QUIC does not guarantee order between data on different | |||
| streams, a decoder might encounter a header block that references a | streams, a decoder might encounter a representation that references a | |||
| dynamic table entry that it has not yet received. | dynamic table entry that it has not yet received. | |||
| Each header block contains a Required Insert Count (Section 4.5.1), | Each encoded field section contains a Required Insert Count | |||
| the lowest possible value for the Insert Count with which the header | (Section 4.5.1), the lowest possible value for the Insert Count with | |||
| block can be decoded. For a header block with references to the | which the field section can be decoded. For a field section encoded | |||
| dynamic table, the Required Insert Count is one larger than the | using references to the dynamic table, the Required Insert Count is | |||
| largest absolute index of all referenced dynamic table entries. For | one larger than the largest absolute index of all referenced dynamic | |||
| a header block with no references to the dynamic table, the Required | table entries. For a field section encoded with no references to the | |||
| Insert Count is zero. | dynamic table, the Required Insert Count is zero. | |||
| When the decoder receives a header block with a Required Insert Count | When the decoder receives an encoded field section with a Required | |||
| greater than its own Insert Count, the stream cannot be processed | Insert Count greater than its own Insert Count, the stream cannot be | |||
| immediately, and is considered "blocked"; see Section 2.2.1. | processed immediately, and is considered "blocked"; see | |||
| Section 2.2.1. | ||||
| The decoder specifies an upper bound on the number of streams which | The decoder specifies an upper bound on the number of streams which | |||
| can be blocked using the SETTINGS_QPACK_BLOCKED_STREAMS setting; see | can be blocked using the SETTINGS_QPACK_BLOCKED_STREAMS setting; see | |||
| Section 5. An encoder MUST limit the number of streams which could | Section 5. An encoder MUST limit the number of streams which could | |||
| become blocked to the value of SETTINGS_QPACK_BLOCKED_STREAMS at all | become blocked to the value of SETTINGS_QPACK_BLOCKED_STREAMS at all | |||
| times. If a decoder encounters more blocked streams than it promised | times. If a decoder encounters more blocked streams than it promised | |||
| to support, it MUST treat this as a connection error of type | to support, it MUST treat this as a connection error of type | |||
| QPACK_DECOMPRESSION_FAILED. | QPACK_DECOMPRESSION_FAILED. | |||
| Note that the decoder might not become blocked on every stream which | Note that the decoder might not become blocked on every stream which | |||
| risks becoming blocked. | risks becoming blocked. | |||
| An encoder can decide whether to risk having a stream become blocked. | An encoder can decide whether to risk having a stream become blocked. | |||
| If permitted by the value of SETTINGS_QPACK_BLOCKED_STREAMS, | If permitted by the value of SETTINGS_QPACK_BLOCKED_STREAMS, | |||
| compression efficiency can often be improved by referencing dynamic | compression efficiency can often be improved by referencing dynamic | |||
| table entries that are still in transit, but if there is loss or | table entries that are still in transit, but if there is loss or | |||
| reordering the stream can become blocked at the decoder. An encoder | reordering the stream can become blocked at the decoder. An encoder | |||
| can avoid the risk of blocking by only referencing dynamic table | can avoid the risk of blocking by only referencing dynamic table | |||
| entries which have been acknowledged, but this could mean using | entries which have been acknowledged, but this could mean using | |||
| literals. Since literals make the header block larger, this can | literals. Since literals make the encoded field section larger, this | |||
| result in the encoder becoming blocked on congestion or flow control | can result in the encoder becoming blocked on congestion or flow | |||
| limits. | control limits. | |||
| 2.1.4. Avoiding Flow Control Deadlocks | 2.1.3. Avoiding Flow Control Deadlocks | |||
| Writing instructions on streams that are limited by flow control can | Writing instructions on streams that are limited by flow control can | |||
| produce deadlocks. | produce deadlocks. | |||
| A decoder might stop issuing flow control credit on the stream that | A decoder might stop issuing flow control credit on the stream that | |||
| carries a header block until the necessary updates are received on | carries an encoded field section until the necessary updates are | |||
| the encoder stream. If the granting of flow control credit on the | received on the encoder stream. If the granting of flow control | |||
| encoder stream (or the connection as a whole) depends on the | credit on the encoder stream (or the connection as a whole) depends | |||
| consumption and release of data on the stream carrying the header | on the consumption and release of data on the stream carrying the | |||
| block, a deadlock might result. | encoded field section, a deadlock might result. | |||
| More generally, a stream containing a large instruction can become | More generally, a stream containing a large instruction can become | |||
| deadlocked if the decoder withholds flow control credit until the | deadlocked if the decoder withholds flow control credit until the | |||
| instruction is completely received. | instruction is completely received. | |||
| To avoid these deadlocks, an encoder SHOULD avoid writing an | To avoid these deadlocks, an encoder SHOULD avoid writing an | |||
| instruction unless sufficient stream and connection flow control | instruction unless sufficient stream and connection flow control | |||
| credit is available for the entire instruction. | credit is available for the entire instruction. | |||
| 2.1.5. Known Received Count | 2.1.4. Known Received Count | |||
| The Known Received Count is the total number of dynamic table | The Known Received Count is the total number of dynamic table | |||
| insertions and duplications acknowledged by the decoder. The encoder | insertions and duplications acknowledged by the decoder. The encoder | |||
| tracks the Known Received Count in order to identify which dynamic | tracks the Known Received Count in order to identify which dynamic | |||
| table entries can be referenced without potentially blocking a | table entries can be referenced without potentially blocking a | |||
| stream. The decoder tracks the Known Received Count in order to be | stream. The decoder tracks the Known Received Count in order to be | |||
| able to send Insert Count Increment instructions. | able to send Insert Count Increment instructions. | |||
| A Header Acknowledgement instruction (Section 4.4.1) implies that the | A Section Acknowledgement instruction (Section 4.4.1) implies that | |||
| decoder has received all dynamic table state necessary to process | the decoder has received all dynamic table state necessary to decode | |||
| corresponding the header block. If the Required Insert Count of the | the field section. If the Required Insert Count of the acknowledged | |||
| acknowledged header block is greater than the current Known Received | field section is greater than the current Known Received Count, Known | |||
| Count, Known Received Count is updated to the value of the Required | Received Count is updated to the value of the Required Insert Count. | |||
| Insert Count. | ||||
| An Insert Count Increment instruction Section 4.4.3 increases the | An Insert Count Increment instruction Section 4.4.3 increases the | |||
| Known Received Count by its Increment parameter. See Section 2.2.2.3 | Known Received Count by its Increment parameter. See Section 2.2.2.3 | |||
| for guidance. | for guidance. | |||
| 2.2. Decoder | 2.2. Decoder | |||
| As in HPACK, the decoder processes header blocks and emits the | As in HPACK, the decoder processes a series of representations and | |||
| corresponding header lists. It also processes instructions received | emits the corresponding field sections. It also processes | |||
| on the encoder stream that modify the dynamic table. Note that | instructions received on the encoder stream that modify the dynamic | |||
| header blocks and encoder stream instructions arrive on separate | table. Note that encoded field sections and encoder stream | |||
| streams. This is unlike HPACK, where header blocks can contain | instructions arrive on separate streams. This is unlike HPACK, where | |||
| instructions that modify the dynamic table, and there is no dedicated | encoded field sections (header blocks) can contain instructions that | |||
| stream of HPACK instructions. | modify the dynamic table, and there is no dedicated stream of HPACK | |||
| instructions. | ||||
| The decoder MUST emit header fields in the order their | The decoder MUST emit field lines in the order their representations | |||
| representations appear in the input header block. | appear in the encoded field section. | |||
| 2.2.1. Blocked Decoding | 2.2.1. Blocked Decoding | |||
| Upon receipt of a header block, the decoder examines the Required | Upon receipt of an encoded field section, the decoder examines the | |||
| Insert Count. When the Required Insert Count is less than or equal | Required Insert Count. When the Required Insert Count is less than | |||
| to the decoder's Insert Count, the header block can be processed | or equal to the decoder's Insert Count, the field section can be | |||
| immediately. Otherwise, the stream on which the header block was | processed immediately. Otherwise, the stream on which the field | |||
| received becomes blocked. | section was received becomes blocked. | |||
| While blocked, header block data SHOULD remain in the blocked | While blocked, encoded field section data SHOULD remain in the | |||
| stream's flow control window. A stream becomes unblocked when the | blocked stream's flow control window. A stream becomes unblocked | |||
| Insert Count becomes greater than or equal to the Required Insert | when the Insert Count becomes greater than or equal to the Required | |||
| Count for all header blocks the decoder has started reading from the | Insert Count for all encoded field sections the decoder has started | |||
| stream. | reading from the stream. | |||
| When processing header blocks, the decoder expects the Required | When processing encoded field sections, the decoder expects the | |||
| Insert Count to exactly match the value defined in Section 2.1.3. If | Required Insert Count to equal the lowest possible value for the | |||
| it encounters a smaller value than expected, it MUST treat this as a | Insert Count with which the field section can be decoded, as | |||
| connection error of type QPACK_DECOMPRESSION_FAILED; see | prescribed in Section 2.1.2. If it encounters a Required Insert | |||
| Section 2.2.3. If it encounters a larger value than expected, it MAY | Count smaller than expected, it MUST treat this as a connection error | |||
| treat this as a connection error of type QPACK_DECOMPRESSION_FAILED. | of type QPACK_DECOMPRESSION_FAILED; see Section 2.2.3. If it | |||
| encounters a Required Insert Count larger than expected, it MAY treat | ||||
| this as a connection error of type QPACK_DECOMPRESSION_FAILED. | ||||
| 2.2.2. State Synchronization | 2.2.2. State Synchronization | |||
| The decoder signals the following events by emitting decoder | The decoder signals the following events by emitting decoder | |||
| instructions (Section 4.4) on the decoder stream. | instructions (Section 4.4) on the decoder stream. | |||
| 2.2.2.1. Completed Processing of a Header Block | 2.2.2.1. Completed Processing of a Field Section | |||
| After the decoder finishes decoding a header block containing dynamic | After the decoder finishes decoding a field section encoded using | |||
| table references, it MUST emit a Header Acknowledgement instruction | representations containing dynamic table references, it MUST emit a | |||
| (Section 4.4.1). A stream may carry multiple header blocks in the | Section Acknowledgement instruction (Section 4.4.1). A stream may | |||
| case of intermediate responses, trailers, and pushed requests. The | carry multiple field sections in the case of intermediate responses, | |||
| encoder interprets each Header Acknowledgement instruction as | trailers, and pushed requests. The encoder interprets each | |||
| acknowledging the earliest unacknowledged header block containing | Section Acknowledgement instruction as acknowledging the earliest | |||
| dynamic table references sent on the given stream. | unacknowledged field section containing dynamic table references sent | |||
| on the given stream. | ||||
| 2.2.2.2. Abandonment of a Stream | 2.2.2.2. Abandonment of a Stream | |||
| When an endpoint receives a stream reset before the end of a stream | When an endpoint receives a stream reset before the end of a stream | |||
| or before all header blocks are processed on that stream, or when it | or before all encoded field sections are processed on that stream, or | |||
| abandons reading of a stream, it generates a Stream Cancellation | when it abandons reading of a stream, it generates a Stream | |||
| instruction; see Section 4.4.2. This signals to the encoder that all | Cancellation instruction; see Section 4.4.2. This signals to the | |||
| references to the dynamic table on that stream are no longer | encoder that all references to the dynamic table on that stream are | |||
| outstanding. A decoder with a maximum dynamic table capacity | no longer outstanding. A decoder with a maximum dynamic table | |||
| (Section 3.2.3) equal to zero MAY omit sending Stream Cancellations, | capacity (Section 3.2.3) equal to zero MAY omit sending Stream | |||
| because the encoder cannot have any dynamic table references. An | Cancellations, because the encoder cannot have any dynamic table | |||
| encoder cannot infer from this instruction that any updates to the | references. An encoder cannot infer from this instruction that any | |||
| dynamic table have been received. | updates to the dynamic table have been received. | |||
| The Header Acknowledgement and Stream Cancellation instructions | The Section Acknowledgement and Stream Cancellation instructions | |||
| permit the encoder to remove references to entries in the dynamic | permit the encoder to remove references to entries in the dynamic | |||
| table. When an entry with absolute index lower than the Known | table. When an entry with absolute index lower than the Known | |||
| Received Count has zero references, then it is considered evictable; | Received Count has zero references, then it is considered evictable; | |||
| see Section 2.1.2. | see Section 2.1.1. | |||
| 2.2.2.3. New Table Entries | 2.2.2.3. New Table Entries | |||
| After receiving new table entries on the encoder stream, the decoder | After receiving new table entries on the encoder stream, the decoder | |||
| chooses when to emit Insert Count Increment instructions; see | chooses when to emit Insert Count Increment instructions; see | |||
| Section 4.4.3. Emitting this instruction after adding each new | Section 4.4.3. Emitting this instruction after adding each new | |||
| dynamic table entry will provide the timeliest feedback to the | dynamic table entry will provide the timeliest feedback to the | |||
| encoder, but could be redundant with other decoder feedback. By | encoder, but could be redundant with other decoder feedback. By | |||
| delaying an Insert Count Increment instruction, the decoder might be | delaying an Insert Count Increment instruction, the decoder might be | |||
| able to coalesce multiple Insert Count Increment instructions, or | able to coalesce multiple Insert Count Increment instructions, or | |||
| replace them entirely with Header Acknowledgements; see | replace them entirely with Section Acknowledgements; see | |||
| Section 4.4.1. However, delaying too long may lead to compression | Section 4.4.1. However, delaying too long may lead to compression | |||
| inefficiencies if the encoder waits for an entry to be acknowledged | inefficiencies if the encoder waits for an entry to be acknowledged | |||
| before using it. | before using it. | |||
| 2.2.3. Invalid References | 2.2.3. Invalid References | |||
| If the decoder encounters a reference in a header block | If the decoder encounters a reference in a field line representation | |||
| representation to a dynamic table entry which has already been | to a dynamic table entry which has already been evicted or which has | |||
| evicted or which has an absolute index greater than or equal to the | an absolute index greater than or equal to the declared Required | |||
| declared Required Insert Count (Section 4.5.1), it MUST treat this as | Insert Count (Section 4.5.1), it MUST treat this as a connection | |||
| a connection error of type QPACK_DECOMPRESSION_FAILED. | error of type QPACK_DECOMPRESSION_FAILED. | |||
| If the decoder encounters a reference in an encoder instruction to a | If the decoder encounters a reference in an encoder instruction to a | |||
| dynamic table entry which has already been evicted, it MUST treat | dynamic table entry which has already been evicted, it MUST treat | |||
| this as a connection error of type QPACK_ENCODER_STREAM_ERROR. | this as a connection error of type QPACK_ENCODER_STREAM_ERROR. | |||
| 3. Header Tables | 3. Reference Tables | |||
| Unlike in HPACK, entries in the QPACK static and dynamic tables are | Unlike in HPACK, entries in the QPACK static and dynamic tables are | |||
| addressed separately. The following sections describe how entries in | addressed separately. The following sections describe how entries in | |||
| each table are addressed. | each table are addressed. | |||
| 3.1. Static Table | 3.1. Static Table | |||
| The static table consists of a predefined static list of header | The static table consists of a predefined static list of field lines, | |||
| fields, each of which has a fixed index over time. Its entries are | each of which has a fixed index over time. Its entries are defined | |||
| defined in Appendix A. | in Appendix A. | |||
| All entries in the static table have a name and a value. However, | All entries in the static table have a name and a value. However, | |||
| values can be empty (that is, have a length of 0). Each entry is | values can be empty (that is, have a length of 0). Each entry is | |||
| identified by a unique index. | identified by a unique index. | |||
| Note that the QPACK static table is indexed from 0, whereas the HPACK | Note that the QPACK static table is indexed from 0, whereas the HPACK | |||
| static table is indexed from 1. | static table is indexed from 1. | |||
| When the decoder encounters an invalid static table index in a header | When the decoder encounters an invalid static table index in a field | |||
| block representation it MUST treat this as a connection error of type | line representation it MUST treat this as a connection error of type | |||
| QPACK_DECOMPRESSION_FAILED. If this index is received on the encoder | QPACK_DECOMPRESSION_FAILED. If this index is received on the encoder | |||
| stream, this MUST be treated as a connection error of type | stream, this MUST be treated as a connection error of type | |||
| QPACK_ENCODER_STREAM_ERROR. | QPACK_ENCODER_STREAM_ERROR. | |||
| 3.2. Dynamic Table | 3.2. Dynamic Table | |||
| The dynamic table consists of a list of header fields maintained in | The dynamic table consists of a list of field lines maintained in | |||
| first-in, first-out order. Each HTTP/3 endpoint holds a dynamic | first-in, first-out order. Each HTTP/3 endpoint holds a dynamic | |||
| table that is initially empty. Entries are added by encoder | table that is initially empty. Entries are added by encoder | |||
| instructions received on the encoder stream; see Section 4.3. | instructions received on the encoder stream; see Section 4.3. | |||
| The dynamic table can contain duplicate entries (i.e., entries with | The dynamic table can contain duplicate entries (i.e., entries with | |||
| the same name and same value). Therefore, duplicate entries MUST NOT | the same name and same value). Therefore, duplicate entries MUST NOT | |||
| be treated as an error by the decoder. | be treated as an error by the decoder. | |||
| Dynamic table entries can have empty values. | Dynamic table entries can have empty values. | |||
| skipping to change at page 12, line 17 ¶ | skipping to change at page 12, line 28 ¶ | |||
| The encoder sets the capacity of the dynamic table, which serves as | The encoder sets the capacity of the dynamic table, which serves as | |||
| the upper limit on its size. The initial capacity of the dynamic | the upper limit on its size. The initial capacity of the dynamic | |||
| table is zero. The encoder sends a Set Dynamic Table Capacity | table is zero. The encoder sends a Set Dynamic Table Capacity | |||
| instruction (Section 4.3.1) with a non-zero capacity to begin using | instruction (Section 4.3.1) with a non-zero capacity to begin using | |||
| the dynamic table. | the dynamic table. | |||
| Before a new entry is added to the dynamic table, entries are evicted | Before a new entry is added to the dynamic table, entries are evicted | |||
| from the end of the dynamic table until the size of the dynamic table | from the end of the dynamic table until the size of the dynamic table | |||
| is less than or equal to (table capacity - size of new entry). The | is less than or equal to (table capacity - size of new entry). The | |||
| encoder MUST NOT cause a dynamic table entry to be evicted unless | encoder MUST NOT cause a dynamic table entry to be evicted unless | |||
| that entry is evictable; see Section 2.1.2. The new entry is then | that entry is evictable; see Section 2.1.1. The new entry is then | |||
| added to the table. It is an error if the encoder attempts to add an | added to the table. It is an error if the encoder attempts to add an | |||
| entry that is larger than the dynamic table capacity; the decoder | entry that is larger than the dynamic table capacity; the decoder | |||
| MUST treat this as a connection error of type | MUST treat this as a connection error of type | |||
| QPACK_ENCODER_STREAM_ERROR. | QPACK_ENCODER_STREAM_ERROR. | |||
| A new entry can reference an entry in the dynamic table that will be | A new entry can reference an entry in the dynamic table that will be | |||
| evicted when adding this new entry into the dynamic table. | evicted when adding this new entry into the dynamic table. | |||
| Implementations are cautioned to avoid deleting the referenced name | Implementations are cautioned to avoid deleting the referenced name | |||
| or value if the referenced entry is evicted from the dynamic table | or value if the referenced entry is evicted from the dynamic table | |||
| prior to inserting the new entry. | prior to inserting the new entry. | |||
| skipping to change at page 13, line 47 ¶ | skipping to change at page 14, line 19 ¶ | |||
| +-----+---------------+-------+ | +-----+---------------+-------+ | |||
| ^ | | ^ | | |||
| | V | | V | |||
| Insertion Point Dropping Point | Insertion Point Dropping Point | |||
| n = count of entries inserted | n = count of entries inserted | |||
| d = count of entries dropped | d = count of entries dropped | |||
| Figure 2: Example Dynamic Table Indexing - Encoder Stream | Figure 2: Example Dynamic Table Indexing - Encoder Stream | |||
| Unlike in encoder instructions, relative indices in header block | Unlike in encoder instructions, relative indices in field line | |||
| representations are relative to the Base at the beginning of the | representations are relative to the Base at the beginning of the | |||
| header block; see Section 4.5.1. This ensures that references are | encoded field section; see Section 4.5.1. This ensures that | |||
| stable even if header blocks and dynamic table updates are processed | references are stable even if encoded field sections and dynamic | |||
| out of order. | table updates are processed out of order. | |||
| In a header block a relative index of "0" refers to the entry with | In a field line representation, a relative index of "0" refers to the | |||
| absolute index equal to Base - 1. | entry with absolute index equal to Base - 1. | |||
| Base | Base | |||
| | | | | |||
| V | V | |||
| +-----+-----+-----+-----+-------+ | +-----+-----+-----+-----+-------+ | |||
| | n-1 | n-2 | n-3 | ... | d | Absolute Index | | n-1 | n-2 | n-3 | ... | d | Absolute Index | |||
| +-----+-----+ - +-----+ - + | +-----+-----+ - +-----+ - + | |||
| | 0 | ... | n-d-3 | Relative Index | | 0 | ... | n-d-3 | Relative Index | |||
| +-----+-----+-------+ | +-----+-----+-------+ | |||
| n = count of entries inserted | n = count of entries inserted | |||
| d = count of entries dropped | d = count of entries dropped | |||
| In this example, Base = n - 2 | In this example, Base = n - 2 | |||
| Figure 3: Example Dynamic Table Indexing - Relative Index in | Figure 3: Example Dynamic Table Indexing - Relative Index in | |||
| Header Block | Representation | |||
| 3.2.6. Post-Base Indexing | 3.2.6. Post-Base Indexing | |||
| Post-Base indices are used in header block instructions for entries | Post-Base indices are used in field line representations for entries | |||
| with absolute indices greater than or equal to Base, starting at 0 | with absolute indices greater than or equal to Base, starting at 0 | |||
| for the entry with absolute index equal to Base, and increasing in | for the entry with absolute index equal to Base, and increasing in | |||
| the same direction as the absolute index. | the same direction as the absolute index. | |||
| Post-Base indices allow an encoder to process a header block in a | Post-Base indices allow an encoder to process a field section in a | |||
| single pass and include references to entries added while processing | single pass and include references to entries added while processing | |||
| this (or other) header blocks. | this (or other) field sections. | |||
| Base | Base | |||
| | | | | |||
| V | V | |||
| +-----+-----+-----+-----+-----+ | +-----+-----+-----+-----+-----+ | |||
| | n-1 | n-2 | n-3 | ... | d | Absolute Index | | n-1 | n-2 | n-3 | ... | d | Absolute Index | |||
| +-----+-----+-----+-----+-----+ | +-----+-----+-----+-----+-----+ | |||
| | 1 | 0 | Post-Base Index | | 1 | 0 | Post-Base Index | |||
| +-----+-----+ | +-----+-----+ | |||
| n = count of entries inserted | n = count of entries inserted | |||
| d = count of entries dropped | d = count of entries dropped | |||
| In this example, Base = n - 2 | In this example, Base = n - 2 | |||
| Figure 4: Example Dynamic Table Indexing - Post-Base Index in | Figure 4: Example Dynamic Table Indexing - Post-Base Index in | |||
| Header Block | Representation | |||
| 4. Wire Format | 4. Wire Format | |||
| 4.1. Primitives | 4.1. Primitives | |||
| 4.1.1. Prefixed Integers | 4.1.1. Prefixed Integers | |||
| The prefixed integer from Section 5.1 of [RFC7541] is used heavily | The prefixed integer from Section 5.1 of [RFC7541] is used heavily | |||
| throughout this document. The format from [RFC7541] is used | throughout this document. The format from [RFC7541] is used | |||
| unmodified. Note, however, that QPACK uses some prefix sizes not | unmodified. Note, however, that QPACK uses some prefix sizes not | |||
| actually used in HPACK. | actually used in HPACK. | |||
| QPACK implementations MUST be able to decode integers up to and | QPACK implementations MUST be able to decode integers up to and | |||
| skipping to change at page 15, line 43 ¶ | skipping to change at page 16, line 20 ¶ | |||
| literal is unmodified. | literal is unmodified. | |||
| A string literal without a prefix length noted is an 8-bit prefix | A string literal without a prefix length noted is an 8-bit prefix | |||
| string literal and follows the definitions in [RFC7541] without | string literal and follows the definitions in [RFC7541] without | |||
| modification. | modification. | |||
| 4.2. Encoder and Decoder Streams | 4.2. Encoder and Decoder Streams | |||
| QPACK defines two unidirectional stream types: | QPACK defines two unidirectional stream types: | |||
| * An encoder stream is a unidirectional stream of type "0x02". It | * An encoder stream is a unidirectional stream of type 0x02. It | |||
| carries an unframed sequence of encoder instructions from encoder | carries an unframed sequence of encoder instructions from encoder | |||
| to decoder. | to decoder. | |||
| * A decoder stream is a unidirectional stream of type "0x03". It | * A decoder stream is a unidirectional stream of type 0x03. It | |||
| carries an unframed sequence of decoder instructions from decoder | carries an unframed sequence of decoder instructions from decoder | |||
| to encoder. | to encoder. | |||
| HTTP/3 endpoints contain a QPACK encoder and decoder. Each endpoint | HTTP/3 endpoints contain a QPACK encoder and decoder. Each endpoint | |||
| MUST initiate at most one encoder stream and at most one decoder | MUST initiate at most one encoder stream and at most one decoder | |||
| stream. Receipt of a second instance of either stream type MUST be | stream. Receipt of a second instance of either stream type MUST be | |||
| treated as a connection error of type HTTP_STREAM_CREATION_ERROR. | treated as a connection error of type H3_STREAM_CREATION_ERROR. | |||
| These streams MUST NOT be closed. Closure of either unidirectional | These streams MUST NOT be closed. Closure of either unidirectional | |||
| stream type MUST be treated as a connection error of type | stream type MUST be treated as a connection error of type | |||
| HTTP_CLOSED_CRITICAL_STREAM. | H3_CLOSED_CRITICAL_STREAM. | |||
| An endpoint MAY avoid creating an encoder stream if it's not going to | An endpoint MAY avoid creating an encoder stream if it's not going to | |||
| be used (for example if its encoder doesn't wish to use the dynamic | be used (for example if its encoder doesn't wish to use the dynamic | |||
| table, or if the maximum size of the dynamic table permitted by the | table, or if the maximum size of the dynamic table permitted by the | |||
| peer is zero). | peer is zero). | |||
| An endpoint MAY avoid creating a decoder stream if its decoder sets | An endpoint MAY avoid creating a decoder stream if its decoder sets | |||
| the maximum capacity of the dynamic table to zero. | the maximum capacity of the dynamic table to zero. | |||
| An endpoint MUST allow its peer to create an encoder stream and a | An endpoint MUST allow its peer to create an encoder stream and a | |||
| skipping to change at page 17, line 11 ¶ | skipping to change at page 17, line 41 ¶ | |||
| The new capacity MUST be lower than or equal to the limit described | The new capacity MUST be lower than or equal to the limit described | |||
| in Section 3.2.3. In HTTP/3, this limit is the value of the | in Section 3.2.3. In HTTP/3, this limit is the value of the | |||
| SETTINGS_QPACK_MAX_TABLE_CAPACITY parameter (Section 5) received from | SETTINGS_QPACK_MAX_TABLE_CAPACITY parameter (Section 5) received from | |||
| the decoder. The decoder MUST treat a new dynamic table capacity | the decoder. The decoder MUST treat a new dynamic table capacity | |||
| value that exceeds this limit as a connection error of type | value that exceeds this limit as a connection error of type | |||
| QPACK_ENCODER_STREAM_ERROR. | QPACK_ENCODER_STREAM_ERROR. | |||
| Reducing the dynamic table capacity can cause entries to be evicted; | Reducing the dynamic table capacity can cause entries to be evicted; | |||
| see Section 3.2.2. This MUST NOT cause the eviction of entries which | see Section 3.2.2. This MUST NOT cause the eviction of entries which | |||
| are not evictable; see Section 2.1.2. Changing the capacity of the | are not evictable; see Section 2.1.1. Changing the capacity of the | |||
| dynamic table is not acknowledged as this instruction does not insert | dynamic table is not acknowledged as this instruction does not insert | |||
| an entry. | an entry. | |||
| 4.3.2. Insert With Name Reference | 4.3.2. Insert With Name Reference | |||
| An encoder adds an entry to the dynamic table where the header field | An encoder adds an entry to the dynamic table where the field name | |||
| name matches the header field name of an entry stored in the static | matches the field name of an entry stored in the static or the | |||
| or the dynamic table using an instruction that starts with the '1' | dynamic table using an instruction that starts with the '1' one-bit | |||
| one-bit pattern. The second ('T') bit indicates whether the | pattern. The second ('T') bit indicates whether the reference is to | |||
| reference is to the static or dynamic table. The 6-bit prefix | the static or dynamic table. The 6-bit prefix integer | |||
| integer (Section 4.1.1) that follows is used to locate the table | (Section 4.1.1) that follows is used to locate the table entry for | |||
| entry for the header name. When T=1, the number represents the | the field name. When T=1, the number represents the static table | |||
| static table index; when T=0, the number is the relative index of the | index; when T=0, the number is the relative index of the entry in the | |||
| entry in the dynamic table. | dynamic table. | |||
| The header name reference is followed by the header field value | The field name reference is followed by the field value represented | |||
| represented as a string literal; see Section 4.1.2. | as a string literal; see Section 4.1.2. | |||
| 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | |||
| +---+---+---+---+---+---+---+---+ | +---+---+---+---+---+---+---+---+ | |||
| | 1 | T | Name Index (6+) | | | 1 | T | Name Index (6+) | | |||
| +---+---+-----------------------+ | +---+---+-----------------------+ | |||
| | H | Value Length (7+) | | | H | Value Length (7+) | | |||
| +---+---------------------------+ | +---+---------------------------+ | |||
| | Value String (Length bytes) | | | Value String (Length bytes) | | |||
| +-------------------------------+ | +-------------------------------+ | |||
| Figure 6: Insert Header Field -- Indexed Name | Figure 6: Insert Field Line -- Indexed Name | |||
| 4.3.3. Insert Without Name Reference | 4.3.3. Insert Without Name Reference | |||
| An encoder adds an entry to the dynamic table where both the header | An encoder adds an entry to the dynamic table where both the field | |||
| field name and the header field value are represented as string | name and the field value are represented as string literals using an | |||
| literals using an instruction that starts with the '01' two-bit | instruction that starts with the '01' two-bit pattern. | |||
| pattern. | ||||
| This is followed by the name represented as a 6-bit prefix string | This is followed by the name represented as a 6-bit prefix string | |||
| literal, and the value represented as an 8-bit prefix string literal; | literal, and the value represented as an 8-bit prefix string literal; | |||
| see Section 4.1.2. | see Section 4.1.2. | |||
| 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | |||
| +---+---+---+---+---+---+---+---+ | +---+---+---+---+---+---+---+---+ | |||
| | 0 | 1 | H | Name Length (5+) | | | 0 | 1 | H | Name Length (5+) | | |||
| +---+---+---+-------------------+ | +---+---+---+-------------------+ | |||
| | Name String (Length bytes) | | | Name String (Length bytes) | | |||
| +---+---------------------------+ | +---+---------------------------+ | |||
| | H | Value Length (7+) | | | H | Value Length (7+) | | |||
| +---+---------------------------+ | +---+---------------------------+ | |||
| | Value String (Length bytes) | | | Value String (Length bytes) | | |||
| +-------------------------------+ | +-------------------------------+ | |||
| Figure 7: Insert Header Field -- New Name | Figure 7: Insert Field Line -- New Name | |||
| 4.3.4. Duplicate | 4.3.4. Duplicate | |||
| An encoder duplicates an existing entry in the dynamic table using an | An encoder duplicates an existing entry in the dynamic table using an | |||
| instruction that begins with the '000' three-bit pattern. This is | instruction that begins with the '000' three-bit pattern. This is | |||
| followed by the relative index of the existing entry represented as | followed by the relative index of the existing entry represented as | |||
| an integer with a 5-bit prefix; see Section 4.1.1. | an integer with a 5-bit prefix; see Section 4.1.1. | |||
| 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | |||
| +---+---+---+---+---+---+---+---+ | +---+---+---+---+---+---+---+---+ | |||
| skipping to change at page 18, line 40 ¶ | skipping to change at page 19, line 20 ¶ | |||
| Figure 8: Duplicate | Figure 8: Duplicate | |||
| The existing entry is re-inserted into the dynamic table without | The existing entry is re-inserted into the dynamic table without | |||
| resending either the name or the value. This is useful to avoid | resending either the name or the value. This is useful to avoid | |||
| adding a reference to an older entry, which might block inserting new | adding a reference to an older entry, which might block inserting new | |||
| entries. | entries. | |||
| 4.4. Decoder Instructions | 4.4. Decoder Instructions | |||
| A decoder sends decoder instructions on the decoder stream to inform | A decoder sends decoder instructions on the decoder stream to inform | |||
| the encoder about the processing of header blocks and table updates | the encoder about the processing of field sections and table updates | |||
| to ensure consistency of the dynamic table. | to ensure consistency of the dynamic table. | |||
| This section specifies the following decoder instructions. | This section specifies the following decoder instructions. | |||
| 4.4.1. Header Acknowledgement | 4.4.1. Section Acknowledgement | |||
| After processing a header block whose declared Required Insert Count | After processing an encoded field section whose declared Required | |||
| is not zero, the decoder emits a Header Acknowledgement instruction. | Insert Count is not zero, the decoder emits a Section Acknowledgement | |||
| The instruction begins with the '1' one-bit pattern which is followed | instruction. The instruction begins with the '1' one-bit pattern | |||
| by the header block's associated stream ID encoded as a 7-bit prefix | which is followed by the field section's associated stream ID encoded | |||
| integer; see Section 4.1.1. | as a 7-bit prefix integer; see Section 4.1.1. | |||
| This instruction is used as described in Section 2.1.5 and in | This instruction is used as described in Section 2.1.4 and in | |||
| Section 2.2.2. | Section 2.2.2. | |||
| 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | |||
| +---+---+---+---+---+---+---+---+ | +---+---+---+---+---+---+---+---+ | |||
| | 1 | Stream ID (7+) | | | 1 | Stream ID (7+) | | |||
| +---+---------------------------+ | +---+---------------------------+ | |||
| Figure 9: Header Acknowledgement | Figure 9: Section Acknowledgement | |||
| If an encoder receives a Header Acknowledgement instruction referring | If an encoder receives a Section Acknowledgement instruction | |||
| to a stream on which every header block with a non-zero Required | referring to a stream on which every encoded field section with a | |||
| Insert Count has already been acknowledged, that MUST be treated as a | non-zero Required Insert Count has already been acknowledged, that | |||
| connection error of type QPACK_DECODER_STREAM_ERROR. | MUST be treated as a connection error of type | |||
| QPACK_DECODER_STREAM_ERROR. | ||||
| The Header Acknowledgement instruction might increase the Known | The Section Acknowledgement instruction might increase the Known | |||
| Received Count; see Section 2.1.5. | Received Count; see Section 2.1.4. | |||
| 4.4.2. Stream Cancellation | 4.4.2. Stream Cancellation | |||
| When a stream is reset or reading is abandoned, the decoder emits a | When a stream is reset or reading is abandoned, the decoder emits a | |||
| Stream Cancellation instruction. The instruction begins with the | Stream Cancellation instruction. The instruction begins with the | |||
| '01' two-bit pattern, which is followed by the stream ID of the | '01' two-bit pattern, which is followed by the stream ID of the | |||
| affected stream encoded as a 6-bit prefix integer. | affected stream encoded as a 6-bit prefix integer. | |||
| This instruction is used as described in Section 2.2.2. | This instruction is used as described in Section 2.2.2. | |||
| skipping to change at page 19, line 43 ¶ | skipping to change at page 20, line 25 ¶ | |||
| +---+---+---+---+---+---+---+---+ | +---+---+---+---+---+---+---+---+ | |||
| | 0 | 1 | Stream ID (6+) | | | 0 | 1 | Stream ID (6+) | | |||
| +---+---+-----------------------+ | +---+---+-----------------------+ | |||
| Figure 10: Stream Cancellation | Figure 10: Stream Cancellation | |||
| 4.4.3. Insert Count Increment | 4.4.3. Insert Count Increment | |||
| The Insert Count Increment instruction begins with the '00' two-bit | The Insert Count Increment instruction begins with the '00' two-bit | |||
| pattern, followed by the Increment encoded as a 6-bit prefix integer. | pattern, followed by the Increment encoded as a 6-bit prefix integer. | |||
| This instruction increases the Known Received Count (Section 2.1.5) | This instruction increases the Known Received Count (Section 2.1.4) | |||
| by the value of the Increment parameter. The decoder should send an | by the value of the Increment parameter. The decoder should send an | |||
| Increment value that increases the Known Received Count to the total | Increment value that increases the Known Received Count to the total | |||
| number of dynamic table insertions and duplications processed so far. | number of dynamic table insertions and duplications processed so far. | |||
| 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | |||
| +---+---+---+---+---+---+---+---+ | +---+---+---+---+---+---+---+---+ | |||
| | 0 | 0 | Increment (6+) | | | 0 | 0 | Increment (6+) | | |||
| +---+---+-----------------------+ | +---+---+-----------------------+ | |||
| Figure 11: Insert Count Increment | Figure 11: Insert Count Increment | |||
| An encoder that receives an Increment field equal to zero, or one | An encoder that receives an Increment field equal to zero, or one | |||
| that increases the Known Received Count beyond what the encoder has | that increases the Known Received Count beyond what the encoder has | |||
| sent MUST treat this as a connection error of type | sent MUST treat this as a connection error of type | |||
| QPACK_DECODER_STREAM_ERROR. | QPACK_DECODER_STREAM_ERROR. | |||
| 4.5. Header Block Representations | 4.5. Field Line Representations | |||
| A header block consists of a prefix and a possibly empty sequence of | An encoded field section consists of a prefix and a possibly empty | |||
| representations defined in this section. Each representation | sequence of representations defined in this section. Each | |||
| corresponds to a single header field. These representations | representation corresponds to a single field line. These | |||
| reference the static table or the dynamic table in a particular | representations reference the static table or the dynamic table in a | |||
| state, but do not modify that state. | particular state, but do not modify that state. | |||
| Header blocks are carried in frames on streams defined by the | Encoded field sections are carried in frames on streams defined by | |||
| enclosing protocol. | the enclosing protocol. | |||
| 4.5.1. Header Block Prefix | 4.5.1. Encoded Field Section Prefix | |||
| Each header block is prefixed with two integers. The Required Insert | Each encoded field section is prefixed with two integers. The | |||
| Count is encoded as an integer with an 8-bit prefix after the | Required Insert Count is encoded as an integer with an 8-bit prefix | |||
| encoding described in Section 4.5.1.1). The Base is encoded as a | after the encoding described in Section 4.5.1.1). The Base is | |||
| sign bit ('S') and a Delta Base value with a 7-bit prefix; see | encoded as a sign bit ('S') and a Delta Base value with a 7-bit | |||
| Section 4.5.1.2. | prefix; see Section 4.5.1.2. | |||
| 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | |||
| +---+---+---+---+---+---+---+---+ | +---+---+---+---+---+---+---+---+ | |||
| | Required Insert Count (8+) | | | Required Insert Count (8+) | | |||
| +---+---------------------------+ | +---+---------------------------+ | |||
| | S | Delta Base (7+) | | | S | Delta Base (7+) | | |||
| +---+---------------------------+ | +---+---------------------------+ | |||
| | Compressed Headers ... | | Encoded Field Lines ... | |||
| +-------------------------------+ | +-------------------------------+ | |||
| Figure 12: Header Block | Figure 12: Encoded Field Section | |||
| 4.5.1.1. Required Insert Count | 4.5.1.1. Required Insert Count | |||
| Required Insert Count identifies the state of the dynamic table | Required Insert Count identifies the state of the dynamic table | |||
| needed to process the header block. Blocking decoders use the | needed to process the encoded field section. Blocking decoders use | |||
| Required Insert Count to determine when it is safe to process the | the Required Insert Count to determine when it is safe to process the | |||
| rest of the block. | rest of the field section. | |||
| The encoder transforms the Required Insert Count as follows before | The encoder transforms the Required Insert Count as follows before | |||
| encoding: | encoding: | |||
| if ReqInsertCount == 0: | if ReqInsertCount == 0: | |||
| EncInsertCount = 0 | EncInsertCount = 0 | |||
| else: | else: | |||
| EncInsertCount = (ReqInsertCount mod (2 * MaxEntries)) + 1 | EncInsertCount = (ReqInsertCount mod (2 * MaxEntries)) + 1 | |||
| Here "MaxEntries" is the maximum number of entries that the dynamic | Here "MaxEntries" is the maximum number of entries that the dynamic | |||
| skipping to change at page 22, line 31 ¶ | skipping to change at page 22, line 40 ¶ | |||
| if ReqInsertCount <= FullRange: | if ReqInsertCount <= FullRange: | |||
| Error | Error | |||
| ReqInsertCount -= FullRange | ReqInsertCount -= FullRange | |||
| # Value of 0 must be encoded as 0. | # Value of 0 must be encoded as 0. | |||
| if ReqInsertCount == 0: | if ReqInsertCount == 0: | |||
| Error | Error | |||
| For example, if the dynamic table is 100 bytes, then the Required | For example, if the dynamic table is 100 bytes, then the Required | |||
| Insert Count will be encoded modulo 6. If a decoder has received 10 | Insert Count will be encoded modulo 6. If a decoder has received 10 | |||
| inserts, then an encoded value of 3 indicates that the Required | inserts, then an encoded value of 4 indicates that the Required | |||
| Insert Count is 9 for the header block. | Insert Count is 9 for the field section. | |||
| 4.5.1.2. Base | 4.5.1.2. Base | |||
| The "Base" is used to resolve references in the dynamic table as | The Base is used to resolve references in the dynamic table as | |||
| described in Section 3.2.5. | described in Section 3.2.5. | |||
| To save space, the Base is encoded relative to the Required Insert | To save space, the Base is encoded relative to the Required Insert | |||
| Count using a one-bit sign ('S') and the "Delta Base" value. A sign | Count using a one-bit sign ('S') and the Delta Base value. A sign | |||
| bit of 0 indicates that the Base is greater than or equal to the | bit of 0 indicates that the Base is greater than or equal to the | |||
| value of the Required Insert Count; the decoder adds the value of | value of the Required Insert Count; the decoder adds the value of | |||
| Delta Base to the Required Insert Count to determine the value of the | Delta Base to the Required Insert Count to determine the value of the | |||
| Base. A sign bit of 1 indicates that the Base is less than the | Base. A sign bit of 1 indicates that the Base is less than the | |||
| Required Insert Count; the decoder subtracts the value of Delta Base | Required Insert Count; the decoder subtracts the value of Delta Base | |||
| from the Required Insert Count and also subtracts one to determine | from the Required Insert Count and also subtracts one to determine | |||
| the value of the Base. That is: | the value of the Base. That is: | |||
| if S == 0: | if S == 0: | |||
| Base = ReqInsertCount + DeltaBase | Base = ReqInsertCount + DeltaBase | |||
| else: | else: | |||
| Base = ReqInsertCount - DeltaBase - 1 | Base = ReqInsertCount - DeltaBase - 1 | |||
| A single-pass encoder determines the Base before encoding a header | A single-pass encoder determines the Base before encoding a field | |||
| block. If the encoder inserted entries in the dynamic table while | section. If the encoder inserted entries in the dynamic table while | |||
| encoding the header block, Required Insert Count will be greater than | encoding the field section, Required Insert Count will be greater | |||
| the Base, so the encoded difference is negative and the sign bit is | than the Base, so the encoded difference is negative and the sign bit | |||
| set to 1. If the header block did not reference the most recent | is set to 1. If the field section was not encoded using | |||
| entry in the table and did not insert any new entries, the Base will | representations which reference the most recent entry in the table | |||
| be greater than the Required Insert Count, so the delta will be | and did not insert any new entries, the Base will be greater than the | |||
| positive and the sign bit is set to 0. | Required Insert Count, so the delta will be positive and the sign bit | |||
| is set to 0. | ||||
| An encoder that produces table updates before encoding a header block | An encoder that produces table updates before encoding a field | |||
| might set Base to the value of Required Insert Count. In such case, | section might set Base to the value of Required Insert Count. In | |||
| both the sign bit and the Delta Base will be set to zero. | such case, both the sign bit and the Delta Base will be set to zero. | |||
| A header block that does not reference the dynamic table can use any | A field section that was encoded without references to the dynamic | |||
| value for the Base; setting Delta Base to zero is one of the most | table can use any value for the Base; setting Delta Base to zero is | |||
| efficient encodings. | one of the most efficient encodings. | |||
| For example, with a Required Insert Count of 9, a decoder receives an | For example, with a Required Insert Count of 9, a decoder receives an | |||
| S bit of 1 and a Delta Base of 2. This sets the Base to 6 and | S bit of 1 and a Delta Base of 2. This sets the Base to 6 and | |||
| enables post-base indexing for three entries. In this example, a | enables post-base indexing for three entries. In this example, a | |||
| relative index of 1 refers to the 5th entry that was added to the | relative index of 1 refers to the 5th entry that was added to the | |||
| table; a post-base index of 1 refers to the 8th entry. | table; a post-base index of 1 refers to the 8th entry. | |||
| 4.5.2. Indexed Header Field | 4.5.2. Indexed Field Line | |||
| An indexed header field representation identifies an entry in the | An indexed field line representation identifies an entry in the | |||
| static table, or an entry in the dynamic table with an absolute index | static table, or an entry in the dynamic table with an absolute index | |||
| less than the value of the Base. | less than the value of the Base. | |||
| 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | |||
| +---+---+---+---+---+---+---+---+ | +---+---+---+---+---+---+---+---+ | |||
| | 1 | T | Index (6+) | | | 1 | T | Index (6+) | | |||
| +---+---+-----------------------+ | +---+---+-----------------------+ | |||
| Figure 13: Indexed Header Field | Figure 13: Indexed Field Line | |||
| This representation starts with the '1' 1-bit pattern, followed by | This representation starts with the '1' 1-bit pattern, followed by | |||
| the 'T' bit indicating whether the reference is into the static or | the 'T' bit indicating whether the reference is into the static or | |||
| dynamic table. The 6-bit prefix integer (Section 4.1.1) that follows | dynamic table. The 6-bit prefix integer (Section 4.1.1) that follows | |||
| is used to locate the table entry for the header field. When T=1, | is used to locate the table entry for the field line. When T=1, the | |||
| the number represents the static table index; when T=0, the number is | number represents the static table index; when T=0, the number is the | |||
| the relative index of the entry in the dynamic table. | relative index of the entry in the dynamic table. | |||
| 4.5.3. Indexed Header Field With Post-Base Index | 4.5.3. Indexed Field Line With Post-Base Index | |||
| An indexed header field with post-base index representation | An indexed field line with post-base index representation identifies | |||
| identifies an entry in the dynamic table with an absolute index | an entry in the dynamic table with an absolute index greater than or | |||
| greater than or equal to the value of the Base. | equal to the value of the Base. | |||
| 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | |||
| +---+---+---+---+---+---+---+---+ | +---+---+---+---+---+---+---+---+ | |||
| | 0 | 0 | 0 | 1 | Index (4+) | | | 0 | 0 | 0 | 1 | Index (4+) | | |||
| +---+---+---+---+---------------+ | +---+---+---+---+---------------+ | |||
| Figure 14: Indexed Header Field with Post-Base Index | Figure 14: Indexed Field Line with Post-Base Index | |||
| This representation starts with the '0001' 4-bit pattern. This is | This representation starts with the '0001' 4-bit pattern. This is | |||
| followed by the post-base index (Section 3.2.6) of the matching | followed by the post-base index (Section 3.2.6) of the matching field | |||
| header field, represented as an integer with a 4-bit prefix; see | line, represented as an integer with a 4-bit prefix; see | |||
| Section 4.1.1. | Section 4.1.1. | |||
| 4.5.4. Literal Header Field With Name Reference | 4.5.4. Literal Field Line With Name Reference | |||
| A literal header field with name reference representation encodes a | A literal field line with name reference representation encodes a | |||
| header field where the header field name matches the header field | field line where the field name matches the field name of an entry in | |||
| name of an entry in the static table, or the header field name of an | the static table, or the field name of an entry in the dynamic table | |||
| entry in the dynamic table with an absolute index less than the value | with an absolute index less than the value of the Base. | |||
| of the Base. | ||||
| 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | |||
| +---+---+---+---+---+---+---+---+ | +---+---+---+---+---+---+---+---+ | |||
| | 0 | 1 | N | T |Name Index (4+)| | | 0 | 1 | N | T |Name Index (4+)| | |||
| +---+---+---+---+---------------+ | +---+---+---+---+---------------+ | |||
| | H | Value Length (7+) | | | H | Value Length (7+) | | |||
| +---+---------------------------+ | +---+---------------------------+ | |||
| | Value String (Length bytes) | | | Value String (Length bytes) | | |||
| +-------------------------------+ | +-------------------------------+ | |||
| Figure 15: Literal Header Field With Name Reference | Figure 15: Literal Field Line With Name Reference | |||
| This representation starts with the '01' two-bit pattern. The | This representation starts with the '01' two-bit pattern. The | |||
| following bit, 'N', indicates whether an intermediary is permitted to | following bit, 'N', indicates whether an intermediary is permitted to | |||
| add this header to the dynamic header table on subsequent hops. When | add this field line to the dynamic table on subsequent hops. When | |||
| the 'N' bit is set, the encoded header MUST always be encoded with a | the 'N' bit is set, the encoded field line MUST always be encoded | |||
| literal representation. In particular, when a peer sends a header | with a literal representation. In particular, when a peer sends a | |||
| field that it received represented as a literal header field with the | field line that it received represented as a literal field line with | |||
| 'N' bit set, it MUST use a literal representation to forward this | the 'N' bit set, it MUST use a literal representation to forward this | |||
| header field. This bit is intended for protecting header field | field line. This bit is intended for protecting field values that | |||
| values that are not to be put at risk by compressing them; see | are not to be put at risk by compressing them; see Section 7 for more | |||
| Section 7 for more details. | details. | |||
| The fourth ('T') bit indicates whether the reference is to the static | The fourth ('T') bit indicates whether the reference is to the static | |||
| or dynamic table. The 4-bit prefix integer (Section 4.1.1) that | or dynamic table. The 4-bit prefix integer (Section 4.1.1) that | |||
| follows is used to locate the table entry for the header name. When | follows is used to locate the table entry for the field name. When | |||
| T=1, the number represents the static table index; when T=0, the | T=1, the number represents the static table index; when T=0, the | |||
| number is the relative index of the entry in the dynamic table. | number is the relative index of the entry in the dynamic table. | |||
| Only the header field name is taken from the dynamic table entry; the | Only the field name is taken from the dynamic table entry; the field | |||
| header field value is encoded as an 8-bit prefix string literal; see | value is encoded as an 8-bit prefix string literal; see | |||
| Section 4.1.2. | Section 4.1.2. | |||
| 4.5.5. Literal Header Field With Post-Base Name Reference | 4.5.5. Literal Field Line With Post-Base Name Reference | |||
| A literal header field with post-base name reference representation | A literal field line with post-base name reference representation | |||
| encodes a header field where the header field name matches the header | encodes a field line where the field name matches the field name of a | |||
| field name of a dynamic table entry with an absolute index greater | dynamic table entry with an absolute index greater than or equal to | |||
| than or equal to the value of the Base. | the value of the Base. | |||
| 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | |||
| +---+---+---+---+---+---+---+---+ | +---+---+---+---+---+---+---+---+ | |||
| | 0 | 0 | 0 | 0 | N |NameIdx(3+)| | | 0 | 0 | 0 | 0 | N |NameIdx(3+)| | |||
| +---+---+---+---+---+-----------+ | +---+---+---+---+---+-----------+ | |||
| | H | Value Length (7+) | | | H | Value Length (7+) | | |||
| +---+---------------------------+ | +---+---------------------------+ | |||
| | Value String (Length bytes) | | | Value String (Length bytes) | | |||
| +-------------------------------+ | +-------------------------------+ | |||
| Figure 16: Literal Header Field With Post-Base Name Reference | Figure 16: Literal Field Line With Post-Base Name Reference | |||
| This representation starts with the '0000' four-bit pattern. The | This representation starts with the '0000' four-bit pattern. The | |||
| fifth bit is the 'N' bit as described in Section 4.5.4. This is | fifth bit is the 'N' bit as described in Section 4.5.4. This is | |||
| followed by a post-base index of the dynamic table entry | followed by a post-base index of the dynamic table entry | |||
| (Section 3.2.6) encoded as an integer with a 3-bit prefix; see | (Section 3.2.6) encoded as an integer with a 3-bit prefix; see | |||
| Section 4.1.1. | Section 4.1.1. | |||
| Only the header field name is taken from the dynamic table entry; the | Only the field name is taken from the dynamic table entry; the field | |||
| header field value is encoded as an 8-bit prefix string literal; see | value is encoded as an 8-bit prefix string literal; see | |||
| Section 4.1.2. | Section 4.1.2. | |||
| 4.5.6. Literal Header Field Without Name Reference | 4.5.6. Literal Field Line Without Name Reference | |||
| The literal header field without name reference representation | The literal field line without name reference representation encodes | |||
| encodes a header field name and a header field value as string | a field name and a field value as string literals. | |||
| literals. | ||||
| 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | |||
| +---+---+---+---+---+---+---+---+ | +---+---+---+---+---+---+---+---+ | |||
| | 0 | 0 | 1 | N | H |NameLen(3+)| | | 0 | 0 | 1 | N | H |NameLen(3+)| | |||
| +---+---+---+---+---+-----------+ | +---+---+---+---+---+-----------+ | |||
| | Name String (Length bytes) | | | Name String (Length bytes) | | |||
| +---+---------------------------+ | +---+---------------------------+ | |||
| | H | Value Length (7+) | | | H | Value Length (7+) | | |||
| +---+---------------------------+ | +---+---------------------------+ | |||
| | Value String (Length bytes) | | | Value String (Length bytes) | | |||
| +-------------------------------+ | +-------------------------------+ | |||
| Figure 17: Literal Header Field Without Name Reference | ||||
| Figure 17: Literal Field Line Without Name Reference | ||||
| This representation begins with the '001' three-bit pattern. The | This representation begins with the '001' three-bit pattern. The | |||
| fourth bit is the 'N' bit as described in Section 4.5.4. The name | fourth bit is the 'N' bit as described in Section 4.5.4. The name | |||
| follows, represented as a 4-bit prefix string literal, then the | follows, represented as a 4-bit prefix string literal, then the | |||
| value, represented as an 8-bit prefix string literal; see | value, represented as an 8-bit prefix string literal; see | |||
| Section 4.1.2. | Section 4.1.2. | |||
| 5. Configuration | 5. Configuration | |||
| QPACK defines two settings which are included in the HTTP/3 SETTINGS | QPACK defines two settings which are included in the HTTP/3 SETTINGS | |||
| frame. | frame. | |||
| SETTINGS_QPACK_MAX_TABLE_CAPACITY (0x1): The default value is zero. | SETTINGS_QPACK_MAX_TABLE_CAPACITY (0x1): The default value is zero. | |||
| See Section 3.2 for usage. This is the equivalent of the | See Section 3.2 for usage. This is the equivalent of the | |||
| SETTINGS_HEADER_TABLE_SIZE from HTTP/2. | SETTINGS_HEADER_TABLE_SIZE from HTTP/2. | |||
| SETTINGS_QPACK_BLOCKED_STREAMS (0x7): The default value is zero. | SETTINGS_QPACK_BLOCKED_STREAMS (0x7): The default value is zero. | |||
| See Section 2.1.3. | See Section 2.1.2. | |||
| 6. Error Handling | 6. Error Handling | |||
| The following error codes are defined for HTTP/3 to indicate failures | The following error codes are defined for HTTP/3 to indicate failures | |||
| of QPACK which prevent the connection from continuing: | of QPACK which prevent the connection from continuing: | |||
| QPACK_DECOMPRESSION_FAILED (0x200): The decoder failed to interpret | QPACK_DECOMPRESSION_FAILED (0x200): The decoder failed to interpret | |||
| a header block and is not able to continue decoding that header | an encoded field section and is not able to continue decoding that | |||
| block. | field section. | |||
| QPACK_ENCODER_STREAM_ERROR (0x201): The decoder failed to interpret | QPACK_ENCODER_STREAM_ERROR (0x201): The decoder failed to interpret | |||
| an encoder instruction received on the encoder stream. | an encoder instruction received on the encoder stream. | |||
| QPACK_DECODER_STREAM_ERROR (0x202): The encoder failed to interpret | QPACK_DECODER_STREAM_ERROR (0x202): The encoder failed to interpret | |||
| a decoder instruction received on the decoder stream. | a decoder instruction received on the decoder stream. | |||
| 7. Security Considerations | 7. Security Considerations | |||
| TBD. Also see Section 7.1 of [RFC7541]. | This section describes potential areas of security concern with | |||
| QPACK: | ||||
| * Use of compression as a length-based oracle for verifying guesses | ||||
| about secrets that are compressed into a shared compression | ||||
| context. | ||||
| * Denial of service resulting from exhausting processing or memory | ||||
| capacity at a decoder. | ||||
| 7.1. Probing Dynamic Table State | ||||
| QPACK reduces the length of header field encodings by exploiting the | ||||
| redundancy inherent in protocols like HTTP. The ultimate goal of | ||||
| this is to reduce the amount of data that is required to send HTTP | ||||
| requests or responses. | ||||
| The compression context used to encode header fields can be probed by | ||||
| an attacker who can both define header fields to be encoded and | ||||
| transmitted and observe the length of those fields once they are | ||||
| encoded. When an attacker can do both, they can adaptively modify | ||||
| requests in order to confirm guesses about the dynamic table state. | ||||
| If a guess is compressed into a shorter length, the attacker can | ||||
| observe the encoded length and infer that the guess was correct. | ||||
| This is possible even over the Transport Layer Security Protocol | ||||
| (TLS, see [RFC5246]), because while TLS provides confidentiality | ||||
| protection for content, it only provides a limited amount of | ||||
| protection for the length of that content. | ||||
| Note: Padding schemes only provide limited protection against an | ||||
| attacker with these capabilities, potentially only forcing an | ||||
| increased number of guesses to learn the length associated with a | ||||
| given guess. Padding schemes also work directly against | ||||
| compression by increasing the number of bits that are transmitted. | ||||
| Attacks like CRIME [CRIME] demonstrated the existence of these | ||||
| general attacker capabilities. The specific attack exploited the | ||||
| fact that DEFLATE [RFC1951] removes redundancy based on prefix | ||||
| matching. This permitted the attacker to confirm guesses a character | ||||
| at a time, reducing an exponential-time attack into a linear-time | ||||
| attack. | ||||
| 7.2. Applicability to QPACK and HTTP | ||||
| QPACK mitigates but does not completely prevent attacks modeled on | ||||
| CRIME [CRIME] by forcing a guess to match an entire header field | ||||
| value, rather than individual characters. An attacker can only learn | ||||
| whether a guess is correct or not, so is reduced to a brute force | ||||
| guess for the header field values. | ||||
| The viability of recovering specific header field values therefore | ||||
| depends on the entropy of values. As a result, values with high | ||||
| entropy are unlikely to be recovered successfully. However, values | ||||
| with low entropy remain vulnerable. | ||||
| Attacks of this nature are possible any time that two mutually | ||||
| distrustful entities control requests or responses that are placed | ||||
| onto a single HTTP/3 connection. If the shared QPACK compressor | ||||
| permits one entity to add entries to the dynamic table, and the other | ||||
| to access those entries, then the state of the table can be learned. | ||||
| Having requests or responses from mutually distrustful entities | ||||
| occurs when an intermediary either: | ||||
| * sends requests from multiple clients on a single connection toward | ||||
| an origin server, or | ||||
| * takes responses from multiple origin servers and places them on a | ||||
| shared connection toward a client. | ||||
| Web browsers also need to assume that requests made on the same | ||||
| connection by different web origins [RFC6454] are made by mutually | ||||
| distrustful entities. | ||||
| 7.3. Mitigation | ||||
| Users of HTTP that require confidentiality for header fields can use | ||||
| values with entropy sufficient to make guessing infeasible. However, | ||||
| this is impractical as a general solution because it forces all users | ||||
| of HTTP to take steps to mitigate attacks. It would impose new | ||||
| constraints on how HTTP is used. | ||||
| Rather than impose constraints on users of HTTP, an implementation of | ||||
| QPACK can instead constrain how compression is applied in order to | ||||
| limit the potential for dynamic table probing. | ||||
| An ideal solution segregates access to the dynamic table based on the | ||||
| entity that is constructing header fields. Header field values that | ||||
| are added to the table are attributed to an entity, and only the | ||||
| entity that created a particular value can extract that value. | ||||
| To improve compression performance of this option, certain entries | ||||
| might be tagged as being public. For example, a web browser might | ||||
| make the values of the Accept-Encoding header field available in all | ||||
| requests. | ||||
| An encoder without good knowledge of the provenance of header fields | ||||
| might instead introduce a penalty for a header field with many | ||||
| different values, such that a large number of attempts to guess a | ||||
| header field value results in the header field not being compared to | ||||
| the dynamic table entries in future messages, effectively preventing | ||||
| further guesses. | ||||
| Note: Simply removing entries corresponding to the header field from | ||||
| the dynamic table can be ineffectual if the attacker has a | ||||
| reliable way of causing values to be reinstalled. For example, a | ||||
| request to load an image in a web browser typically includes the | ||||
| Cookie header field (a potentially highly valued target for this | ||||
| sort of attack), and web sites can easily force an image to be | ||||
| loaded, thereby refreshing the entry in the dynamic table. | ||||
| This response might be made inversely proportional to the length of | ||||
| the header field value. Disabling access to the dynamic table for a | ||||
| header field might occur for shorter values more quickly or with | ||||
| higher probability than for longer values. | ||||
| 7.4. Never Indexed Literals | ||||
| Implementations can also choose to protect sensitive header fields by | ||||
| not compressing them and instead encoding their value as literals. | ||||
| Refusing to insert a header field into the dynamic table is only | ||||
| effective if doing so is avoided on all hops. The never indexed | ||||
| literal bit (see Section 4.5.4) can be used to signal to | ||||
| intermediaries that a particular value was intentionally sent as a | ||||
| literal. | ||||
| An intermediary MUST NOT re-encode a value that uses a literal | ||||
| representation with the 'N' bit set with another representation that | ||||
| would index it. If QPACK is used for re-encoding, a literal | ||||
| representation with the 'N' bit set MUST be used. If HPACK is used | ||||
| for re-encoding, the never indexed literal representation (see | ||||
| Section 6.2.3 of [RFC7541]) MUST be used. | ||||
| The choice to mark that a header field should never be indexed | ||||
| depends on several factors. Since QPACK doesn't protect against | ||||
| guessing an entire header field value, short or low-entropy values | ||||
| are more readily recovered by an adversary. Therefore, an encoder | ||||
| might choose not to index values with low entropy. | ||||
| An encoder might also choose not to index values for header fields | ||||
| that are considered to be highly valuable or sensitive to recovery, | ||||
| such as the Cookie or Authorization header fields. | ||||
| On the contrary, an encoder might prefer indexing values for header | ||||
| fields that have little or no value if they were exposed. For | ||||
| instance, a User-Agent header field does not commonly vary between | ||||
| requests and is sent to any server. In that case, confirmation that | ||||
| a particular User-Agent value has been used provides little value. | ||||
| Note that these criteria for deciding to use a never indexed literal | ||||
| representation will evolve over time as new attacks are discovered. | ||||
| 7.5. Static Huffman Encoding | ||||
| There is no currently known attack against a static Huffman encoding. | ||||
| A study has shown that using a static Huffman encoding table created | ||||
| an information leakage, however this same study concluded that an | ||||
| attacker could not take advantage of this information leakage to | ||||
| recover any meaningful amount of information (see [PETAL]). | ||||
| 7.6. Memory Consumption | ||||
| An attacker can try to cause an endpoint to exhaust its memory. | ||||
| QPACK is designed to limit both the peak and stable amounts of memory | ||||
| allocated by an endpoint. | ||||
| The amount of memory used by the encoder is limited by the protocol | ||||
| using QPACK through the definition of the maximum size of the dynamic | ||||
| table, and the maximum number of blocking streams. In HTTP/3, these | ||||
| values are controlled by the decoder through the settings parameters | ||||
| SETTINGS_QPACK_MAX_TABLE_CAPACITY and SETTINGS_QPACK_BLOCKED_STREAMS, | ||||
| respectively (see Section 3.2.3 and Section 2.1.2). The limit on the | ||||
| size of the dynamic table takes into account the size of the data | ||||
| stored in the dynamic table, plus a small allowance for overhead. | ||||
| The limit on the number of blocked streams is only a proxy for the | ||||
| maximum amount of memory required by the decoder. The actual maximum | ||||
| amount of memory will depend on how much memory the decoder uses to | ||||
| track each blocked stream. | ||||
| A decoder can limit the amount of state memory used for the dynamic | ||||
| table by setting an appropriate value for the maximum size of the | ||||
| dynamic table. In HTTP/3, this is realized by setting an appropriate | ||||
| value for the SETTINGS_QPACK_MAX_TABLE_CAPACITY parameter. An | ||||
| encoder can limit the amount of state memory it uses by signaling a | ||||
| lower dynamic table size than the decoder allows (see Section 3.2.2). | ||||
| A decoder can limit the amount of state memory used for blocked | ||||
| streams by setting an appropriate value for the maximum number of | ||||
| blocked streams. In HTTP/3, this is realized by setting an | ||||
| appropriate value for the QPACK_BLOCKED_STREAMS parameter. An | ||||
| encoder can limit the amount of state memory by only using as many | ||||
| blocked streams as it wishes to support; no signaling to the decoder | ||||
| is required. | ||||
| The amount of temporary memory consumed by an encoder or decoder can | ||||
| be limited by processing header fields sequentially. A decoder | ||||
| implementation does not need to retain a complete list of header | ||||
| fields while decoding a header block. An encoder implementation does | ||||
| not need to retain a complete list of header fields while encoding a | ||||
| header block if it is using a single-pass algorithm. Note that it | ||||
| might be necessary for an application to retain a complete header | ||||
| list for other reasons; even if QPACK does not force this to occur, | ||||
| application constraints might make this necessary. | ||||
| While the negotiated limit on the dynamic table size accounts for | While the negotiated limit on the dynamic table size accounts for | |||
| much of the memory that can be consumed by a QPACK implementation, | much of the memory that can be consumed by a QPACK implementation, | |||
| data which cannot be immediately sent due to flow control is not | data which cannot be immediately sent due to flow control is not | |||
| affected by this limit. Implementations should limit the size of | affected by this limit. Implementations should limit the size of | |||
| unsent data, especially on the decoder stream where flexibility to | unsent data, especially on the decoder stream where flexibility to | |||
| choose what to send is limited. Possible responses to an excess of | choose what to send is limited. Possible responses to an excess of | |||
| unsent data might include limiting the ability of the peer to open | unsent data might include limiting the ability of the peer to open | |||
| new streams, reading only from the encoder stream, or closing the | new streams, reading only from the encoder stream, or closing the | |||
| connection. | connection. | |||
| 7.7. Implementation Limits | ||||
| An implementation of QPACK needs to ensure that large values for | ||||
| integers, long encoding for integers, or long string literals do not | ||||
| create security weaknesses. | ||||
| An implementation has to set a limit for the values it accepts for | ||||
| integers, as well as for the encoded length (see Section 4.1.1). In | ||||
| the same way, it has to set a limit to the length it accepts for | ||||
| string literals (see Section 4.1.2). | ||||
| 8. IANA Considerations | 8. IANA Considerations | |||
| 8.1. Settings Registration | 8.1. Settings Registration | |||
| This document specifies two settings. The entries in the following | This document specifies two settings. The entries in the following | |||
| table are registered in the "HTTP/3 Settings" registry established in | table are registered in the "HTTP/3 Settings" registry established in | |||
| [HTTP3]. | [HTTP3]. | |||
| +--------------------------+------+---------------+---------+ | +--------------------------+------+---------------+---------+ | |||
| | Setting Name | Code | Specification | Default | | | Setting Name | Code | Specification | Default | | |||
| skipping to change at page 28, line 5 ¶ | skipping to change at page 33, line 5 ¶ | |||
| +----------------------+------+---------------+--------+ | +----------------------+------+---------------+--------+ | |||
| Table 2 | Table 2 | |||
| 8.3. Error Code Registration | 8.3. Error Code Registration | |||
| This document specifies three error codes. The entries in the | This document specifies three error codes. The entries in the | |||
| following table are registered in the "HTTP/3 Error Code" registry | following table are registered in the "HTTP/3 Error Code" registry | |||
| established in [HTTP3]. | established in [HTTP3]. | |||
| +----------------------------+------+---------------+---------------+ | +----------------------------+-------+-------------+---------------+ | |||
| | Name | Code | Description | Specification | | | Name | Code | Description | Specification | | |||
| +============================+======+===============+===============+ | +============================+=======+=============+===============+ | |||
| | QPACK_DECOMPRESSION_FAILED |0x200 | Decompression | Section 6 | | | QPACK_DECOMPRESSION_FAILED | 0x200 | Decoding of | Section 6 | | |||
| | | | of a header | | | | | | a field | | | |||
| | | | block failed | | | | | | section | | | |||
| +----------------------------+------+---------------+---------------+ | | | | failed | | | |||
| | QPACK_ENCODER_STREAM_ERROR |0x201 | Error on the | Section 6 | | +----------------------------+-------+-------------+---------------+ | |||
| | | |encoder stream | | | | QPACK_ENCODER_STREAM_ERROR | 0x201 | Error on | Section 6 | | |||
| +----------------------------+------+---------------+---------------+ | | | | the encoder | | | |||
| | QPACK_DECODER_STREAM_ERROR |0x202 | Error on the | Section 6 | | | | | stream | | | |||
| | | |decoder stream | | | +----------------------------+-------+-------------+---------------+ | |||
| +----------------------------+------+---------------+---------------+ | | QPACK_DECODER_STREAM_ERROR | 0x202 | Error on | Section 6 | | |||
| | | | the decoder | | | ||||
| | | | stream | | | ||||
| +----------------------------+-------+-------------+---------------+ | ||||
| Table 3 | Table 3 | |||
| 9. References | 9. References | |||
| 9.1. Normative References | 9.1. Normative References | |||
| [HTTP3] Bishop, M., Ed., "Hypertext Transfer Protocol Version 3 | [HTTP3] Bishop, M., Ed., "Hypertext Transfer Protocol Version 3 | |||
| (HTTP/3)", Work in Progress, Internet-Draft, draft-ietf- | (HTTP/3)", Work in Progress, Internet-Draft, draft-ietf- | |||
| quic-http-27, 21 February 2020, | quic-http-28, 20 May 2020, | |||
| <https://tools.ietf.org/html/draft-ietf-quic-http-27>. | <https://tools.ietf.org/html/draft-ietf-quic-http-28>. | |||
| [QUIC-TRANSPORT] | [QUIC-TRANSPORT] | |||
| Iyengar, J., Ed. and M. Thomson, Ed., "QUIC: A UDP-Based | Iyengar, J., Ed. and M. Thomson, Ed., "QUIC: A UDP-Based | |||
| Multiplexed and Secure Transport", Work in Progress, | Multiplexed and Secure Transport", Work in Progress, | |||
| Internet-Draft, draft-ietf-quic-transport-27, 21 February | Internet-Draft, draft-ietf-quic-transport-28, 20 May 2020, | |||
| 2020, <https://tools.ietf.org/html/draft-ietf-quic- | <https://tools.ietf.org/html/draft-ietf-quic-transport- | |||
| transport-27>. | 28>. | |||
| [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate | [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate | |||
| 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>. | |||
| [RFC7541] Peon, R. and H. Ruellan, "HPACK: Header Compression for | [RFC7541] Peon, R. and H. Ruellan, "HPACK: Header Compression for | |||
| HTTP/2", RFC 7541, DOI 10.17487/RFC7541, May 2015, | HTTP/2", RFC 7541, DOI 10.17487/RFC7541, May 2015, | |||
| <https://www.rfc-editor.org/info/rfc7541>. | <https://www.rfc-editor.org/info/rfc7541>. | |||
| [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>. | |||
| [SEMANTICS] | ||||
| Fielding, R., Nottingham, M., and J. Reschke, "HTTP | ||||
| Semantics", Work in Progress, Internet-Draft, draft-ietf- | ||||
| httpbis-semantics-07, 7 March 2020, <http://www.ietf.org/ | ||||
| internet-drafts/draft-ietf-httpbis-semantics-07.txt>. | ||||
| 9.2. Informative References | 9.2. Informative References | |||
| [CRIME] Wikipedia, "CRIME", May 2015, <http://en.wikipedia.org/w/ | ||||
| index.php?title=CRIME&oldid=660948120>. | ||||
| [PETAL] Tan, J. and J. Nahata, "PETAL: Preset Encoding | ||||
| Table Information Leakage", April 2013, | ||||
| <http://www.pdl.cmu.edu/PDL-FTP/associated/CMU-PDL- | ||||
| 13-106.pdf>. | ||||
| [RFC1951] Deutsch, P., "DEFLATE Compressed Data Format Specification | ||||
| version 1.3", RFC 1951, DOI 10.17487/RFC1951, May 1996, | ||||
| <https://www.rfc-editor.org/info/rfc1951>. | ||||
| [RFC2360] Scott, G., "Guide for Internet Standards Writers", BCP 22, | [RFC2360] Scott, G., "Guide for Internet Standards Writers", BCP 22, | |||
| RFC 2360, DOI 10.17487/RFC2360, June 1998, | RFC 2360, DOI 10.17487/RFC2360, June 1998, | |||
| <https://www.rfc-editor.org/info/rfc2360>. | <https://www.rfc-editor.org/info/rfc2360>. | |||
| [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security | ||||
| (TLS) Protocol Version 1.2", RFC 5246, | ||||
| DOI 10.17487/RFC5246, August 2008, | ||||
| <https://www.rfc-editor.org/info/rfc5246>. | ||||
| [RFC6454] Barth, A., "The Web Origin Concept", RFC 6454, | ||||
| DOI 10.17487/RFC6454, December 2011, | ||||
| <https://www.rfc-editor.org/info/rfc6454>. | ||||
| [RFC7540] Belshe, M., Peon, R., and M. Thomson, Ed., "Hypertext | [RFC7540] Belshe, M., Peon, R., and M. Thomson, Ed., "Hypertext | |||
| Transfer Protocol Version 2 (HTTP/2)", RFC 7540, | Transfer Protocol Version 2 (HTTP/2)", RFC 7540, | |||
| DOI 10.17487/RFC7540, May 2015, | DOI 10.17487/RFC7540, May 2015, | |||
| <https://www.rfc-editor.org/info/rfc7540>. | <https://www.rfc-editor.org/info/rfc7540>. | |||
| Appendix A. Static Table | Appendix A. Static Table | |||
| This table was generated by analyzing actual internet traffic in 2018 | ||||
| and including the most common headers, after filtering out some | ||||
| unsupported and non-standard values. Due to this methodology, some | ||||
| of the entries may be inconsistent or appear multiple times with | ||||
| similar but not identical values. The order of the entries is | ||||
| optimized to encode the most common headers with the smallest number | ||||
| of bytes. | ||||
| +-------+----------------------------------+-----------------------+ | +-------+----------------------------------+-----------------------+ | |||
| | Index | Name | Value | | | Index | Name | Value | | |||
| +=======+==================================+=======================+ | +=======+==================================+=======================+ | |||
| | 0 | :authority | | | | 0 | :authority | | | |||
| +-------+----------------------------------+-----------------------+ | +-------+----------------------------------+-----------------------+ | |||
| | 1 | :path | / | | | 1 | :path | / | | |||
| +-------+----------------------------------+-----------------------+ | +-------+----------------------------------+-----------------------+ | |||
| | 2 | age | 0 | | | 2 | age | 0 | | |||
| +-------+----------------------------------+-----------------------+ | +-------+----------------------------------+-----------------------+ | |||
| | 3 | content-disposition | | | | 3 | content-disposition | | | |||
| skipping to change at page 33, line 42 ¶ | skipping to change at page 39, line 31 ¶ | |||
| | 97 | x-frame-options | deny | | | 97 | x-frame-options | deny | | |||
| +-------+----------------------------------+-----------------------+ | +-------+----------------------------------+-----------------------+ | |||
| | 98 | x-frame-options | sameorigin | | | 98 | x-frame-options | sameorigin | | |||
| +-------+----------------------------------+-----------------------+ | +-------+----------------------------------+-----------------------+ | |||
| Table 4 | Table 4 | |||
| Appendix B. Sample One Pass Encoding Algorithm | Appendix B. Sample One Pass Encoding Algorithm | |||
| Pseudo-code for single pass encoding, excluding handling of | Pseudo-code for single pass encoding, excluding handling of | |||
| duplicates, non-blocking mode, and reference tracking. | duplicates, non-blocking mode, available encoder stream flow control | |||
| and reference tracking. | ||||
| baseIndex = dynamicTable.baseIndex | base = dynamicTable.getInsertCount() | |||
| largestReference = 0 | requiredInsertCount = 0 | |||
| for header in headers: | for line in field_lines: | |||
| staticIdx = staticTable.getIndex(header) | staticIndex = staticTable.findIndex(line) | |||
| if staticIdx: | if staticIndex is not None: | |||
| encodeIndexReference(streamBuffer, staticIdx) | encodeIndexReference(streamBuffer, staticIndex) | |||
| continue | continue | |||
| dynamicIdx = dynamicTable.getIndex(header) | dynamicIndex = dynamicTable.findIndex(line) | |||
| if !dynamicIdx: | if dynamicIndex is None: | |||
| # No matching entry. Either insert+index or encode literal | # No matching entry. Either insert+index or encode literal | |||
| nameIdx = getNameIndex(header) | staticNameIndex = staticTable.findName(line.name) | |||
| if shouldIndex(header) and dynamicTable.canIndex(header): | if staticNameIndex is None: | |||
| encodeLiteralWithIncrementalIndex(controlBuffer, nameIdx, | dynamicNameIndex = dynamicTable.findName(line.name) | |||
| header) | ||||
| dynamicTable.add(header) | ||||
| dynamicIdx = dynamicTable.baseIndex | ||||
| if !dynamicIdx: | if shouldIndex(line) and dynamicTable.canIndex(line): | |||
| encodeInsert(encoderBuffer, staticNameIndex, | ||||
| dynamicNameIndex, line) | ||||
| dynamicIndex = dynamicTable.add(line) | ||||
| if dynamicIndex is None: | ||||
| # Couldn't index it, literal | # Couldn't index it, literal | |||
| if nameIdx <= staticTable.size: | if nameIndex is None or isStaticName: | |||
| encodeLiteral(streamBuffer, nameIndex, header) | # Encodes a literal with a static name or literal name | |||
| encodeLiteral(streamBuffer, nameIndex, line) | ||||
| else: | else: | |||
| # encode literal, possibly with nameIdx above baseIndex | # encode literal with dynamic name, possibly above base | |||
| encodeDynamicLiteral(streamBuffer, nameIndex, baseIndex, | encodeDynamicLiteral(streamBuffer, nameIndex, base, line) | |||
| header) | requiredInsertCount = max(requiredInsertCount, nameIndex) | |||
| largestReference = max(largestReference, | ||||
| dynamicTable.toAbsolute(nameIdx)) | ||||
| else: | else: | |||
| # Dynamic index reference | # Dynamic index reference | |||
| assert(dynamicIdx) | assert(dynamicIndex is not None) | |||
| largestReference = max(largestReference, dynamicIdx) | requiredInsertCount = max(requiredInsertCount, dynamicIndex) | |||
| # Encode dynamicIdx, possibly with dynamicIdx above baseIndex | # Encode dynamicIndex, possibly above base | |||
| encodeDynamicIndexReference(streamBuffer, dynamicIdx, | encodeDynamicIndexReference(streamBuffer, dynamicIndex, base) | |||
| baseIndex) | ||||
| # encode the prefix | # encode the prefix | |||
| encodeInteger(prefixBuffer, 0x00, largestReference, 8) | if requiredInsertCount == 0: | |||
| if baseIndex >= largestReference: | encodeIndexReference(prefixBuffer, 0, 0, 8) | |||
| encodeInteger(prefixBuffer, 0, baseIndex - largestReference, 7) | encodeIndexReference(prefixBuffer, 0, 0, 7) | |||
| else: | else: | |||
| encodeInteger(prefixBuffer, 0x80, | wireRIC = ( | |||
| largestReference - baseIndex, 7) | requiredInsertCount | |||
| % (2 * getMaxEntries(maxTableCapacity)) | ||||
| ) + 1; | ||||
| encodeInteger(prefixBuffer, 0x00, wireRIC, 8) | ||||
| if base >= requiredInsertCount: | ||||
| encodeInteger(prefixBuffer, 0, base - requiredInsertCount, 7) | ||||
| else: | ||||
| encodeInteger(prefixBuffer, 0x80, | ||||
| requiredInsertCount - base - 1, 7) | ||||
| return controlBuffer, prefixBuffer + streamBuffer | return encoderBuffer, prefixBuffer + streamBuffer | |||
| Appendix C. Change Log | Appendix C. Change Log | |||
| *RFC Editor's Note:* Please remove this section prior to | *RFC Editor's Note:* Please remove this section prior to | |||
| publication of a final version of this document. | publication of a final version of this document. | |||
| C.1. Since draft-ietf-quic-qpack-13 | C.1. Since draft-ietf-quic-qpack-14 | |||
| Added security considerations | ||||
| C.2. Since draft-ietf-quic-qpack-13 | ||||
| No changes | No changes | |||
| C.2. Since draft-ietf-quic-qpack-12 | C.3. Since draft-ietf-quic-qpack-12 | |||
| Editorial changes only | Editorial changes only | |||
| C.3. Since draft-ietf-quic-qpack-11 | C.4. Since draft-ietf-quic-qpack-11 | |||
| Editorial changes only | Editorial changes only | |||
| C.4. Since draft-ietf-quic-qpack-10 | C.5. Since draft-ietf-quic-qpack-10 | |||
| Editorial changes only | Editorial changes only | |||
| C.5. Since draft-ietf-quic-qpack-09 | C.6. Since draft-ietf-quic-qpack-09 | |||
| * Decoders MUST emit Header Acknowledgements (#2939) | * Decoders MUST emit Header Acknowledgements (#2939) | |||
| * Updated error code for multiple encoder or decoder streams (#2970) | * Updated error code for multiple encoder or decoder streams (#2970) | |||
| * Added explicit defaults for new SETTINGS (#2974) | * Added explicit defaults for new SETTINGS (#2974) | |||
| C.6. Since draft-ietf-quic-qpack-08 | C.7. Since draft-ietf-quic-qpack-08 | |||
| * Endpoints are permitted to create encoder and decoder streams even | * Endpoints are permitted to create encoder and decoder streams even | |||
| if they can't use them (#2100, #2529) | if they can't use them (#2100, #2529) | |||
| * Maximum values for settings removed (#2766, #2767) | * Maximum values for settings removed (#2766, #2767) | |||
| C.7. Since draft-ietf-quic-qpack-06 | C.8. Since draft-ietf-quic-qpack-06 | |||
| * Clarify initial dynamic table capacity maximums (#2276, #2330, | * Clarify initial dynamic table capacity maximums (#2276, #2330, | |||
| #2330) | #2330) | |||
| C.8. Since draft-ietf-quic-qpack-05 | C.9. Since draft-ietf-quic-qpack-05 | |||
| * Introduced the terms dynamic table capacity and maximum dynamic | * Introduced the terms dynamic table capacity and maximum dynamic | |||
| table capacity. | table capacity. | |||
| * Renamed SETTINGS_HEADER_TABLE_SIZE to | * Renamed SETTINGS_HEADER_TABLE_SIZE to | |||
| SETTINGS_QPACK_MAX_TABLE_CAPACITY. | SETTINGS_QPACK_MAX_TABLE_CAPACITY. | |||
| C.9. Since draft-ietf-quic-qpack-04 | C.10. Since draft-ietf-quic-qpack-04 | |||
| * Changed calculation of Delta Base Index to avoid an illegal value | * Changed calculation of Delta Base Index to avoid an illegal value | |||
| (#2002, #2005) | (#2002, #2005) | |||
| C.10. Since draft-ietf-quic-qpack-03 | C.11. Since draft-ietf-quic-qpack-03 | |||
| * Change HTTP settings defaults (#2038) | * Change HTTP settings defaults (#2038) | |||
| * Substantial editorial reorganization | * Substantial editorial reorganization | |||
| C.11. Since draft-ietf-quic-qpack-02 | C.12. Since draft-ietf-quic-qpack-02 | |||
| * Largest Reference encoded modulo MaxEntries (#1763) | * Largest Reference encoded modulo MaxEntries (#1763) | |||
| * New Static Table (#1355) | * New Static Table (#1355) | |||
| * Table Size Update with Insert Count=0 is a connection error | * Table Size Update with Insert Count=0 is a connection error | |||
| (#1762) | (#1762) | |||
| * Stream Cancellations are optional when | * Stream Cancellations are optional when | |||
| SETTINGS_HEADER_TABLE_SIZE=0 (#1761) | SETTINGS_HEADER_TABLE_SIZE=0 (#1761) | |||
| skipping to change at page 36, line 38 ¶ | skipping to change at page 42, line 33 ¶ | |||
| * Implementations must handle 62 bit integers (#1760) | * Implementations must handle 62 bit integers (#1760) | |||
| * Different error types for each QPACK stream, other changes to | * Different error types for each QPACK stream, other changes to | |||
| error handling (#1726) | error handling (#1726) | |||
| * Preserve header field order (#1725) | * Preserve header field order (#1725) | |||
| * Initial table size is the maximum permitted when table is first | * Initial table size is the maximum permitted when table is first | |||
| usable (#1642) | usable (#1642) | |||
| C.12. Since draft-ietf-quic-qpack-01 | C.13. Since draft-ietf-quic-qpack-01 | |||
| * Only header blocks that reference the dynamic table are | * Only header blocks that reference the dynamic table are | |||
| acknowledged (#1603, #1605) | acknowledged (#1603, #1605) | |||
| C.13. Since draft-ietf-quic-qpack-00 | C.14. Since draft-ietf-quic-qpack-00 | |||
| * Renumbered instructions for consistency (#1471, #1472) | * Renumbered instructions for consistency (#1471, #1472) | |||
| * Decoder is allowed to validate largest reference (#1404, #1469) | * Decoder is allowed to validate largest reference (#1404, #1469) | |||
| * Header block acknowledgments also acknowledge the associated | * Header block acknowledgments also acknowledge the associated | |||
| largest reference (#1370, #1400) | largest reference (#1370, #1400) | |||
| * Added an acknowledgment for unread streams (#1371, #1400) | * Added an acknowledgment for unread streams (#1371, #1400) | |||
| * Removed framing from encoder stream (#1361,#1467) | * Removed framing from encoder stream (#1361,#1467) | |||
| * Control streams use typed unidirectional streams rather than fixed | * Control streams use typed unidirectional streams rather than fixed | |||
| stream IDs (#910,#1359) | stream IDs (#910,#1359) | |||
| C.14. Since draft-ietf-quic-qcram-00 | C.15. Since draft-ietf-quic-qcram-00 | |||
| * Separate instruction sets for table updates and header blocks | * Separate instruction sets for table updates and header blocks | |||
| (#1235, #1142, #1141) | (#1235, #1142, #1141) | |||
| * Reworked indexing scheme (#1176, #1145, #1136, #1130, #1125, | * Reworked indexing scheme (#1176, #1145, #1136, #1130, #1125, | |||
| #1314) | #1314) | |||
| * Added mechanisms that support one-pass encoding (#1138, #1320) | * Added mechanisms that support one-pass encoding (#1138, #1320) | |||
| * Added a setting to control the number of blocked decoders (#238, | * Added a setting to control the number of blocked decoders (#238, | |||
| #1140, #1143) | #1140, #1143) | |||
| * Moved table updates and acknowledgments to dedicated streams | * Moved table updates and acknowledgments to dedicated streams | |||
| (#1121, #1122, #1238) | (#1121, #1122, #1238) | |||
| Acknowledgments | Acknowledgments | |||
| This draft draws heavily on the text of [RFC7541]. The indirect | The IETF QUIC Working Group received an enormous amount of support | |||
| input of those authors is gratefully acknowledged, as well as ideas | from many people. | |||
| from: | ||||
| The compression design team did substantial work exploring the | ||||
| problem space and influencing the initial draft. The contributions | ||||
| of design team members Roberto Peon, Martin Thomson, and Dmitri | ||||
| Tikhonov are gratefully acknowledged. | ||||
| The following people also provided substantial contributions to this | ||||
| document: | ||||
| * Bence Beky | ||||
| * Alessandro Ghedini | ||||
| * Ryan Hamilton | * Ryan Hamilton | |||
| * Robin Marx | ||||
| * Patrick McManus | * Patrick McManus | |||
| * Kazuho Oku | * 奥 一穂 (Kazuho Oku) | |||
| * Lucas Pardue | ||||
| * Biren Roy | * Biren Roy | |||
| * Ian Swett | * Ian Swett | |||
| This draft draws heavily on the text of [RFC7541]. The indirect | ||||
| * Dmitri Tikhonov | input of those authors is also gratefully acknowledged. | |||
| Buck's contribution was supported by Google during his employment | Buck's contribution was supported by Google during his employment | |||
| there. | there. | |||
| A substantial portion of Mike's contribution was supported by | A portion of Mike's contribution was supported by Microsoft during | |||
| Microsoft during his employment there. | his employment there. | |||
| Authors' Addresses | Authors' Addresses | |||
| Charles 'Buck' Krasic | Charles 'Buck' Krasic | |||
| Netflix | Netflix | |||
| Email: ckrasic@netflix.com | Email: ckrasic@netflix.com | |||
| Mike Bishop | Mike Bishop | |||
| Akamai Technologies | Akamai Technologies | |||
| Email: mbishop@evequefou.be | Email: mbishop@evequefou.be | |||
| End of changes. 167 change blocks. | ||||
| 419 lines changed or deleted | 725 lines changed or added | |||
This html diff was produced by rfcdiff 1.45. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ | ||||