github.com/icodeface/tls@v0.0.0-20230910023335-34df9250cd12/internal/x/net/http2/hpack/huffman.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package hpack 6 7 import ( 8 "bytes" 9 "errors" 10 "io" 11 "sync" 12 ) 13 14 var bufPool = sync.Pool{ 15 New: func() interface{} { return new(bytes.Buffer) }, 16 } 17 18 // HuffmanDecode decodes the string in v and writes the expanded 19 // result to w, returning the number of bytes written to w and the 20 // Write call's return value. At most one Write call is made. 21 func HuffmanDecode(w io.Writer, v []byte) (int, error) { 22 buf := bufPool.Get().(*bytes.Buffer) 23 buf.Reset() 24 defer bufPool.Put(buf) 25 if err := huffmanDecode(buf, 0, v); err != nil { 26 return 0, err 27 } 28 return w.Write(buf.Bytes()) 29 } 30 31 // HuffmanDecodeToString decodes the string in v. 32 func HuffmanDecodeToString(v []byte) (string, error) { 33 buf := bufPool.Get().(*bytes.Buffer) 34 buf.Reset() 35 defer bufPool.Put(buf) 36 if err := huffmanDecode(buf, 0, v); err != nil { 37 return "", err 38 } 39 return buf.String(), nil 40 } 41 42 // ErrInvalidHuffman is returned for errors found decoding 43 // Huffman-encoded strings. 44 var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data") 45 46 // huffmanDecode decodes v to buf. 47 // If maxLen is greater than 0, attempts to write more to buf than 48 // maxLen bytes will return ErrStringLength. 49 func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error { 50 rootHuffmanNode := getRootHuffmanNode() 51 n := rootHuffmanNode 52 // cur is the bit buffer that has not been fed into n. 53 // cbits is the number of low order bits in cur that are valid. 54 // sbits is the number of bits of the symbol prefix being decoded. 55 cur, cbits, sbits := uint(0), uint8(0), uint8(0) 56 for _, b := range v { 57 cur = cur<<8 | uint(b) 58 cbits += 8 59 sbits += 8 60 for cbits >= 8 { 61 idx := byte(cur >> (cbits - 8)) 62 n = n.children[idx] 63 if n == nil { 64 return ErrInvalidHuffman 65 } 66 if n.children == nil { 67 if maxLen != 0 && buf.Len() == maxLen { 68 return ErrStringLength 69 } 70 buf.WriteByte(n.sym) 71 cbits -= n.codeLen 72 n = rootHuffmanNode 73 sbits = cbits 74 } else { 75 cbits -= 8 76 } 77 } 78 } 79 for cbits > 0 { 80 n = n.children[byte(cur<<(8-cbits))] 81 if n == nil { 82 return ErrInvalidHuffman 83 } 84 if n.children != nil || n.codeLen > cbits { 85 break 86 } 87 if maxLen != 0 && buf.Len() == maxLen { 88 return ErrStringLength 89 } 90 buf.WriteByte(n.sym) 91 cbits -= n.codeLen 92 n = rootHuffmanNode 93 sbits = cbits 94 } 95 if sbits > 7 { 96 // Either there was an incomplete symbol, or overlong padding. 97 // Both are decoding errors per RFC 7541 section 5.2. 98 return ErrInvalidHuffman 99 } 100 if mask := uint(1<<cbits - 1); cur&mask != mask { 101 // Trailing bits must be a prefix of EOS per RFC 7541 section 5.2. 102 return ErrInvalidHuffman 103 } 104 105 return nil 106 } 107 108 type node struct { 109 // children is non-nil for internal nodes 110 children *[256]*node 111 112 // The following are only valid if children is nil: 113 codeLen uint8 // number of bits that led to the output of sym 114 sym byte // output symbol 115 } 116 117 func newInternalNode() *node { 118 return &node{children: new([256]*node)} 119 } 120 121 var ( 122 buildRootOnce sync.Once 123 lazyRootHuffmanNode *node 124 ) 125 126 func getRootHuffmanNode() *node { 127 buildRootOnce.Do(buildRootHuffmanNode) 128 return lazyRootHuffmanNode 129 } 130 131 func buildRootHuffmanNode() { 132 if len(huffmanCodes) != 256 { 133 panic("unexpected size") 134 } 135 lazyRootHuffmanNode = newInternalNode() 136 for i, code := range huffmanCodes { 137 addDecoderNode(byte(i), code, huffmanCodeLen[i]) 138 } 139 } 140 141 func addDecoderNode(sym byte, code uint32, codeLen uint8) { 142 cur := lazyRootHuffmanNode 143 for codeLen > 8 { 144 codeLen -= 8 145 i := uint8(code >> codeLen) 146 if cur.children[i] == nil { 147 cur.children[i] = newInternalNode() 148 } 149 cur = cur.children[i] 150 } 151 shift := 8 - codeLen 152 start, end := int(uint8(code<<shift)), int(1<<shift) 153 for i := start; i < start+end; i++ { 154 cur.children[i] = &node{sym: sym, codeLen: codeLen} 155 } 156 } 157 158 // AppendHuffmanString appends s, as encoded in Huffman codes, to dst 159 // and returns the extended buffer. 160 func AppendHuffmanString(dst []byte, s string) []byte { 161 rembits := uint8(8) 162 163 for i := 0; i < len(s); i++ { 164 if rembits == 8 { 165 dst = append(dst, 0) 166 } 167 dst, rembits = appendByteToHuffmanCode(dst, rembits, s[i]) 168 } 169 170 if rembits < 8 { 171 // special EOS symbol 172 code := uint32(0x3fffffff) 173 nbits := uint8(30) 174 175 t := uint8(code >> (nbits - rembits)) 176 dst[len(dst)-1] |= t 177 } 178 179 return dst 180 } 181 182 // HuffmanEncodeLength returns the number of bytes required to encode 183 // s in Huffman codes. The result is round up to byte boundary. 184 func HuffmanEncodeLength(s string) uint64 { 185 n := uint64(0) 186 for i := 0; i < len(s); i++ { 187 n += uint64(huffmanCodeLen[s[i]]) 188 } 189 return (n + 7) / 8 190 } 191 192 // appendByteToHuffmanCode appends Huffman code for c to dst and 193 // returns the extended buffer and the remaining bits in the last 194 // element. The appending is not byte aligned and the remaining bits 195 // in the last element of dst is given in rembits. 196 func appendByteToHuffmanCode(dst []byte, rembits uint8, c byte) ([]byte, uint8) { 197 code := huffmanCodes[c] 198 nbits := huffmanCodeLen[c] 199 200 for { 201 if rembits > nbits { 202 t := uint8(code << (rembits - nbits)) 203 dst[len(dst)-1] |= t 204 rembits -= nbits 205 break 206 } 207 208 t := uint8(code >> (nbits - rembits)) 209 dst[len(dst)-1] |= t 210 211 nbits -= rembits 212 rembits = 8 213 214 if nbits == 0 { 215 break 216 } 217 218 dst = append(dst, 0) 219 } 220 221 return dst, rembits 222 }