encoder.go 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. package qpack
  2. import (
  3. "io"
  4. "golang.org/x/net/http2/hpack"
  5. )
  6. // An Encoder performs QPACK encoding.
  7. type Encoder struct {
  8. wrotePrefix bool
  9. w io.Writer
  10. buf []byte
  11. }
  12. // NewEncoder returns a new Encoder which performs QPACK encoding. An
  13. // encoded data is written to w.
  14. func NewEncoder(w io.Writer) *Encoder {
  15. return &Encoder{w: w}
  16. }
  17. // WriteField encodes f into a single Write to e's underlying Writer.
  18. // This function may also produce bytes for the Header Block Prefix
  19. // if necessary. If produced, it is done before encoding f.
  20. func (e *Encoder) WriteField(f HeaderField) error {
  21. // write the Header Block Prefix
  22. if !e.wrotePrefix {
  23. e.buf = appendVarInt(e.buf, 8, 0)
  24. e.buf = appendVarInt(e.buf, 7, 0)
  25. e.wrotePrefix = true
  26. }
  27. idxAndVals, nameFound := encoderMap[f.Name]
  28. if nameFound {
  29. if idxAndVals.values == nil {
  30. if len(f.Value) == 0 {
  31. e.writeIndexedField(idxAndVals.idx)
  32. } else {
  33. e.writeLiteralFieldWithNameReference(&f, idxAndVals.idx)
  34. }
  35. } else {
  36. valIdx, valueFound := idxAndVals.values[f.Value]
  37. if valueFound {
  38. e.writeIndexedField(valIdx)
  39. } else {
  40. e.writeLiteralFieldWithNameReference(&f, idxAndVals.idx)
  41. }
  42. }
  43. } else {
  44. e.writeLiteralFieldWithoutNameReference(f)
  45. }
  46. _, err := e.w.Write(e.buf)
  47. e.buf = e.buf[:0]
  48. return err
  49. }
  50. // Close declares that the encoding is complete and resets the Encoder
  51. // to be reused again for a new header block.
  52. func (e *Encoder) Close() error {
  53. e.wrotePrefix = false
  54. return nil
  55. }
  56. func (e *Encoder) writeLiteralFieldWithoutNameReference(f HeaderField) {
  57. offset := len(e.buf)
  58. e.buf = appendVarInt(e.buf, 3, hpack.HuffmanEncodeLength(f.Name))
  59. e.buf[offset] ^= 0x20 ^ 0x8
  60. e.buf = hpack.AppendHuffmanString(e.buf, f.Name)
  61. offset = len(e.buf)
  62. e.buf = appendVarInt(e.buf, 7, hpack.HuffmanEncodeLength(f.Value))
  63. e.buf[offset] ^= 0x80
  64. e.buf = hpack.AppendHuffmanString(e.buf, f.Value)
  65. }
  66. // Encodes a header field whose name is present in one of the tables.
  67. func (e *Encoder) writeLiteralFieldWithNameReference(f *HeaderField, id uint8) {
  68. offset := len(e.buf)
  69. e.buf = appendVarInt(e.buf, 4, uint64(id))
  70. // Set the 01NTxxxx pattern, forcing N to 0 and T to 1
  71. e.buf[offset] ^= 0x50
  72. offset = len(e.buf)
  73. e.buf = appendVarInt(e.buf, 7, hpack.HuffmanEncodeLength(f.Value))
  74. e.buf[offset] ^= 0x80
  75. e.buf = hpack.AppendHuffmanString(e.buf, f.Value)
  76. }
  77. // Encodes an indexed field, meaning it's entirely defined in one of the tables.
  78. func (e *Encoder) writeIndexedField(id uint8) {
  79. offset := len(e.buf)
  80. e.buf = appendVarInt(e.buf, 6, uint64(id))
  81. // Set the 1Txxxxxx pattern, forcing T to 1
  82. e.buf[offset] ^= 0xc0
  83. }