Brad Fitzpatrick | 7a3dcd2 | 2015-10-14 03:37:10 +0000 | [diff] [blame] | 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 implements HPACK, a compression format for |
| 6 | // efficiently representing HTTP header fields in the context of HTTP/2. |
| 7 | // |
| 8 | // See http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09 |
| 9 | package hpack |
| 10 | |
| 11 | import ( |
| 12 | "bytes" |
| 13 | "errors" |
| 14 | "fmt" |
| 15 | ) |
| 16 | |
| 17 | // A DecodingError is something the spec defines as a decoding error. |
| 18 | type DecodingError struct { |
| 19 | Err error |
| 20 | } |
| 21 | |
| 22 | func (de DecodingError) Error() string { |
| 23 | return fmt.Sprintf("decoding error: %v", de.Err) |
| 24 | } |
| 25 | |
| 26 | // An InvalidIndexError is returned when an encoder references a table |
| 27 | // entry before the static table or after the end of the dynamic table. |
| 28 | type InvalidIndexError int |
| 29 | |
| 30 | func (e InvalidIndexError) Error() string { |
| 31 | return fmt.Sprintf("invalid indexed representation index %d", int(e)) |
| 32 | } |
| 33 | |
| 34 | // A HeaderField is a name-value pair. Both the name and value are |
| 35 | // treated as opaque sequences of octets. |
| 36 | type HeaderField struct { |
| 37 | Name, Value string |
| 38 | |
| 39 | // Sensitive means that this header field should never be |
| 40 | // indexed. |
| 41 | Sensitive bool |
| 42 | } |
| 43 | |
| 44 | func (hf *HeaderField) size() uint32 { |
| 45 | // http://http2.github.io/http2-spec/compression.html#rfc.section.4.1 |
| 46 | // "The size of the dynamic table is the sum of the size of |
| 47 | // its entries. The size of an entry is the sum of its name's |
| 48 | // length in octets (as defined in Section 5.2), its value's |
| 49 | // length in octets (see Section 5.2), plus 32. The size of |
| 50 | // an entry is calculated using the length of the name and |
| 51 | // value without any Huffman encoding applied." |
| 52 | |
| 53 | // This can overflow if somebody makes a large HeaderField |
| 54 | // Name and/or Value by hand, but we don't care, because that |
| 55 | // won't happen on the wire because the encoding doesn't allow |
| 56 | // it. |
| 57 | return uint32(len(hf.Name) + len(hf.Value) + 32) |
| 58 | } |
| 59 | |
| 60 | // A Decoder is the decoding context for incremental processing of |
| 61 | // header blocks. |
| 62 | type Decoder struct { |
| 63 | dynTab dynamicTable |
| 64 | emit func(f HeaderField) |
| 65 | |
| 66 | emitEnabled bool // whether calls to emit are enabled |
| 67 | maxStrLen int // 0 means unlimited |
| 68 | |
| 69 | // buf is the unparsed buffer. It's only written to |
| 70 | // saveBuf if it was truncated in the middle of a header |
| 71 | // block. Because it's usually not owned, we can only |
| 72 | // process it under Write. |
| 73 | buf []byte // not owned; only valid during Write |
| 74 | |
| 75 | // saveBuf is previous data passed to Write which we weren't able |
| 76 | // to fully parse before. Unlike buf, we own this data. |
| 77 | saveBuf bytes.Buffer |
| 78 | } |
| 79 | |
| 80 | // NewDecoder returns a new decoder with the provided maximum dynamic |
| 81 | // table size. The emitFunc will be called for each valid field |
| 82 | // parsed, in the same goroutine as calls to Write, before Write returns. |
| 83 | func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decoder { |
| 84 | d := &Decoder{ |
| 85 | emit: emitFunc, |
| 86 | emitEnabled: true, |
| 87 | } |
| 88 | d.dynTab.allowedMaxSize = maxDynamicTableSize |
| 89 | d.dynTab.setMaxSize(maxDynamicTableSize) |
| 90 | return d |
| 91 | } |
| 92 | |
| 93 | // ErrStringLength is returned by Decoder.Write when the max string length |
| 94 | // (as configured by Decoder.SetMaxStringLength) would be violated. |
| 95 | var ErrStringLength = errors.New("hpack: string too long") |
| 96 | |
| 97 | // SetMaxStringLength sets the maximum size of a HeaderField name or |
| 98 | // value string. If a string exceeds this length (even after any |
| 99 | // decompression), Write will return ErrStringLength. |
| 100 | // A value of 0 means unlimited and is the default from NewDecoder. |
| 101 | func (d *Decoder) SetMaxStringLength(n int) { |
| 102 | d.maxStrLen = n |
| 103 | } |
| 104 | |
| 105 | // SetEmitEnabled controls whether the emitFunc provided to NewDecoder |
| 106 | // should be called. The default is true. |
| 107 | // |
| 108 | // This facility exists to let servers enforce MAX_HEADER_LIST_SIZE |
| 109 | // while still decoding and keeping in-sync with decoder state, but |
| 110 | // without doing unnecessary decompression or generating unnecessary |
| 111 | // garbage for header fields past the limit. |
| 112 | func (d *Decoder) SetEmitEnabled(v bool) { d.emitEnabled = v } |
| 113 | |
| 114 | // EmitEnabled reports whether calls to the emitFunc provided to NewDecoder |
| 115 | // are currently enabled. The default is true. |
| 116 | func (d *Decoder) EmitEnabled() bool { return d.emitEnabled } |
| 117 | |
| 118 | // TODO: add method *Decoder.Reset(maxSize, emitFunc) to let callers re-use Decoders and their |
| 119 | // underlying buffers for garbage reasons. |
| 120 | |
| 121 | func (d *Decoder) SetMaxDynamicTableSize(v uint32) { |
| 122 | d.dynTab.setMaxSize(v) |
| 123 | } |
| 124 | |
| 125 | // SetAllowedMaxDynamicTableSize sets the upper bound that the encoded |
| 126 | // stream (via dynamic table size updates) may set the maximum size |
| 127 | // to. |
| 128 | func (d *Decoder) SetAllowedMaxDynamicTableSize(v uint32) { |
| 129 | d.dynTab.allowedMaxSize = v |
| 130 | } |
| 131 | |
| 132 | type dynamicTable struct { |
| 133 | // ents is the FIFO described at |
| 134 | // http://http2.github.io/http2-spec/compression.html#rfc.section.2.3.2 |
| 135 | // The newest (low index) is append at the end, and items are |
| 136 | // evicted from the front. |
| 137 | ents []HeaderField |
| 138 | size uint32 |
| 139 | maxSize uint32 // current maxSize |
| 140 | allowedMaxSize uint32 // maxSize may go up to this, inclusive |
| 141 | } |
| 142 | |
| 143 | func (dt *dynamicTable) setMaxSize(v uint32) { |
| 144 | dt.maxSize = v |
| 145 | dt.evict() |
| 146 | } |
| 147 | |
| 148 | // TODO: change dynamicTable to be a struct with a slice and a size int field, |
| 149 | // per http://http2.github.io/http2-spec/compression.html#rfc.section.4.1: |
| 150 | // |
| 151 | // |
| 152 | // Then make add increment the size. maybe the max size should move from Decoder to |
| 153 | // dynamicTable and add should return an ok bool if there was enough space. |
| 154 | // |
| 155 | // Later we'll need a remove operation on dynamicTable. |
| 156 | |
| 157 | func (dt *dynamicTable) add(f HeaderField) { |
| 158 | dt.ents = append(dt.ents, f) |
| 159 | dt.size += f.size() |
| 160 | dt.evict() |
| 161 | } |
| 162 | |
| 163 | // If we're too big, evict old stuff (front of the slice) |
| 164 | func (dt *dynamicTable) evict() { |
| 165 | base := dt.ents // keep base pointer of slice |
| 166 | for dt.size > dt.maxSize { |
| 167 | dt.size -= dt.ents[0].size() |
| 168 | dt.ents = dt.ents[1:] |
| 169 | } |
| 170 | |
| 171 | // Shift slice contents down if we evicted things. |
| 172 | if len(dt.ents) != len(base) { |
| 173 | copy(base, dt.ents) |
| 174 | dt.ents = base[:len(dt.ents)] |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | // constantTimeStringCompare compares string a and b in a constant |
| 179 | // time manner. |
| 180 | func constantTimeStringCompare(a, b string) bool { |
| 181 | if len(a) != len(b) { |
| 182 | return false |
| 183 | } |
| 184 | |
| 185 | c := byte(0) |
| 186 | |
| 187 | for i := 0; i < len(a); i++ { |
| 188 | c |= a[i] ^ b[i] |
| 189 | } |
| 190 | |
| 191 | return c == 0 |
| 192 | } |
| 193 | |
| 194 | // Search searches f in the table. The return value i is 0 if there is |
| 195 | // no name match. If there is name match or name/value match, i is the |
| 196 | // index of that entry (1-based). If both name and value match, |
| 197 | // nameValueMatch becomes true. |
| 198 | func (dt *dynamicTable) search(f HeaderField) (i uint64, nameValueMatch bool) { |
| 199 | l := len(dt.ents) |
| 200 | for j := l - 1; j >= 0; j-- { |
| 201 | ent := dt.ents[j] |
| 202 | if !constantTimeStringCompare(ent.Name, f.Name) { |
| 203 | continue |
| 204 | } |
| 205 | if i == 0 { |
| 206 | i = uint64(l - j) |
| 207 | } |
| 208 | if f.Sensitive { |
| 209 | continue |
| 210 | } |
| 211 | if !constantTimeStringCompare(ent.Value, f.Value) { |
| 212 | continue |
| 213 | } |
| 214 | i = uint64(l - j) |
| 215 | nameValueMatch = true |
| 216 | return |
| 217 | } |
| 218 | return |
| 219 | } |
| 220 | |
| 221 | func (d *Decoder) maxTableIndex() int { |
| 222 | return len(d.dynTab.ents) + len(staticTable) |
| 223 | } |
| 224 | |
| 225 | func (d *Decoder) at(i uint64) (hf HeaderField, ok bool) { |
| 226 | if i < 1 { |
| 227 | return |
| 228 | } |
| 229 | if i > uint64(d.maxTableIndex()) { |
| 230 | return |
| 231 | } |
| 232 | if i <= uint64(len(staticTable)) { |
| 233 | return staticTable[i-1], true |
| 234 | } |
| 235 | dents := d.dynTab.ents |
| 236 | return dents[len(dents)-(int(i)-len(staticTable))], true |
| 237 | } |
| 238 | |
| 239 | // Decode decodes an entire block. |
| 240 | // |
| 241 | // TODO: remove this method and make it incremental later? This is |
| 242 | // easier for debugging now. |
| 243 | func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error) { |
| 244 | var hf []HeaderField |
| 245 | saveFunc := d.emit |
| 246 | defer func() { d.emit = saveFunc }() |
| 247 | d.emit = func(f HeaderField) { hf = append(hf, f) } |
| 248 | if _, err := d.Write(p); err != nil { |
| 249 | return nil, err |
| 250 | } |
| 251 | if err := d.Close(); err != nil { |
| 252 | return nil, err |
| 253 | } |
| 254 | return hf, nil |
| 255 | } |
| 256 | |
| 257 | func (d *Decoder) Close() error { |
| 258 | if d.saveBuf.Len() > 0 { |
| 259 | d.saveBuf.Reset() |
| 260 | return DecodingError{errors.New("truncated headers")} |
| 261 | } |
| 262 | return nil |
| 263 | } |
| 264 | |
| 265 | func (d *Decoder) Write(p []byte) (n int, err error) { |
| 266 | if len(p) == 0 { |
| 267 | // Prevent state machine CPU attacks (making us redo |
| 268 | // work up to the point of finding out we don't have |
| 269 | // enough data) |
| 270 | return |
| 271 | } |
| 272 | // Only copy the data if we have to. Optimistically assume |
| 273 | // that p will contain a complete header block. |
| 274 | if d.saveBuf.Len() == 0 { |
| 275 | d.buf = p |
| 276 | } else { |
| 277 | d.saveBuf.Write(p) |
| 278 | d.buf = d.saveBuf.Bytes() |
| 279 | d.saveBuf.Reset() |
| 280 | } |
| 281 | |
| 282 | for len(d.buf) > 0 { |
| 283 | err = d.parseHeaderFieldRepr() |
| 284 | if err == errNeedMore { |
Brad Fitzpatrick | 3b000b3 | 2015-10-20 23:53:31 +0000 | [diff] [blame] | 285 | // Extra paranoia, making sure saveBuf won't |
| 286 | // get too large. All the varint and string |
| 287 | // reading code earlier should already catch |
| 288 | // overlong things and return ErrStringLength, |
| 289 | // but keep this as a last resort. |
Brad Fitzpatrick | 7a3dcd2 | 2015-10-14 03:37:10 +0000 | [diff] [blame] | 290 | const varIntOverhead = 8 // conservative |
| 291 | if d.maxStrLen != 0 && int64(len(d.buf)) > 2*(int64(d.maxStrLen)+varIntOverhead) { |
| 292 | return 0, ErrStringLength |
| 293 | } |
| 294 | d.saveBuf.Write(d.buf) |
| 295 | return len(p), nil |
| 296 | } |
| 297 | if err != nil { |
| 298 | break |
| 299 | } |
| 300 | } |
| 301 | return len(p), err |
| 302 | } |
| 303 | |
| 304 | // errNeedMore is an internal sentinel error value that means the |
| 305 | // buffer is truncated and we need to read more data before we can |
| 306 | // continue parsing. |
| 307 | var errNeedMore = errors.New("need more data") |
| 308 | |
| 309 | type indexType int |
| 310 | |
| 311 | const ( |
| 312 | indexedTrue indexType = iota |
| 313 | indexedFalse |
| 314 | indexedNever |
| 315 | ) |
| 316 | |
| 317 | func (v indexType) indexed() bool { return v == indexedTrue } |
| 318 | func (v indexType) sensitive() bool { return v == indexedNever } |
| 319 | |
| 320 | // returns errNeedMore if there isn't enough data available. |
| 321 | // any other error is fatal. |
| 322 | // consumes d.buf iff it returns nil. |
| 323 | // precondition: must be called with len(d.buf) > 0 |
| 324 | func (d *Decoder) parseHeaderFieldRepr() error { |
| 325 | b := d.buf[0] |
| 326 | switch { |
| 327 | case b&128 != 0: |
| 328 | // Indexed representation. |
| 329 | // High bit set? |
| 330 | // http://http2.github.io/http2-spec/compression.html#rfc.section.6.1 |
| 331 | return d.parseFieldIndexed() |
| 332 | case b&192 == 64: |
| 333 | // 6.2.1 Literal Header Field with Incremental Indexing |
| 334 | // 0b10xxxxxx: top two bits are 10 |
| 335 | // http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.1 |
| 336 | return d.parseFieldLiteral(6, indexedTrue) |
| 337 | case b&240 == 0: |
| 338 | // 6.2.2 Literal Header Field without Indexing |
| 339 | // 0b0000xxxx: top four bits are 0000 |
| 340 | // http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.2 |
| 341 | return d.parseFieldLiteral(4, indexedFalse) |
| 342 | case b&240 == 16: |
| 343 | // 6.2.3 Literal Header Field never Indexed |
| 344 | // 0b0001xxxx: top four bits are 0001 |
| 345 | // http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.3 |
| 346 | return d.parseFieldLiteral(4, indexedNever) |
| 347 | case b&224 == 32: |
| 348 | // 6.3 Dynamic Table Size Update |
| 349 | // Top three bits are '001'. |
| 350 | // http://http2.github.io/http2-spec/compression.html#rfc.section.6.3 |
| 351 | return d.parseDynamicTableSizeUpdate() |
| 352 | } |
| 353 | |
| 354 | return DecodingError{errors.New("invalid encoding")} |
| 355 | } |
| 356 | |
| 357 | // (same invariants and behavior as parseHeaderFieldRepr) |
| 358 | func (d *Decoder) parseFieldIndexed() error { |
| 359 | buf := d.buf |
| 360 | idx, buf, err := readVarInt(7, buf) |
| 361 | if err != nil { |
| 362 | return err |
| 363 | } |
| 364 | hf, ok := d.at(idx) |
| 365 | if !ok { |
| 366 | return DecodingError{InvalidIndexError(idx)} |
| 367 | } |
| 368 | d.buf = buf |
| 369 | return d.callEmit(HeaderField{Name: hf.Name, Value: hf.Value}) |
| 370 | } |
| 371 | |
| 372 | // (same invariants and behavior as parseHeaderFieldRepr) |
| 373 | func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error { |
| 374 | buf := d.buf |
| 375 | nameIdx, buf, err := readVarInt(n, buf) |
| 376 | if err != nil { |
| 377 | return err |
| 378 | } |
| 379 | |
| 380 | var hf HeaderField |
| 381 | wantStr := d.emitEnabled || it.indexed() |
| 382 | if nameIdx > 0 { |
| 383 | ihf, ok := d.at(nameIdx) |
| 384 | if !ok { |
| 385 | return DecodingError{InvalidIndexError(nameIdx)} |
| 386 | } |
| 387 | hf.Name = ihf.Name |
| 388 | } else { |
| 389 | hf.Name, buf, err = d.readString(buf, wantStr) |
| 390 | if err != nil { |
| 391 | return err |
| 392 | } |
| 393 | } |
| 394 | hf.Value, buf, err = d.readString(buf, wantStr) |
| 395 | if err != nil { |
| 396 | return err |
| 397 | } |
| 398 | d.buf = buf |
| 399 | if it.indexed() { |
| 400 | d.dynTab.add(hf) |
| 401 | } |
| 402 | hf.Sensitive = it.sensitive() |
| 403 | return d.callEmit(hf) |
| 404 | } |
| 405 | |
| 406 | func (d *Decoder) callEmit(hf HeaderField) error { |
| 407 | if d.maxStrLen != 0 { |
| 408 | if len(hf.Name) > d.maxStrLen || len(hf.Value) > d.maxStrLen { |
| 409 | return ErrStringLength |
| 410 | } |
| 411 | } |
| 412 | if d.emitEnabled { |
| 413 | d.emit(hf) |
| 414 | } |
| 415 | return nil |
| 416 | } |
| 417 | |
| 418 | // (same invariants and behavior as parseHeaderFieldRepr) |
| 419 | func (d *Decoder) parseDynamicTableSizeUpdate() error { |
| 420 | buf := d.buf |
| 421 | size, buf, err := readVarInt(5, buf) |
| 422 | if err != nil { |
| 423 | return err |
| 424 | } |
| 425 | if size > uint64(d.dynTab.allowedMaxSize) { |
| 426 | return DecodingError{errors.New("dynamic table size update too large")} |
| 427 | } |
| 428 | d.dynTab.setMaxSize(uint32(size)) |
| 429 | d.buf = buf |
| 430 | return nil |
| 431 | } |
| 432 | |
| 433 | var errVarintOverflow = DecodingError{errors.New("varint integer overflow")} |
| 434 | |
| 435 | // readVarInt reads an unsigned variable length integer off the |
| 436 | // beginning of p. n is the parameter as described in |
| 437 | // http://http2.github.io/http2-spec/compression.html#rfc.section.5.1. |
| 438 | // |
| 439 | // n must always be between 1 and 8. |
| 440 | // |
| 441 | // The returned remain buffer is either a smaller suffix of p, or err != nil. |
| 442 | // The error is errNeedMore if p doesn't contain a complete integer. |
| 443 | func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) { |
| 444 | if n < 1 || n > 8 { |
| 445 | panic("bad n") |
| 446 | } |
| 447 | if len(p) == 0 { |
| 448 | return 0, p, errNeedMore |
| 449 | } |
| 450 | i = uint64(p[0]) |
| 451 | if n < 8 { |
| 452 | i &= (1 << uint64(n)) - 1 |
| 453 | } |
| 454 | if i < (1<<uint64(n))-1 { |
| 455 | return i, p[1:], nil |
| 456 | } |
| 457 | |
| 458 | origP := p |
| 459 | p = p[1:] |
| 460 | var m uint64 |
| 461 | for len(p) > 0 { |
| 462 | b := p[0] |
| 463 | p = p[1:] |
| 464 | i += uint64(b&127) << m |
| 465 | if b&128 == 0 { |
| 466 | return i, p, nil |
| 467 | } |
| 468 | m += 7 |
| 469 | if m >= 63 { // TODO: proper overflow check. making this up. |
| 470 | return 0, origP, errVarintOverflow |
| 471 | } |
| 472 | } |
| 473 | return 0, origP, errNeedMore |
| 474 | } |
| 475 | |
| 476 | // readString decodes an hpack string from p. |
| 477 | // |
| 478 | // wantStr is whether s will be used. If false, decompression and |
| 479 | // []byte->string garbage are skipped if s will be ignored |
| 480 | // anyway. This does mean that huffman decoding errors for non-indexed |
| 481 | // strings past the MAX_HEADER_LIST_SIZE are ignored, but the server |
| 482 | // is returning an error anyway, and because they're not indexed, the error |
| 483 | // won't affect the decoding state. |
| 484 | func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) { |
| 485 | if len(p) == 0 { |
| 486 | return "", p, errNeedMore |
| 487 | } |
| 488 | isHuff := p[0]&128 != 0 |
| 489 | strLen, p, err := readVarInt(7, p) |
| 490 | if err != nil { |
| 491 | return "", p, err |
| 492 | } |
| 493 | if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) { |
| 494 | return "", nil, ErrStringLength |
| 495 | } |
| 496 | if uint64(len(p)) < strLen { |
| 497 | return "", p, errNeedMore |
| 498 | } |
| 499 | if !isHuff { |
| 500 | if wantStr { |
| 501 | s = string(p[:strLen]) |
| 502 | } |
| 503 | return s, p[strLen:], nil |
| 504 | } |
| 505 | |
| 506 | if wantStr { |
| 507 | buf := bufPool.Get().(*bytes.Buffer) |
| 508 | buf.Reset() // don't trust others |
| 509 | defer bufPool.Put(buf) |
| 510 | if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil { |
Brad Fitzpatrick | 3b000b3 | 2015-10-20 23:53:31 +0000 | [diff] [blame] | 511 | buf.Reset() |
Brad Fitzpatrick | 7a3dcd2 | 2015-10-14 03:37:10 +0000 | [diff] [blame] | 512 | return "", nil, err |
| 513 | } |
| 514 | s = buf.String() |
| 515 | buf.Reset() // be nice to GC |
| 516 | } |
| 517 | return s, p[strLen:], nil |
| 518 | } |