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
3 // found in the LICENSE file.
4
5 #include "quiche/http2/hpack/decoder/hpack_decoder_string_buffer.h"
6
7 #include <utility>
8
9 #include "quiche/common/platform/api/quiche_bug_tracker.h"
10 #include "quiche/common/platform/api/quiche_logging.h"
11
12 namespace http2 {
13
operator <<(std::ostream & out,const HpackDecoderStringBuffer::State v)14 std::ostream& operator<<(std::ostream& out,
15 const HpackDecoderStringBuffer::State v) {
16 switch (v) {
17 case HpackDecoderStringBuffer::State::RESET:
18 return out << "RESET";
19 case HpackDecoderStringBuffer::State::COLLECTING:
20 return out << "COLLECTING";
21 case HpackDecoderStringBuffer::State::COMPLETE:
22 return out << "COMPLETE";
23 }
24 // Since the value doesn't come over the wire, only a programming bug should
25 // result in reaching this point.
26 int unknown = static_cast<int>(v);
27 QUICHE_BUG(http2_bug_50_1)
28 << "Invalid HpackDecoderStringBuffer::State: " << unknown;
29 return out << "HpackDecoderStringBuffer::State(" << unknown << ")";
30 }
31
operator <<(std::ostream & out,const HpackDecoderStringBuffer::Backing v)32 std::ostream& operator<<(std::ostream& out,
33 const HpackDecoderStringBuffer::Backing v) {
34 switch (v) {
35 case HpackDecoderStringBuffer::Backing::RESET:
36 return out << "RESET";
37 case HpackDecoderStringBuffer::Backing::UNBUFFERED:
38 return out << "UNBUFFERED";
39 case HpackDecoderStringBuffer::Backing::BUFFERED:
40 return out << "BUFFERED";
41 case HpackDecoderStringBuffer::Backing::STATIC:
42 return out << "STATIC";
43 }
44 // Since the value doesn't come over the wire, only a programming bug should
45 // result in reaching this point.
46 auto v2 = static_cast<int>(v);
47 QUICHE_BUG(http2_bug_50_2)
48 << "Invalid HpackDecoderStringBuffer::Backing: " << v2;
49 return out << "HpackDecoderStringBuffer::Backing(" << v2 << ")";
50 }
51
HpackDecoderStringBuffer()52 HpackDecoderStringBuffer::HpackDecoderStringBuffer()
53 : remaining_len_(0),
54 is_huffman_encoded_(false),
55 state_(State::RESET),
56 backing_(Backing::RESET) {}
57 HpackDecoderStringBuffer::~HpackDecoderStringBuffer() = default;
58
Reset()59 void HpackDecoderStringBuffer::Reset() {
60 QUICHE_DVLOG(3) << "HpackDecoderStringBuffer::Reset";
61 state_ = State::RESET;
62 }
63
Set(absl::string_view value,bool is_static)64 void HpackDecoderStringBuffer::Set(absl::string_view value, bool is_static) {
65 QUICHE_DVLOG(2) << "HpackDecoderStringBuffer::Set";
66 QUICHE_DCHECK_EQ(state_, State::RESET);
67 value_ = value;
68 state_ = State::COMPLETE;
69 backing_ = is_static ? Backing::STATIC : Backing::UNBUFFERED;
70 // TODO(jamessynge): Determine which of these two fields must be set.
71 remaining_len_ = 0;
72 is_huffman_encoded_ = false;
73 }
74
OnStart(bool huffman_encoded,size_t len)75 void HpackDecoderStringBuffer::OnStart(bool huffman_encoded, size_t len) {
76 QUICHE_DVLOG(2) << "HpackDecoderStringBuffer::OnStart";
77 QUICHE_DCHECK_EQ(state_, State::RESET);
78
79 remaining_len_ = len;
80 is_huffman_encoded_ = huffman_encoded;
81 state_ = State::COLLECTING;
82
83 if (huffman_encoded) {
84 // We don't set, clear or use value_ for buffered strings until OnEnd.
85 decoder_.Reset();
86 buffer_.clear();
87 backing_ = Backing::BUFFERED;
88
89 // Reserve space in buffer_ for the uncompressed string, assuming the
90 // maximum expansion. The shortest Huffman codes in the RFC are 5 bits long,
91 // which then expand to 8 bits during decoding (i.e. each code is for one
92 // plain text octet, aka byte), so the maximum size is 60% longer than the
93 // encoded size.
94 len = len * 8 / 5;
95 if (buffer_.capacity() < len) {
96 buffer_.reserve(len);
97 }
98 } else {
99 // Assume for now that we won't need to use buffer_, so don't reserve space
100 // in it.
101 backing_ = Backing::RESET;
102 // OnData is not called for empty (zero length) strings, so make sure that
103 // value_ is cleared.
104 value_ = absl::string_view();
105 }
106 }
107
OnData(const char * data,size_t len)108 bool HpackDecoderStringBuffer::OnData(const char* data, size_t len) {
109 QUICHE_DVLOG(2) << "HpackDecoderStringBuffer::OnData state=" << state_
110 << ", backing=" << backing_;
111 QUICHE_DCHECK_EQ(state_, State::COLLECTING);
112 QUICHE_DCHECK_LE(len, remaining_len_);
113 remaining_len_ -= len;
114
115 if (is_huffman_encoded_) {
116 QUICHE_DCHECK_EQ(backing_, Backing::BUFFERED);
117 return decoder_.Decode(absl::string_view(data, len), &buffer_);
118 }
119
120 if (backing_ == Backing::RESET) {
121 // This is the first call to OnData. If data contains the entire string,
122 // don't copy the string. If we later find that the HPACK entry is split
123 // across input buffers, then we'll copy the string into buffer_.
124 if (remaining_len_ == 0) {
125 value_ = absl::string_view(data, len);
126 backing_ = Backing::UNBUFFERED;
127 return true;
128 }
129
130 // We need to buffer the string because it is split across input buffers.
131 // Reserve space in buffer_ for the entire string.
132 backing_ = Backing::BUFFERED;
133 buffer_.reserve(remaining_len_ + len);
134 buffer_.assign(data, len);
135 return true;
136 }
137
138 // This is not the first call to OnData for this string, so it should be
139 // buffered.
140 QUICHE_DCHECK_EQ(backing_, Backing::BUFFERED);
141
142 // Append to the current contents of the buffer.
143 buffer_.append(data, len);
144 return true;
145 }
146
OnEnd()147 bool HpackDecoderStringBuffer::OnEnd() {
148 QUICHE_DVLOG(2) << "HpackDecoderStringBuffer::OnEnd";
149 QUICHE_DCHECK_EQ(state_, State::COLLECTING);
150 QUICHE_DCHECK_EQ(0u, remaining_len_);
151
152 if (is_huffman_encoded_) {
153 QUICHE_DCHECK_EQ(backing_, Backing::BUFFERED);
154 // Did the Huffman encoding of the string end properly?
155 if (!decoder_.InputProperlyTerminated()) {
156 return false; // No, it didn't.
157 }
158 value_ = buffer_;
159 } else if (backing_ == Backing::BUFFERED) {
160 value_ = buffer_;
161 }
162 state_ = State::COMPLETE;
163 return true;
164 }
165
BufferStringIfUnbuffered()166 void HpackDecoderStringBuffer::BufferStringIfUnbuffered() {
167 QUICHE_DVLOG(3) << "HpackDecoderStringBuffer::BufferStringIfUnbuffered state="
168 << state_ << ", backing=" << backing_;
169 if (state_ != State::RESET && backing_ == Backing::UNBUFFERED) {
170 QUICHE_DVLOG(2)
171 << "HpackDecoderStringBuffer buffering std::string of length "
172 << value_.size();
173 buffer_.assign(value_.data(), value_.size());
174 if (state_ == State::COMPLETE) {
175 value_ = buffer_;
176 }
177 backing_ = Backing::BUFFERED;
178 }
179 }
180
IsBuffered() const181 bool HpackDecoderStringBuffer::IsBuffered() const {
182 QUICHE_DVLOG(3) << "HpackDecoderStringBuffer::IsBuffered";
183 return state_ != State::RESET && backing_ == Backing::BUFFERED;
184 }
185
BufferedLength() const186 size_t HpackDecoderStringBuffer::BufferedLength() const {
187 QUICHE_DVLOG(3) << "HpackDecoderStringBuffer::BufferedLength";
188 return IsBuffered() ? buffer_.size() : 0;
189 }
190
str() const191 absl::string_view HpackDecoderStringBuffer::str() const {
192 QUICHE_DVLOG(3) << "HpackDecoderStringBuffer::str";
193 QUICHE_DCHECK_EQ(state_, State::COMPLETE);
194 return value_;
195 }
196
GetStringIfComplete() const197 absl::string_view HpackDecoderStringBuffer::GetStringIfComplete() const {
198 if (state_ != State::COMPLETE) {
199 return {};
200 }
201 return str();
202 }
203
ReleaseString()204 std::string HpackDecoderStringBuffer::ReleaseString() {
205 QUICHE_DVLOG(3) << "HpackDecoderStringBuffer::ReleaseString";
206 QUICHE_DCHECK_EQ(state_, State::COMPLETE);
207 QUICHE_DCHECK_EQ(backing_, Backing::BUFFERED);
208 if (state_ == State::COMPLETE) {
209 state_ = State::RESET;
210 if (backing_ == Backing::BUFFERED) {
211 return std::move(buffer_);
212 } else {
213 return std::string(value_);
214 }
215 }
216 return "";
217 }
218
OutputDebugStringTo(std::ostream & out) const219 void HpackDecoderStringBuffer::OutputDebugStringTo(std::ostream& out) const {
220 out << "{state=" << state_;
221 if (state_ != State::RESET) {
222 out << ", backing=" << backing_;
223 out << ", remaining_len=" << remaining_len_;
224 out << ", is_huffman_encoded=" << is_huffman_encoded_;
225 if (backing_ == Backing::BUFFERED) {
226 out << ", buffer: " << buffer_;
227 } else {
228 out << ", value: " << value_;
229 }
230 }
231 out << "}";
232 }
233
operator <<(std::ostream & out,const HpackDecoderStringBuffer & v)234 std::ostream& operator<<(std::ostream& out, const HpackDecoderStringBuffer& v) {
235 v.OutputDebugStringTo(out);
236 return out;
237 }
238
239 } // namespace http2
240