QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1 | // Copyright 2018 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef QUICHE_QUIC_CORE_QPACK_QPACK_INSTRUCTION_DECODER_H_ |
| 6 | #define QUICHE_QUIC_CORE_QPACK_QPACK_INSTRUCTION_DECODER_H_ |
| 7 | |
| 8 | #include <cstddef> |
| 9 | #include <cstdint> |
vasilvv | 872e7a3 | 2019-03-12 16:42:44 -0700 | [diff] [blame] | 10 | #include <string> |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 11 | |
vasilvv | 7cac7b0 | 2020-10-08 12:32:10 -0700 | [diff] [blame] | 12 | #include "absl/strings/string_view.h" |
QUICHE team | 5be974e | 2020-12-29 18:35:24 -0500 | [diff] [blame] | 13 | #include "http2/hpack/huffman/hpack_huffman_decoder.h" |
| 14 | #include "http2/hpack/varint/hpack_varint_decoder.h" |
| 15 | #include "quic/core/qpack/qpack_instructions.h" |
| 16 | #include "quic/platform/api/quic_export.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 17 | |
| 18 | namespace quic { |
| 19 | |
| 20 | // Generic instruction decoder class. Takes a QpackLanguage that describes a |
| 21 | // language, that is, a set of instruction opcodes together with a list of |
| 22 | // fields that follow each instruction. |
| 23 | class QUIC_EXPORT_PRIVATE QpackInstructionDecoder { |
| 24 | public: |
bnc | 4e44010 | 2020-10-20 17:32:29 -0700 | [diff] [blame] | 25 | enum class ErrorCode { |
| 26 | INTEGER_TOO_LARGE, |
| 27 | STRING_LITERAL_TOO_LONG, |
| 28 | HUFFMAN_ENCODING_ERROR, |
| 29 | }; |
| 30 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 31 | // Delegate is notified each time an instruction is decoded or when an error |
| 32 | // occurs. |
| 33 | class QUIC_EXPORT_PRIVATE Delegate { |
| 34 | public: |
| 35 | virtual ~Delegate() = default; |
| 36 | |
| 37 | // Called when an instruction (including all its fields) is decoded. |
| 38 | // |instruction| points to an entry in |language|. |
| 39 | // Returns true if decoded fields are valid. |
| 40 | // Returns false otherwise, in which case QpackInstructionDecoder stops |
| 41 | // decoding: Delegate methods will not be called, and Decode() must not be |
bnc | fb4f4fc | 2019-11-18 17:14:56 -0800 | [diff] [blame] | 42 | // called. Implementations are allowed to destroy the |
| 43 | // QpackInstructionDecoder instance synchronously if OnInstructionDecoded() |
| 44 | // returns false. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 45 | virtual bool OnInstructionDecoded(const QpackInstruction* instruction) = 0; |
| 46 | |
| 47 | // Called by QpackInstructionDecoder if an error has occurred. |
| 48 | // No more data is processed afterwards. |
bnc | fb4f4fc | 2019-11-18 17:14:56 -0800 | [diff] [blame] | 49 | // Implementations are allowed to destroy the QpackInstructionDecoder |
| 50 | // instance synchronously. |
bnc | 34a2680 | 2020-10-17 05:09:54 -0700 | [diff] [blame] | 51 | virtual void OnInstructionDecodingError( |
bnc | 4e44010 | 2020-10-20 17:32:29 -0700 | [diff] [blame] | 52 | ErrorCode error_code, |
bnc | 34a2680 | 2020-10-17 05:09:54 -0700 | [diff] [blame] | 53 | absl::string_view error_message) = 0; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 54 | }; |
| 55 | |
| 56 | // Both |*language| and |*delegate| must outlive this object. |
| 57 | QpackInstructionDecoder(const QpackLanguage* language, Delegate* delegate); |
| 58 | QpackInstructionDecoder() = delete; |
| 59 | QpackInstructionDecoder(const QpackInstructionDecoder&) = delete; |
| 60 | QpackInstructionDecoder& operator=(const QpackInstructionDecoder&) = delete; |
| 61 | |
| 62 | // Provide a data fragment to decode. Must not be called after an error has |
bnc | fb4f4fc | 2019-11-18 17:14:56 -0800 | [diff] [blame] | 63 | // occurred. Must not be called with empty |data|. Return true on success, |
bnc | 34a2680 | 2020-10-17 05:09:54 -0700 | [diff] [blame] | 64 | // false on error (in which case Delegate::OnInstructionDecodingError() is |
| 65 | // called synchronously). |
vasilvv | 7cac7b0 | 2020-10-08 12:32:10 -0700 | [diff] [blame] | 66 | bool Decode(absl::string_view data); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 67 | |
| 68 | // Returns true if no decoding has taken place yet or if the last instruction |
| 69 | // has been entirely parsed. |
| 70 | bool AtInstructionBoundary() const; |
| 71 | |
| 72 | // Accessors for decoded values. Should only be called for fields that are |
| 73 | // part of the most recently decoded instruction, and only after |this| calls |
| 74 | // Delegate::OnInstructionDecoded() but before Decode() is called again. |
| 75 | bool s_bit() const { return s_bit_; } |
| 76 | uint64_t varint() const { return varint_; } |
| 77 | uint64_t varint2() const { return varint2_; } |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 78 | const std::string& name() const { return name_; } |
| 79 | const std::string& value() const { return value_; } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 80 | |
| 81 | private: |
| 82 | enum class State { |
| 83 | // Identify instruction. |
| 84 | kStartInstruction, |
| 85 | // Start decoding next field. |
| 86 | kStartField, |
| 87 | // Read a single bit. |
| 88 | kReadBit, |
| 89 | // Start reading integer. |
| 90 | kVarintStart, |
| 91 | // Resume reading integer. |
| 92 | kVarintResume, |
| 93 | // Done reading integer. |
| 94 | kVarintDone, |
| 95 | // Read string. |
| 96 | kReadString, |
| 97 | // Done reading string. |
| 98 | kReadStringDone |
| 99 | }; |
| 100 | |
bnc | fb4f4fc | 2019-11-18 17:14:56 -0800 | [diff] [blame] | 101 | // One method for each state. They each return true on success, false on |
| 102 | // error (in which case |this| might already be destroyed). Some take input |
| 103 | // data and set |*bytes_consumed| to the number of octets processed. Some |
| 104 | // take input data but do not consume any bytes. Some do not take any |
| 105 | // arguments because they only change internal state. |
vasilvv | 7cac7b0 | 2020-10-08 12:32:10 -0700 | [diff] [blame] | 106 | bool DoStartInstruction(absl::string_view data); |
bnc | fb4f4fc | 2019-11-18 17:14:56 -0800 | [diff] [blame] | 107 | bool DoStartField(); |
vasilvv | 7cac7b0 | 2020-10-08 12:32:10 -0700 | [diff] [blame] | 108 | bool DoReadBit(absl::string_view data); |
| 109 | bool DoVarintStart(absl::string_view data, size_t* bytes_consumed); |
| 110 | bool DoVarintResume(absl::string_view data, size_t* bytes_consumed); |
bnc | fb4f4fc | 2019-11-18 17:14:56 -0800 | [diff] [blame] | 111 | bool DoVarintDone(); |
vasilvv | 7cac7b0 | 2020-10-08 12:32:10 -0700 | [diff] [blame] | 112 | bool DoReadString(absl::string_view data, size_t* bytes_consumed); |
bnc | fb4f4fc | 2019-11-18 17:14:56 -0800 | [diff] [blame] | 113 | bool DoReadStringDone(); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 114 | |
| 115 | // Identify instruction based on opcode encoded in |byte|. |
| 116 | // Returns a pointer to an element of |*language_|. |
| 117 | const QpackInstruction* LookupOpcode(uint8_t byte) const; |
| 118 | |
bnc | 34a2680 | 2020-10-17 05:09:54 -0700 | [diff] [blame] | 119 | // Stops decoding and calls Delegate::OnInstructionDecodingError(). |
bnc | 4e44010 | 2020-10-20 17:32:29 -0700 | [diff] [blame] | 120 | void OnError(ErrorCode error_code, absl::string_view error_message); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 121 | |
| 122 | // Describes the language used for decoding. |
| 123 | const QpackLanguage* const language_; |
| 124 | |
| 125 | // The Delegate to notify of decoded instructions and errors. |
| 126 | Delegate* const delegate_; |
| 127 | |
| 128 | // Storage for decoded field values. |
| 129 | bool s_bit_; |
| 130 | uint64_t varint_; |
| 131 | uint64_t varint2_; |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 132 | std::string name_; |
| 133 | std::string value_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 134 | // Whether the currently decoded header name or value is Huffman encoded. |
| 135 | bool is_huffman_encoded_; |
| 136 | // Length of string being read into |name_| or |value_|. |
| 137 | size_t string_length_; |
| 138 | |
| 139 | // Decoder instance for decoding integers. |
| 140 | http2::HpackVarintDecoder varint_decoder_; |
| 141 | |
| 142 | // Decoder instance for decoding Huffman encoded strings. |
| 143 | http2::HpackHuffmanDecoder huffman_decoder_; |
| 144 | |
bnc | fb4f4fc | 2019-11-18 17:14:56 -0800 | [diff] [blame] | 145 | // True if a decoding error has been detected by QpackInstructionDecoder. |
| 146 | // Only used in DCHECKs. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 147 | bool error_detected_; |
| 148 | |
| 149 | // Decoding state. |
| 150 | State state_; |
| 151 | |
| 152 | // Instruction currently being decoded. |
| 153 | const QpackInstruction* instruction_; |
| 154 | |
| 155 | // Field currently being decoded. |
| 156 | QpackInstructionFields::const_iterator field_; |
| 157 | }; |
| 158 | |
| 159 | } // namespace quic |
| 160 | |
| 161 | #endif // QUICHE_QUIC_CORE_QPACK_QPACK_INSTRUCTION_DECODER_H_ |