| Index: net/http2/hpack/decoder/hpack_string_decoder.h
|
| diff --git a/net/http2/hpack/decoder/hpack_string_decoder.h b/net/http2/hpack/decoder/hpack_string_decoder.h
|
| deleted file mode 100644
|
| index baea422cebf91b0aac3b64c3a3524fa334a62c88..0000000000000000000000000000000000000000
|
| --- a/net/http2/hpack/decoder/hpack_string_decoder.h
|
| +++ /dev/null
|
| @@ -1,236 +0,0 @@
|
| -// Copyright 2016 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#ifndef NET_HTTP2_HPACK_DECODER_HPACK_STRING_DECODER_H_
|
| -#define NET_HTTP2_HPACK_DECODER_HPACK_STRING_DECODER_H_
|
| -
|
| -// HpackStringDecoder decodes strings encoded per the HPACK spec; this does
|
| -// not mean decompressing Huffman encoded strings, just identifying the length,
|
| -// encoding and contents for a listener.
|
| -
|
| -#include <stddef.h>
|
| -
|
| -#include <algorithm>
|
| -#include <string>
|
| -
|
| -#include "base/logging.h"
|
| -#include "base/macros.h"
|
| -#include "net/base/net_export.h"
|
| -#include "net/http2/decoder/decode_buffer.h"
|
| -#include "net/http2/decoder/decode_status.h"
|
| -#include "net/http2/hpack/decoder/hpack_varint_decoder.h"
|
| -
|
| -namespace net {
|
| -
|
| -// Decodes a single string in an HPACK header entry. The high order bit of
|
| -// the first byte of the length is the H (Huffman) bit indicating whether
|
| -// the value is Huffman encoded, and the remainder of the byte is the first
|
| -// 7 bits of an HPACK varint.
|
| -//
|
| -// Call Start() to begin decoding; if it returns kDecodeInProgress, then call
|
| -// Resume() when more input is available, repeating until kDecodeInProgress is
|
| -// not returned. If kDecodeDone or kDecodeError is returned, then Resume() must
|
| -// not be called until Start() has been called to start decoding a new string.
|
| -//
|
| -// There are 3 variants of Start in this class, participants in a performance
|
| -// experiment. Perflab experiments show it is generally fastest to call
|
| -// StartSpecialCaseShort rather than StartOnly (~9% slower) or
|
| -// StartAndDecodeLength (~10% slower).
|
| -class NET_EXPORT_PRIVATE HpackStringDecoder {
|
| - public:
|
| - enum StringDecoderState {
|
| - kStartDecodingLength,
|
| - kDecodingString,
|
| - kResumeDecodingLength,
|
| - };
|
| -
|
| - // TODO(jamessynge): Get rid of all but one of the Start and Resume methods
|
| - // after all of the HPACK decoder is checked in and has been perf tested.
|
| - template <class Listener>
|
| - DecodeStatus Start(DecodeBuffer* db, Listener* cb) {
|
| - return StartSpecialCaseShort(db, cb);
|
| - }
|
| -
|
| - template <class Listener>
|
| - DecodeStatus StartOnly(DecodeBuffer* db, Listener* cb) {
|
| - state_ = kStartDecodingLength;
|
| - return Resume(db, cb);
|
| - }
|
| -
|
| - template <class Listener>
|
| - DecodeStatus StartAndDecodeLength(DecodeBuffer* db, Listener* cb) {
|
| - DecodeStatus status;
|
| - if (StartDecodingLength(db, cb, &status)) {
|
| - state_ = kDecodingString;
|
| - return DecodeString(db, cb);
|
| - }
|
| - return status;
|
| - }
|
| -
|
| - template <class Listener>
|
| - DecodeStatus StartSpecialCaseShort(DecodeBuffer* db, Listener* cb) {
|
| - // Fast decode path is used if the string is under 127 bytes and the
|
| - // entire length of the string is in the decode buffer. More than 83% of
|
| - // string lengths are encoded in just one byte.
|
| - if (db->HasData() && (*db->cursor() & 0x7f) != 0x7f) {
|
| - // The string is short.
|
| - uint8_t h_and_prefix = db->DecodeUInt8();
|
| - uint8_t length = h_and_prefix & 0x7f;
|
| - bool huffman_encoded = (h_and_prefix & 0x80) == 0x80;
|
| - cb->OnStringStart(huffman_encoded, length);
|
| - if (length <= db->Remaining()) {
|
| - // Yeah, we've got the whole thing in the decode buffer.
|
| - // Ideally this will be the common case. Note that we don't
|
| - // update any of the member variables in this path.
|
| - cb->OnStringData(db->cursor(), length);
|
| - db->AdvanceCursor(length);
|
| - cb->OnStringEnd();
|
| - return DecodeStatus::kDecodeDone;
|
| - }
|
| - // Not all in the buffer.
|
| - huffman_encoded_ = huffman_encoded;
|
| - remaining_ = length;
|
| - // Call Resume to decode the string body, which is only partially
|
| - // in the decode buffer (or not at all).
|
| - state_ = kDecodingString;
|
| - return Resume(db, cb);
|
| - }
|
| - // Call Resume to decode the string length, which is either not in
|
| - // the decode buffer, or spans multiple bytes.
|
| - state_ = kStartDecodingLength;
|
| - return Resume(db, cb);
|
| - }
|
| -
|
| - template <class Listener>
|
| - DecodeStatus Resume(DecodeBuffer* db, Listener* cb) {
|
| - DecodeStatus status;
|
| - while (true) {
|
| - switch (state_) {
|
| - case kStartDecodingLength:
|
| - DVLOG(2) << "kStartDecodingLength: db->Remaining=" << db->Remaining();
|
| - if (!StartDecodingLength(db, cb, &status)) {
|
| - // The length is split across decode buffers.
|
| - return status;
|
| - }
|
| - // We've finished decoding the length, which spanned one or more
|
| - // bytes. Approximately 17% of strings have a length that is greater
|
| - // than 126 bytes, and thus the length is encoded in more than one
|
| - // byte, and so doesn't get the benefit of the optimization in
|
| - // Start() for single byte lengths. But, we still expect that most
|
| - // of such strings will be contained entirely in a single decode
|
| - // buffer, and hence this fall through skips another trip through the
|
| - // switch above and more importantly skips setting the state_ variable
|
| - // again in those cases where we don't need it.
|
| -
|
| - // FALLTHROUGH_INTENDED
|
| -
|
| - case kDecodingString:
|
| - DVLOG(2) << "kDecodingString: db->Remaining=" << db->Remaining()
|
| - << " remaining_=" << remaining_;
|
| - return DecodeString(db, cb);
|
| -
|
| - case kResumeDecodingLength:
|
| - DVLOG(2) << "kResumeDecodingLength: db->Remaining="
|
| - << db->Remaining();
|
| - if (!ResumeDecodingLength(db, cb, &status)) {
|
| - return status;
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - std::string DebugString() const;
|
| -
|
| - private:
|
| - static std::string StateToString(StringDecoderState v);
|
| -
|
| - // Returns true if the length is fully decoded and the listener wants the
|
| - // decoding to continue, false otherwise; status is set to the status from
|
| - // the varint decoder.
|
| - // If the length is not fully decoded, case state_ is set appropriately
|
| - // for the next call to Resume.
|
| - template <class Listener>
|
| - bool StartDecodingLength(DecodeBuffer* db,
|
| - Listener* cb,
|
| - DecodeStatus* status) {
|
| - if (db->Empty()) {
|
| - *status = DecodeStatus::kDecodeInProgress;
|
| - state_ = kStartDecodingLength;
|
| - return false;
|
| - }
|
| - uint8_t h_and_prefix = db->DecodeUInt8();
|
| - huffman_encoded_ = (h_and_prefix & 0x80) == 0x80;
|
| - *status = length_decoder_.Start(h_and_prefix, 0x7f, db);
|
| - if (*status == DecodeStatus::kDecodeDone) {
|
| - OnStringStart(cb, status);
|
| - return true;
|
| - }
|
| - // Set the state to cover the DecodeStatus::kDecodeInProgress case.
|
| - // Won't be needed if the status is kDecodeError.
|
| - state_ = kResumeDecodingLength;
|
| - return false;
|
| - }
|
| -
|
| - // Returns true if the length is fully decoded and the listener wants the
|
| - // decoding to continue, false otherwise; status is set to the status from
|
| - // the varint decoder; state_ is updated when fully decoded.
|
| - // If the length is not fully decoded, case state_ is set appropriately
|
| - // for the next call to Resume.
|
| - template <class Listener>
|
| - bool ResumeDecodingLength(DecodeBuffer* db,
|
| - Listener* cb,
|
| - DecodeStatus* status) {
|
| - DCHECK_EQ(state_, kResumeDecodingLength);
|
| - *status = length_decoder_.Resume(db);
|
| - if (*status == DecodeStatus::kDecodeDone) {
|
| - state_ = kDecodingString;
|
| - OnStringStart(cb, status);
|
| - return true;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - // Returns true if the listener wants the decoding to continue, and
|
| - // false otherwise, in which case status set.
|
| - template <class Listener>
|
| - void OnStringStart(Listener* cb, DecodeStatus* status) {
|
| - remaining_ = length_decoder_.value();
|
| - // Make callback so consumer knows what is coming.
|
| - cb->OnStringStart(huffman_encoded_, remaining_);
|
| - return;
|
| - }
|
| -
|
| - // Passes the available portion of the string to the listener, and signals
|
| - // the end of the string when it is reached. Returns kDecodeDone or
|
| - // kDecodeInProgress as appropriate.
|
| - template <class Listener>
|
| - DecodeStatus DecodeString(DecodeBuffer* db, Listener* cb) {
|
| - size_t len = std::min(remaining_, db->Remaining());
|
| - if (len > 0) {
|
| - cb->OnStringData(db->cursor(), len);
|
| - db->AdvanceCursor(len);
|
| - remaining_ -= len;
|
| - }
|
| - if (remaining_ == 0) {
|
| - cb->OnStringEnd();
|
| - return DecodeStatus::kDecodeDone;
|
| - }
|
| - state_ = kDecodingString;
|
| - return DecodeStatus::kDecodeInProgress;
|
| - }
|
| -
|
| - HpackVarintDecoder length_decoder_;
|
| -
|
| - // These fields are initialized just to keep ASAN happy about reading
|
| - // them from DebugString().
|
| - size_t remaining_ = 0;
|
| - StringDecoderState state_ = kStartDecodingLength;
|
| - bool huffman_encoded_ = false;
|
| -};
|
| -
|
| -NET_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out,
|
| - const HpackStringDecoder& v);
|
| -
|
| -} // namespace net
|
| -#endif // NET_HTTP2_HPACK_DECODER_HPACK_STRING_DECODER_H_
|
|
|