RFC Errata


Errata Search

 
Source of RFC  
Summary Table Full Records

RFC 9204, "QPACK: Field Compression for HTTP/3", June 2022

Source of RFC: quic (wit)
See Also: RFC 9204 w/ inline errata

Errata ID: 8410
Status: Verified
Type: Technical
Publication Format(s) : TEXT, PDF, HTML

Reported By: Kazu Yamamoto
Date Reported: 2025-05-08
Verifier Name: Mike Bishop
Date Verified: 2025-06-02

Section Appendix C says:

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

It should say:

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)

Report New Errata



Advanced Search