| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // Decoder for strings encoded using the HPACK Huffman Code (see | 5 // Decoder for strings encoded using the HPACK Huffman Code (see |
| 6 // https://httpwg.github.io/specs/rfc7541.html#huffman.code). | 6 // https://httpwg.github.io/specs/rfc7541.html#huffman.code). |
| 7 // | 7 // |
| 8 // This implementation is inspired by the One-Shift algorithm described in | 8 // This implementation is inspired by the One-Shift algorithm described in |
| 9 // "On the Implementation of Minimum Redundancy Prefix Codes", by Alistair | 9 // "On the Implementation of Minimum Redundancy Prefix Codes", by Alistair |
| 10 // Moffat and Andrew Turpin, 1997. | 10 // Moffat and Andrew Turpin, 1997. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 #include <bitset> | 28 #include <bitset> |
| 29 #include <limits> | 29 #include <limits> |
| 30 #include <utility> | 30 #include <utility> |
| 31 | 31 |
| 32 #include "base/logging.h" | 32 #include "base/logging.h" |
| 33 #include "net/spdy/core/hpack/hpack_input_stream.h" | 33 #include "net/spdy/core/hpack/hpack_input_stream.h" |
| 34 | 34 |
| 35 namespace net { | 35 namespace net { |
| 36 namespace { | 36 namespace { |
| 37 | 37 |
| 38 typedef HpackHuffmanDecoder::HuffmanWord HuffmanWord; | 38 typedef SpdyHpackHuffmanDecoder::HuffmanWord HuffmanWord; |
| 39 typedef HpackHuffmanDecoder::HuffmanCodeLength HuffmanCodeLength; | 39 typedef SpdyHpackHuffmanDecoder::HuffmanCodeLength HuffmanCodeLength; |
| 40 | 40 |
| 41 const HuffmanCodeLength kHuffmanWordLength = | 41 const HuffmanCodeLength kHuffmanWordLength = |
| 42 std::numeric_limits<HuffmanWord>::digits; | 42 std::numeric_limits<HuffmanWord>::digits; |
| 43 | 43 |
| 44 const HuffmanCodeLength kMinCodeLength = 5; | 44 const HuffmanCodeLength kMinCodeLength = 5; |
| 45 const HuffmanCodeLength kMaxCodeLength = 30; | 45 const HuffmanCodeLength kMaxCodeLength = 30; |
| 46 | 46 |
| 47 const HuffmanWord kInvalidLJCode = ~static_cast<HuffmanWord>(0); | 47 const HuffmanWord kInvalidLJCode = ~static_cast<HuffmanWord>(0); |
| 48 // Length of a code in bits to the first code with that length, left-justified. | 48 // Length of a code in bits to the first code with that length, left-justified. |
| 49 // Note that this can be computed from kLengthToFirstCanonical. | 49 // Note that this can be computed from kLengthToFirstCanonical. |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 | 173 |
| 174 #endif // DCHECK_IS_ON() | 174 #endif // DCHECK_IS_ON() |
| 175 | 175 |
| 176 } // namespace | 176 } // namespace |
| 177 | 177 |
| 178 // TODO(jamessynge): Should we read these magic numbers from | 178 // TODO(jamessynge): Should we read these magic numbers from |
| 179 // kLengthToFirstLJCode? Would that reduce cache consumption? Slow decoding? | 179 // kLengthToFirstLJCode? Would that reduce cache consumption? Slow decoding? |
| 180 // TODO(jamessynge): Is this being inlined by the compiler? Should we inline | 180 // TODO(jamessynge): Is this being inlined by the compiler? Should we inline |
| 181 // into DecodeString the tests for code lengths 5 through 8 (> 99% of codes | 181 // into DecodeString the tests for code lengths 5 through 8 (> 99% of codes |
| 182 // according to the HPACK spec)? | 182 // according to the HPACK spec)? |
| 183 HpackHuffmanDecoder::HuffmanCodeLength HpackHuffmanDecoder::CodeLengthOfPrefix( | 183 SpdyHpackHuffmanDecoder::HuffmanCodeLength SpdyHpackHuffmanDecoder::CodeLengthOf
Prefix( |
| 184 HpackHuffmanDecoder::HuffmanWord value) { | 184 SpdyHpackHuffmanDecoder::HuffmanWord value) { |
| 185 HuffmanCodeLength length; | 185 HuffmanCodeLength length; |
| 186 if (value < 0xb8000000) { | 186 if (value < 0xb8000000) { |
| 187 if (value < 0x50000000) { | 187 if (value < 0x50000000) { |
| 188 length = 5; | 188 length = 5; |
| 189 } else { | 189 } else { |
| 190 length = 6; | 190 length = 6; |
| 191 } | 191 } |
| 192 } else { | 192 } else { |
| 193 if (value < 0xfe000000) { | 193 if (value < 0xfe000000) { |
| 194 if (value < 0xf8000000) { | 194 if (value < 0xf8000000) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 } | 260 } |
| 261 } | 261 } |
| 262 } | 262 } |
| 263 } | 263 } |
| 264 } | 264 } |
| 265 } | 265 } |
| 266 } | 266 } |
| 267 return length; | 267 return length; |
| 268 } | 268 } |
| 269 | 269 |
| 270 HuffmanWord HpackHuffmanDecoder::DecodeToCanonical( | 270 HuffmanWord SpdyHpackHuffmanDecoder::DecodeToCanonical( |
| 271 HuffmanCodeLength code_length, | 271 HuffmanCodeLength code_length, |
| 272 HuffmanWord bits) { | 272 HuffmanWord bits) { |
| 273 DCHECK_LE(kMinCodeLength, code_length); | 273 DCHECK_LE(kMinCodeLength, code_length); |
| 274 DCHECK_LE(code_length, kMaxCodeLength); | 274 DCHECK_LE(code_length, kMaxCodeLength); |
| 275 | 275 |
| 276 // What is the first left-justified code of length |code_length|? | 276 // What is the first left-justified code of length |code_length|? |
| 277 HuffmanWord first_lj_code = kLengthToFirstLJCode[code_length]; | 277 HuffmanWord first_lj_code = kLengthToFirstLJCode[code_length]; |
| 278 DCHECK_NE(kInvalidLJCode, first_lj_code); | 278 DCHECK_NE(kInvalidLJCode, first_lj_code); |
| 279 | 279 |
| 280 // Which canonical symbol corresponds to the high order |code_length| | 280 // Which canonical symbol corresponds to the high order |code_length| |
| 281 // bits of |first_lj_code|? | 281 // bits of |first_lj_code|? |
| 282 HuffmanWord first_canonical = kLengthToFirstCanonical[code_length]; | 282 HuffmanWord first_canonical = kLengthToFirstCanonical[code_length]; |
| 283 DCHECK_NE(kInvalidCanonical, first_canonical); | 283 DCHECK_NE(kInvalidCanonical, first_canonical); |
| 284 | 284 |
| 285 // What is the position of the canonical symbol being decoded within | 285 // What is the position of the canonical symbol being decoded within |
| 286 // the canonical symbols of length |code_length|? | 286 // the canonical symbols of length |code_length|? |
| 287 HuffmanWord ordinal_in_length = | 287 HuffmanWord ordinal_in_length = |
| 288 ((bits - first_lj_code) >> (kHuffmanWordLength - code_length)); | 288 ((bits - first_lj_code) >> (kHuffmanWordLength - code_length)); |
| 289 | 289 |
| 290 // Combined these two to produce the position of the canonical symbol | 290 // Combined these two to produce the position of the canonical symbol |
| 291 // being decoded within all of the canonical symbols. | 291 // being decoded within all of the canonical symbols. |
| 292 return first_canonical + ordinal_in_length; | 292 return first_canonical + ordinal_in_length; |
| 293 } | 293 } |
| 294 | 294 |
| 295 uint8_t HpackHuffmanDecoder::CanonicalToSource(HuffmanWord canonical) { | 295 uint8_t SpdyHpackHuffmanDecoder::CanonicalToSource(HuffmanWord canonical) { |
| 296 DCHECK_LT(canonical, 256u); | 296 DCHECK_LT(canonical, 256u); |
| 297 return kCanonicalToSymbol[canonical]; | 297 return kCanonicalToSymbol[canonical]; |
| 298 } | 298 } |
| 299 | 299 |
| 300 // TODO(jamessynge): Maybe further refactorings, including just passing in a | 300 // TODO(jamessynge): Maybe further refactorings, including just passing in a |
| 301 // SpdyStringPiece instead of an HpackInputStream, thus avoiding the PeekBits | 301 // SpdyStringPiece instead of an HpackInputStream, thus avoiding the PeekBits |
| 302 // calls, and also allowing us to separate the code into portions dealing with | 302 // calls, and also allowing us to separate the code into portions dealing with |
| 303 // long strings, and a later portion dealing with the last few bytes of strings. | 303 // long strings, and a later portion dealing with the last few bytes of strings. |
| 304 // TODO(jamessynge): Determine if that is worth it by adding some counters to | 304 // TODO(jamessynge): Determine if that is worth it by adding some counters to |
| 305 // measure the distribution of string sizes seen in practice. | 305 // measure the distribution of string sizes seen in practice. |
| 306 bool HpackHuffmanDecoder::DecodeString(HpackInputStream* in, SpdyString* out) { | 306 bool SpdyHpackHuffmanDecoder::DecodeString(HpackInputStream* in, SpdyString* out
) { |
| 307 out->clear(); | 307 out->clear(); |
| 308 | 308 |
| 309 // Load |bits| with the leading bits of the input stream, left justified | 309 // Load |bits| with the leading bits of the input stream, left justified |
| 310 // (i.e. the bits of the first byte are the high-order bits of |bits|, | 310 // (i.e. the bits of the first byte are the high-order bits of |bits|, |
| 311 // and the bits of the fourth byte are the low-order bits of |bits|). | 311 // and the bits of the fourth byte are the low-order bits of |bits|). |
| 312 // |peeked_success| if there are more bits in |*in| (i.e. the encoding | 312 // |peeked_success| if there are more bits in |*in| (i.e. the encoding |
| 313 // of the string to be decoded is more than 4 bytes). | 313 // of the string to be decoded is more than 4 bytes). |
| 314 | 314 |
| 315 auto bits_available_and_bits = in->InitializePeekBits(); | 315 auto bits_available_and_bits = in->InitializePeekBits(); |
| 316 HuffmanCodeLength bits_available = bits_available_and_bits.first; | 316 HuffmanCodeLength bits_available = bits_available_and_bits.first; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 // Get some more bits for decoding (up to 8). |peeked_success| is true | 391 // Get some more bits for decoding (up to 8). |peeked_success| is true |
| 392 // if we got any bits. | 392 // if we got any bits. |
| 393 peeked_success = in->PeekBits(&bits_available, &bits); | 393 peeked_success = in->PeekBits(&bits_available, &bits); |
| 394 } | 394 } |
| 395 DLOG_IF(WARNING, (VLOG_IS_ON(2) && bits_available < 32 && !peeked_success)) | 395 DLOG_IF(WARNING, (VLOG_IS_ON(2) && bits_available < 32 && !peeked_success)) |
| 396 << "no more peeking possible"; | 396 << "no more peeking possible"; |
| 397 } | 397 } |
| 398 } | 398 } |
| 399 | 399 |
| 400 } // namespace net | 400 } // namespace net |
| OLD | NEW |