QUIC Working Group D. Tikhonov Internet-Draft LiteSpeed Technologies Intended status: Standards Track November 13, 2017 Expires: May 17, 2018 QMIN: Header Compression for QUIC draft-tikhonov-quic-qmin-00 Abstract This specification defines QMIN, a compression format and protocol for HTTP/2 ([RFC7540]) headers. QMIN is based on HPACK ([RFC7541]). The modifications to HPACK are meant to allow robust compression use in QUIC: That is, no head-of-line blocking and low overhead. QMIN is guided by HPACK design principles. It inherits all of HPACK's data structures and retains binary compatibility with it. While designed with QUIC in mind, QMIN can be used in other contexts. Status of This Memo This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79. Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet- Drafts is at https://datatracker.ietf.org/drafts/current/. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress." This Internet-Draft will expire on May 17, 2018. Copyright Notice Copyright (c) 2017 IETF Trust and the persons identified as the document authors. All rights reserved. This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of Tikhonov Expires May 17, 2018 [Page 1] Internet-Draft QMIN: Header Compression for QUIC November 2017 the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License. Table of Contents 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 2. Overview . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3. Checkpoint States . . . . . . . . . . . . . . . . . . . . . . 5 3.1. Checkpoint State: NEW . . . . . . . . . . . . . . . . . . 5 3.2. Checkpoint State: PENDING . . . . . . . . . . . . . . . . 5 3.3. Checkpoint State: LIVE . . . . . . . . . . . . . . . . . 5 3.4. Checkpoint State: DEAD . . . . . . . . . . . . . . . . . 6 4. Control Stream . . . . . . . . . . . . . . . . . . . . . . . 6 4.1. Encoder Commands . . . . . . . . . . . . . . . . . . . . 6 4.1.1. INSERT_ENTRY . . . . . . . . . . . . . . . . . . . . 6 4.1.2. REUSE_ENTRY . . . . . . . . . . . . . . . . . . . . . 7 4.1.3. FLUSH_CHKPOINT . . . . . . . . . . . . . . . . . . . 8 4.1.4. DROP_CHKPOINT . . . . . . . . . . . . . . . . . . . . 8 4.2. Decoder Messages . . . . . . . . . . . . . . . . . . . . 9 4.2.1. ACK_FLUSH . . . . . . . . . . . . . . . . . . . . . . 9 4.3. Stream Notification Commands . . . . . . . . . . . . . . 9 4.3.1. STREAM_DONE . . . . . . . . . . . . . . . . . . . . . 9 4.4. Expansion . . . . . . . . . . . . . . . . . . . . . . . . 10 5. Header Encoding . . . . . . . . . . . . . . . . . . . . . . . 10 6. Table Size Calculation . . . . . . . . . . . . . . . . . . . 10 6.1. Entry Size . . . . . . . . . . . . . . . . . . . . . . . 10 6.2. Checkpoint Size . . . . . . . . . . . . . . . . . . . . . 10 6.3. Overall Table Size . . . . . . . . . . . . . . . . . . . 11 6.4. Comparison with HPACK . . . . . . . . . . . . . . . . . . 11 7. Encoding Process . . . . . . . . . . . . . . . . . . . . . . 11 7.1. Indexable Header Fields . . . . . . . . . . . . . . . . . 11 7.1.1. New Index . . . . . . . . . . . . . . . . . . . . . . 11 7.1.2. Existing Index . . . . . . . . . . . . . . . . . . . 11 7.2. Non-indexable Header Fields . . . . . . . . . . . . . . . 12 7.3. When Maximum Table Size Is Reached . . . . . . . . . . . 12 7.4. Memory Cost of Flushing . . . . . . . . . . . . . . . . . 12 8. Decoding Process . . . . . . . . . . . . . . . . . . . . . . 12 9. Encoder Strategies . . . . . . . . . . . . . . . . . . . . . 13 9.1. Flushing and Dropping . . . . . . . . . . . . . . . . . . 13 9.1.1. Simple Strategy . . . . . . . . . . . . . . . . . . . 13 9.1.2. Rule-Based Strategy . . . . . . . . . . . . . . . . . 13 9.1.3. Feedback-Based Strategy . . . . . . . . . . . . . . . 14 9.2. Control Channel Cost . . . . . . . . . . . . . . . . . . 14 10. HPACK Interoperability . . . . . . . . . . . . . . . . . . . 15 11. Implementation Notes . . . . . . . . . . . . . . . . . . . . 15 11.1. Control Messages Made Easy . . . . . . . . . . . . . . . 15 12. QMIN Drawbacks . . . . . . . . . . . . . . . . . . . . . . . 15 13. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 16 Tikhonov Expires May 17, 2018 [Page 2] Internet-Draft QMIN: Header Compression for QUIC November 2017 14. References . . . . . . . . . . . . . . . . . . . . . . . . . 16 14.1. Normative References . . . . . . . . . . . . . . . . . . 16 14.2. Informative References . . . . . . . . . . . . . . . . . 16 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 16 1. Introduction Google QUIC implementation uses HPACK to compress HTTP headers. HTTP headers for all requests and responses are sent on a dedicated stream. This introduces head-of-line (HoL) blocking: if this stream is blocked due to packet loss, all HTTP messages whose compressed headers follow the lost packet in the stream are stalled. Solving the HoL problem has been one of the goals of the IETF QUIC Working Group. QMIN solves the HoL problem and has the following beneficial properties: o The compression logic is mostly contained in the encoder, keeping the decoder simple. o QMIN is transport-independent. o Memory penalty over HPACK is manageable (Section 6.4). o QMIN and HPACK are interoperable (Section 10). 2. Overview The QMIN innovation is in using a *checkpointed* dynamic table, with the encoder always aware whether the decoder possesses the dynamic table entry (from here on, simply "entry") necessary for decoding a header. The encoder learns this information from messages carried on a single dedicated control stream. The reliable nature of this stream guarantees serialized protocol operation. In request and response streams, header blocks use either literal representations or references to entries that are known to exist in the decoder table. Dynamic table changes are communicated via the control stream. The process of decoding header blocks does not change the decoder state, thus avoiding the HoL blocking. QMIN inherits HPACK's data structures and encoding formats (see [RFC7541]). In addition, *checkpoints* are introduced. A checkpoint is used to track entries added to the dynamic table and streams that reference those entries. Checkpoints are ordered in a list, from newest to oldest. A new checkpoint gets appended to the "new" end of the checkpoint list. Tikhonov Expires May 17, 2018 [Page 3] Internet-Draft QMIN: Header Compression for QUIC November 2017 The encoder always has a checkpoint in the NEW state. Flushing a checkpoint is a two-step operation. First, a FLUSH_CHKPOINT command is sent to the decoder. At that time, the encoder's NEW checkpoint becomes PENDING. The decoder moves its NEW checkpoint directly to LIVE and responds with ACK_FLUSH message. When the encoder receives this message, its PENDING checkpoint becomes LIVE and entries associated with this checkpoint become available for encoding. The encoder always has exactly one NEW checkpoint, zero or one PENDING checkpoints, and zero or more LIVE and DEAD checkpoints. The decoder has exactly one NEW checkpoint and zero or more LIVE checkpoints. Unused entries are evicted indirectly, by dropping checkpoints. Before a checkpoint can be dropped, its state is changed to DEAD: the encoder cannot use an entry for encoding that is not referenced by a LIVE checkpoint. Changing a checkpoint's state to DEAD allows the checkpoint to age out. The encoder can decide to drop a DEAD checkpoint when it is no longer referenced by any active streams. See Section 3. The control stream is used to notify the encoder that the peer is done decoding HTTP headers for a stream using the STREAM_DONE message. The encoder uses this information to track which checkpoints can be dropped. When a checkpoint is dropped, the table entries it references are checked: if an entry is no longer referenced by any checkpoint, the entry is evicted. The encoder sends the DROP_CHKPOINT command to the decoder when it drops a checkpoint; no acknowledgement for this command is necessary. Dropping a checkpoint and the entries associated with it is not limited to just the oldest checkpoint; any DEAD checkpoint -- as long as state transition rules are followed -- may be dropped. This flexibility permits the encoder to use a number of strategies for entry eviction. As long as the maximum dynamic table size is observed, new checkpoints can be created; no upper limit on the number of checkpoints is specified. A well-balanced spread of checkpoints permits the encoder to recycle entries effectively. The HPACK index address space stays the same. The static table stays as-is. Indices are unique between all checkpoints. An index can be reused once no checkpoint references it. Tikhonov Expires May 17, 2018 [Page 4] Internet-Draft QMIN: Header Compression for QUIC November 2017 3. Checkpoint States A checkpoint can be in one of several states. It goes through these states in order, without skipping any, throughout its lifetime. On the encoder, the checkpoint states are: o NEW o PENDING o LIVE o DEAD On the decoder, only two states are used: o NEW o LIVE 3.1. Checkpoint State: NEW Applicability: encoder and decoder. All newly reused or inserted entries are referred to by the NEW checkpoint. There is always a NEW checkpoint. Whenever this checkpoint changes state, a new NEW checkpoint is created. The encoder and the decoder both begin with an empty NEW checkpoint. 3.2. Checkpoint State: PENDING Applicability: encoder only. At some point, the encoder may want to flush new entries. It then changes the NEW checkpoint state to PENDING and issues the FLUSH_CHKPOINT command. The entries in the PENDING checkpoint cannot be used for encoding yet; the encoder waits for ACK_FLUSH message. Upon receipt of this message, the PENDING checkpoint changes to the LIVE state. There can be at most one PENDING checkpoint. 3.3. Checkpoint State: LIVE Applicability: encoder and decoder. Entries that were added to the dynamic table when this checkpoint was in the NEW state can now be used to encode and decode headers. The decoder moves its NEW checkpoint to LIVE when it receives the Tikhonov Expires May 17, 2018 [Page 5] Internet-Draft QMIN: Header Compression for QUIC November 2017 FLUSH_CHKPOINT command. The encoder moves its PENDING checkpoint to LIVE when it receives the ACK_FLUSH message. Other than the maximum table size, the number of LIVE checkpoints is not limited. 3.4. Checkpoint State: DEAD Applicability: encoder only. To evict old entries, the encoder marks a LIVE checkpoint as DEAD. (An entry that is not referenced by any LIVE checkpoint cannot be used for header encoding. Marking a checkpoint DEAD allows entries to age out.) When all streams whose header blocks were encoded using entries referenced by this checkpoint have been closed, the checkpoint is destroyed and the DROP_CHKPOINT message is sent to the decoder. There can be any number of DEAD checkpoints. 4. Control Stream The control stream is used to carry messages to the encoder and the decoder. This is the only way that dynamic table changes are communicated to the decoder. The messages are either o Commands issued by the encoder to the decoder; o Acknowledgements issued by the decoder; or o Stream processed notifications sent to the encoder. The format of the messages is similar in structure to the format of the encoded header fields in the header block as specified in HPACK (RFC 7541, Section 6). The same variable-length integer encoding mechanism is used (RFC 7541, Section 5). 4.1. Encoder Commands The encoder issues the following commands: 4.1.1. INSERT_ENTRY This message is sent by the encoder at the same time it creates a new indexed entry in its dynamic table. The smallest unused index in the address space ( [62 - oO] ) MUST be assigned to the new entry. Tikhonov Expires May 17, 2018 [Page 6] Internet-Draft QMIN: Header Compression for QUIC November 2017 The decoder creates the new entry in the table, but does not make the entry available for decoding yet. If indexed name representation is used, but the decoder does not have this entry already referenced by its NEW checkpoint, it MUST treat it as an error. The format of this message is identical to HPACK's Literal Header Field Representation (RFC 7541, Section 6.2). 0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | 0 | 1 | Index (6+) | +---+---+-----------------------+ | H | Value Length (7+) | +---+---------------------------+ | Value String (Length octets) | +-------------------------------+ Figure: Insert Entry - Indexed Name 0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | 0 | 1 | 0 | +---+---+-----------------------+ | H | Name Length (7+) | +---+---------------------------+ | Name String (Length octets) | +---+---------------------------+ | H | Value Length (7+) | +---+---------------------------+ | Value String (Length octets) | +-------------------------------+ Figure: Insert Entry - New Name 4.1.2. REUSE_ENTRY This message is issued instead of INSERT_ENTRY whenever the encoder uses an indexed representation from an existing LIVE checkpoint to encode a header and this index has not yet been added to the NEW checkpoint. Upon receipt of the REUSE_ENTRY command, the decoder creates a reference to the corresponding entry in its NEW checkpoint. The encoder MUST NOT issue multiple REUSE_ENTRY commands for the same entry in the context of the same NEW checkpoint. If the decoder receives the REUSE_ENTRY message that specifies an index already referenced by its NEW checkpoint, it MUST treat it as an error. If a Tikhonov Expires May 17, 2018 [Page 7] Internet-Draft QMIN: Header Compression for QUIC November 2017 non-existent index is specified, the decoder MUST treat is as an error. The format of this message is identical to HPACK's Indexed Header Field Representation (RFC 7541, Section 6.1). 0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | 1 | Index (7+) | +---+---------------------------+ Figure: Reuse Entry Message 4.1.3. FLUSH_CHKPOINT When the encoder wants to start using entries associated with the NEW checkpoint, it moves it from NEW to PENDING state and issues the FLUSH_CHKPOINT command. The decoder moves its checkpoint from NEW to LIVE: all newly inserted entries become available for decoding. 0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | +---+---------------------------+ Figure: Flush Checkpoint 4.1.4. DROP_CHKPOINT When a DEAD checkpoint is no longer referenced by any streams, the encoder MAY drop it. This means evicting all dynamic table entries whose reference counts have gone to zero and issuing the DROP_CHKPOINT command. The ID of the checkpoint to drop is its current position in the checkpoint list, from oldest to newest. Thus, the oldest checkpoint has ID 0, second-oldest has ID 1, and so on. The decoder performs the same operation as the encoder: decrements reference counts of dynamic table entries -- evicting those whose reference counts are now zero -- and drops the specified checkpoint. Tikhonov Expires May 17, 2018 [Page 8] Internet-Draft QMIN: Header Compression for QUIC November 2017 0 1 2 3 4 5 6 7 +---+---+---+---+---+---+----+----+ | 0 | 0 | 0 | 0 | 0 | 1 | ID (2+) | +---+------------------------+----+ Figure: Drop Checkpoint 4.2. Decoder Messages The decoder sends replies to one of the encoder commands. 4.2.1. ACK_FLUSH The decoder SHOULD inform the encoder that it has performed the flush using ACK_FLUSH message. The encoder's PENDING checkpoint becomes LIVE when this acknowledgement is received. 0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | +---+---------------------------+ Figure: Ack Flush 4.3. Stream Notification Commands 4.3.1. STREAM_DONE When all HTTP headers for a stream have been decoded, this message is sent to inform the encoder that the peer is done with the stream. This allows the encoder to decrement its reference counts, potentially triggering a checkpoint flush or a checkpoint drop. It is preferable to send this message as soon as possible. For example, one does not have to wait until stream FIN is read if HTTP headers have been decoded and there are no trailers. 0 1 2 3 4 5 6 7 +---+---+---+---+---+----+-----+-----+ | 0 | 0 | 0 | 0 | 1 | Stream ID (3+) | +---+--------------------------------+ Figure: Stream Done The client knows that the server is done with the request if the stream is reset or it has read all of the response. A QMIN implementation SHOULD use this knowledge to let the encoder know that Tikhonov Expires May 17, 2018 [Page 9] Internet-Draft QMIN: Header Compression for QUIC November 2017 the stream is done. The encoder SHOULD use the earliest indicator to move its mechanisms along. Any subsequent indicators are no-ops. 4.4. Expansion Two bit patterns are still available to the command coding scheme: 001 and 00000001. The former is used to encode the dynamic table size update by HPACK (RFC 7541, Section 6.3). There is no inherent limitation in QMIN as to why it could not support this command. 5. Header Encoding The headers are encoded in the same way they are encoded by HPACK, except QMIN does not support the dynamic table size update specified in RFC 7541, Section 6.3 in the headers block. This is because header block decoding is not to change the decoder state. 6. Table Size Calculation HPACK defines the dynamic table size as "the sum of the size of its entries." (RFC 7541, Section 4.1). QMIN's dynamic table entry carries another element -- reference count -- which increases the entry size. QMIN introduces checkpoints, whose size should also be accounted for. A decoder-side checkpoint keeps track of the index values created or reused when it was NEW. 6.1. Entry Size A QMIN entry contains a reference count, which makes it larger that the HPACK entry. Using a standard integer size, the QMIN entry overhead is set to 36 bytes: 32 bytes overhead of the HPACK entry plus four bytes for the additional reference count field. Thus, the QMIN entry size is the sum of the entry name size, the entry value size, and 36. 6.2. Checkpoint Size QMIN uses the smallest possible available value (Section 4.1.2) in the index address space for new entries. Therefore, the total number of index values is at most the value of the largest index in use. A checkpoint can track indices via a bitmask: 1 bit per index. The size of a checkpoint, then, is defined as (Highest Index Value - 62) / 8 + 128 The additional 128 bytes is the checkpoint overhead. Tikhonov Expires May 17, 2018 [Page 10] Internet-Draft QMIN: Header Compression for QUIC November 2017 6.3. Overall Table Size The decoder table size is calculated as number of entries times the entry size as calculated in Section 6.1 plus the number of checkpoints times the checkpoint size as calculated in Section 6.2. 6.4. Comparison with HPACK In HPACK, a table with 700 dynamic entries and 35,000 bytes allocated to header names and values is 700 * 32 + 35,000 = 57,400 bytes. The same table in QMIN with 10 checkpoints is 700 * 36 + 35,000 + 10 * ((1000 / 8) + 128) = 62,730 bytes. This is a 9% increase in memory consumption. 7. Encoding Process Given a header field to compress, the encoder returns the compressed representation of it. In addition, it may emit one or more commands that should be sent on the control stream. 7.1. Indexable Header Fields An indexable header field is that which the user specifies as "with indexing" (RFC 7541, Section 6.2). 7.1.1. New Index If no matching entry is found, a new entry is created, its ID is recorded in the NEW checkpoint, and the encoder emits the INSERT_ENTRY command. If the encoded name component refers to an existing entry, this entry is reused as described in Section 7.1.2. 7.1.2. Existing Index An indexable header field causes the encoder to search the table. If an existing dynamic table entry is found that is referenced by at least one LIVE checkpoint, it can be used to encode the header field. The encoder records a reference to the stream using this entry in one of the checkpoints. (Which checkpoint to select can be decided based on strategy. See Section 9.1). Tikhonov Expires May 17, 2018 [Page 11] Internet-Draft QMIN: Header Compression for QUIC November 2017 If the NEW checkpoint does not have a reference to this entry, the reference is recorded in the NEW checkpoint and the REUSE_ENTRY command is emitted. 7.2. Non-indexable Header Fields Non-indexable header fields are compressed the same way as HPACK (RFC 7541, Sections 6.2.2 and 6.2.3). The encoder state is not changed. No command is emitted. 7.3. When Maximum Table Size Is Reached When the encoder table reaches its maximum size, further insertions into the dynamic table are not possible. In this case, the encoder compresses header fields without inserting or reusing entries and without emitting any commands. A simple recovery strategy is to mark one or more checkpoints DEAD immediately. Alternatively, the existing table may provide an acceptable compression level. It may be more efficient to wait until this level falls below a threshold before marking checkpoints DEAD, as it may become possible to drop an already-DEAD checkpoint before the threshold is reached. The encoder SHOULD try to avoid reaching a point when it can no longer insert new entries. See Section 9. 7.4. Memory Cost of Flushing Because flushing automatically creates a new NEW checkpoint, it is possible to get into a situation where a flush is not possible due to the memory constraint. If inserting a new entry would result in subsequent inability to flush, the encoder SHOULD flush instead. 8. Decoding Process All header field representations defined in HPACK (Section 6 of [RFC7541]) are used as-is. Dynamic size update (Ibid., Section 6.3) or an unknown command MUST be treated as an error. The decoder looks up dynamic entries in its table when it is given a header list to decode. If corresponding entry is not found or if it is found but not referred to by any of LIVE checkpoints, this MUST be treated as an error. Tikhonov Expires May 17, 2018 [Page 12] Internet-Draft QMIN: Header Compression for QUIC November 2017 9. Encoder Strategies 9.1. Flushing and Dropping The encoder decides when to flush checkpoints and when to declare them dead. Flushing SHOULD occur when enough new entries have been created to try to reuse them. Marking checkpoints as DEAD SHOULD happen before the table size is exhausted. If an entry used to encode a header field is referenced to by more than one LIVE checkpoint, one of them is selected to refer to the stream ID whose header field has been encoded. Which LIVE checkpoint to pick is a decision that also affects compression performance. Several strategies are outlined below. 9.1.1. Simple Strategy The encoder picks a number of streams to use as a threshold for flushing checkpoints. Every time header blocks for N streams have been encoded, flush. The encoder picks the oldest checkpoint to mark as DEAD. It does so when table size reaches some proportion, let's say 3/4, of the maximum table size. The newest LIVE checkpoint that references an entry used for encoding is picked to record the stream ID. This strategy is estimated to work well most of the time due to the temporal aspect of the checkpoint dropping policy. When a connection is used to serve a small number of requests, however, the compression will be overall suboptimal, as the initial period when no dynamic table is available for encoding is amortized poorly. 9.1.2. Rule-Based Strategy Heuristic rules may provide performance improvement over the simple strategy above. For example: o Flush very often, perhaps once for every new stream, when the number of dynamic entries is very small (such as when the encoder has just been instantiated). Since the table size is likely to be small when only few dynamic entries exist, one can fit a lot of checkpoints and still be able to add new entries to the table. These early-flushed checkpoints will also be easier to drop later, as they are not referenced by many streams. Tikhonov Expires May 17, 2018 [Page 13] Internet-Draft QMIN: Header Compression for QUIC November 2017 o Flush when the number of newly added entries is 1/10 of the number of existing entries. When this many new entries have been added, it is a likely indicator making them available for encoding will improve overall compression. o When declaring a checkpoint DEAD: * Pick a LIVE checkpoint that is referenced by the fewest existing streams; or * Pick a LIVE checkpoint that references the largest number of old entries, where an "old" entry is that which has not been used for encoding in a period of some number of checkpoints. Other rules are possible. 9.1.3. Feedback-Based Strategy The goal of QMIN is to produce the best compression. The compression level can be computed by dividing the sum of the sizes of all header fields submitted for compression by the number of compressed bytes returned *plus* the size of all commands sent to the decoder. A checkpoint can be taken as unit of time and a decaying average can be computed. Availability of entries that can be used for compression directly affects compression performance. This availability, in turn, is a function of how often checkpoints are flushed and which checkpoints are marked for deletion. Flushing very often costs memory; infrequent flushing delays entry availability. It is possible to come up with a dynamic function that adjusts these parameters based on feedback: the compression performance. 9.2. Control Channel Cost Sending commands on the control channel affects the overall compression level. Sending an INSERT_ENTRY command for a header field that is never reused is more expensive than not inserting the field at all. A single large, ever-changing HTTP header (for example, session state in a cookie) could defeat the compression mechanism. The encoder SHOULD prevent this from happening. Since a header field that repeats is likely to repeat more than once, a simple conservative approach is never to insert a header field that is not known to have repeated. Because HTTP header names are relatively small and not as numerous as the header values, it is possible to maintain a history of a number of recently compressed header fields. (To use less memory, hashes of header values, instead of the values themselves, can be stored.) The encoder can consult Tikhonov Expires May 17, 2018 [Page 14] Internet-Draft QMIN: Header Compression for QUIC November 2017 this history and only issue an INSERT_ENTRY command if the header field has been seen before. 10. HPACK Interoperability Because QMIN uses the same binary format as HPACK, the two are interoperable. This makes it possible for peers to use the current HTTP/QUIC HPACK mechanism to talk to peers that use QMIN. It is useful: all implementations do not have to start using QMIN at the same time. For this to work, four things must be true: 1. The HPACK side must advertise maximum dynamic table size of zero. 2. The HPACK side must not send dynamic table size updates. 3. The HPACK side must consume and discard data sent on the control stream. This is so that QMIN sender does not get stuck when it reaches the stream flow control limit. 4. The HPACK side must assume that peer's dynamic table size is zero. This is to prevent HPACK encoder from relying on dynamic entries. (1) and (2) are already true according to [I-D.ietf-quic-http]. (3) and (4) are trivial modifications. 11. Implementation Notes 11.1. Control Messages Made Easy Since INSERT_ENTRY and REUSE_ENTRY messages are identical to the encoded header field representation, the latter can be placed onto the control stream verbatim. Generate once, use twice. 12. QMIN Drawbacks The following QMIN properties affect compression negatively: o All insertion commands are duplicated: they are sent both as literal representation in headers block and as insertion commands on the control stream. o A new entry cannot be used until the checkpoint is flushed and the encoder receives ACK_FLUSH message. Until that time, the header field literal representation must be used for subsequent encodings. Tikhonov Expires May 17, 2018 [Page 15] Internet-Draft QMIN: Header Compression for QUIC November 2017 13. Acknowledgements QMIN is based on HPACK ([RFC7540]); I am thankful to its authors. Observations of the following members of the IETF QUIC WG have been particularly insightful: o Alan Frindell; o Charles 'Buck' Krasic; and o Mike Bishop. Finally, my colleagues at LiteSpeed Technologies reviewed the rough draft and provided valuable feedback: o George Wang; o Ron Saad. 14. References 14.1. Normative References [RFC7540] Belshe, M., Peon, R., and M. Thomson, Ed., "Hypertext Transfer Protocol Version 2 (HTTP/2)", RFC 7540, DOI 10.17487/RFC7540, May 2015, . [RFC7541] Peon, R. and H. Ruellan, "HPACK: Header Compression for HTTP/2", RFC 7541, DOI 10.17487/RFC7541, May 2015, . 14.2. Informative References [I-D.ietf-quic-http] Bishop, M., "Hypertext Transfer Protocol (HTTP) over QUIC", draft-ietf-quic-http-07 (work in progress), October 2017. Author's Address Dmitri Tikhonov LiteSpeed Technologies Email: dtikhonov@litespeedtech.com Tikhonov Expires May 17, 2018 [Page 16]