The following errata report has been submitted for RFC9204, "QPACK: Field Compression for HTTP/3".
-------------------------------------- You may review the report below and at: https://www.rfc-editor.org/errata/eid8410 -------------------------------------- Type: Technical Reported by: Kazu Yamamoto <k...@iij.ad.jp> Section: Appendix C Original Text ------------- base = dynamicTable.getInsertCount() requiredInsertCount = 0 for line in fieldLines: staticIndex = staticTable.findIndex(line) if staticIndex is not None: encodeStaticIndexReference(streamBuffer, staticIndex) continue dynamicIndex = dynamicTable.findIndex(line) if dynamicIndex is None: # No matching entry. Either insert+index or encode literal staticNameIndex = staticTable.findName(line.name) if staticNameIndex is None: dynamicNameIndex = dynamicTable.findName(line.name) if shouldIndex(line) and dynamicTable.canIndex(line): encodeInsert(encoderBuffer, staticNameIndex, dynamicNameIndex, line) dynamicIndex = dynamicTable.add(line) if dynamicIndex is None: # Could not index it, literal if dynamicNameIndex is not None: # Encode literal with dynamic name, possibly above Base encodeDynamicLiteral(streamBuffer, dynamicNameIndex, base, line) requiredInsertCount = max(requiredInsertCount, dynamicNameIndex) else: # Encodes a literal with a static name or literal name encodeLiteral(streamBuffer, staticNameIndex, line) else: # Dynamic index reference assert(dynamicIndex is not None) requiredInsertCount = max(requiredInsertCount, dynamicIndex) # Encode dynamicIndex, possibly above Base encodeDynamicIndexReference(streamBuffer, dynamicIndex, base) # encode the prefix if requiredInsertCount == 0: encodeInteger(prefixBuffer, 0x00, 0, 8) encodeInteger(prefixBuffer, 0x00, 0, 7) else: wireRIC = ( requiredInsertCount % (2 * getMaxEntries(maxTableCapacity)) ) + 1; encodeInteger(prefixBuffer, 0x00, wireRIC, 8) if base >= requiredInsertCount: encodeInteger(prefixBuffer, 0x00, base - requiredInsertCount, 7) else: encodeInteger(prefixBuffer, 0x80, requiredInsertCount - base - 1, 7) return encoderBuffer, prefixBuffer + streamBuffer Corrected Text -------------- base = dynamicTable.getInsertCount() requiredInsertCount = 0 for line in fieldLines: staticIndex = staticTable.findIndex(line) if staticIndex is not None: encodeStaticIndexReference(streamBuffer, staticIndex) continue dynamicIndex = dynamicTable.findIndex(line) if dynamicIndex is None: # No matching entry. Either insert+index or encode literal staticNameIndex = staticTable.findName(line.name) if staticNameIndex is None: dynamicNameIndex = dynamicTable.findName(line.name) if shouldIndex(line) and dynamicTable.canIndex(line): encodeInsert(encoderBuffer, staticNameIndex, dynamicNameIndex, line) dynamicIndex = dynamicTable.add(line) if dynamicIndex is None: # Could not index it, literal if dynamicNameIndex is not None: # Encode literal with dynamic name, possibly above Base encodeDynamicLiteral(streamBuffer, dynamicNameIndex, base, line) requiredInsertCount = max(requiredInsertCount, dynamicNameIndex + 1) else: # Encodes a literal with a static name or literal name encodeLiteral(streamBuffer, staticNameIndex, line) else: # Dynamic index reference assert(dynamicIndex is not None) requiredInsertCount = max(requiredInsertCount, dynamicIndex + 1) # Encode dynamicIndex, possibly above Base encodeDynamicIndexReference(streamBuffer, dynamicIndex, base) # encode the prefix if requiredInsertCount == 0: encodeInteger(prefixBuffer, 0x00, 0, 8) encodeInteger(prefixBuffer, 0x00, 0, 7) else: wireRIC = ( requiredInsertCount % (2 * getMaxEntries(maxTableCapacity)) ) + 1; encodeInteger(prefixBuffer, 0x00, wireRIC, 8) if base >= requiredInsertCount: encodeInteger(prefixBuffer, 0x00, base - requiredInsertCount, 7) else: encodeInteger(prefixBuffer, 0x80, requiredInsertCount - base - 1, 7) return encoderBuffer, prefixBuffer + streamBuffer Notes ----- "Sample Single-Pass Encoding Algorithm" in Appendix C has a bug that Count is equel to the index. Count must be one higher than index. Reasoning the code: requiredInsertCount is initialized with 0: requiredInsertCount = 0 dynamicIndex can be 0 if it is the first entry of the dynamic table: dynamicIndex = dynamicTable.findIndex(line) In this case, requiredInsertCount stay with 0: requiredInsertCount = max(requiredInsertCount, dynamicIndex) This results in a wrong prefix: if requiredInsertCount == 0: encodeInteger(prefixBuffer, 0x00, 0, 8) encodeInteger(prefixBuffer, 0x00, 0, 7) The following code is correct: requiredInsertCount = max(requiredInsertCount, dynamicIndex + 1) Instructions: ------------- This erratum is currently posted as "Reported". (If it is spam, it will be removed shortly by the RFC Production Center.) Please use "Reply All" to discuss whether it should be verified or rejected. When a decision is reached, the verifying party will log in to change the status and edit the report, if necessary. -------------------------------------- RFC9204 (draft-ietf-quic-qpack-21) -------------------------------------- Title : QPACK: Field Compression for HTTP/3 Publication Date : June 2022 Author(s) : C. Krasic, M. Bishop, A. Frindell, Ed. Category : PROPOSED STANDARD Source : QUIC Stream : IETF Verifying Party : IESG