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   }
42   // Since the value doesn't come over the wire, only a programming bug should
43   // result in reaching this point.
44   auto v2 = static_cast<int>(v);
45   QUICHE_BUG(http2_bug_50_2)
46       << "Invalid HpackDecoderStringBuffer::Backing: " << v2;
47   return out << "HpackDecoderStringBuffer::Backing(" << v2 << ")";
48 }
49 
HpackDecoderStringBuffer()50 HpackDecoderStringBuffer::HpackDecoderStringBuffer()
51     : remaining_len_(0),
52       is_huffman_encoded_(false),
53       state_(State::RESET),
54       backing_(Backing::RESET) {}
55 HpackDecoderStringBuffer::~HpackDecoderStringBuffer() = default;
56 
Reset()57 void HpackDecoderStringBuffer::Reset() {
58   QUICHE_DVLOG(3) << "HpackDecoderStringBuffer::Reset";
59   state_ = State::RESET;
60 }
61 
OnStart(bool huffman_encoded,size_t len)62 void HpackDecoderStringBuffer::OnStart(bool huffman_encoded, size_t len) {
63   QUICHE_DVLOG(2) << "HpackDecoderStringBuffer::OnStart";
64   QUICHE_DCHECK_EQ(state_, State::RESET);
65 
66   remaining_len_ = len;
67   is_huffman_encoded_ = huffman_encoded;
68   state_ = State::COLLECTING;
69 
70   if (huffman_encoded) {
71     // We don't set, clear or use value_ for buffered strings until OnEnd.
72     decoder_.Reset();
73     buffer_.clear();
74     backing_ = Backing::BUFFERED;
75 
76     // Reserve space in buffer_ for the uncompressed string, assuming the
77     // maximum expansion. The shortest Huffman codes in the RFC are 5 bits long,
78     // which then expand to 8 bits during decoding (i.e. each code is for one
79     // plain text octet, aka byte), so the maximum size is 60% longer than the
80     // encoded size.
81     len = len * 8 / 5;
82     if (buffer_.capacity() < len) {
83       buffer_.reserve(len);
84     }
85   } else {
86     // Assume for now that we won't need to use buffer_, so don't reserve space
87     // in it.
88     backing_ = Backing::RESET;
89     // OnData is not called for empty (zero length) strings, so make sure that
90     // value_ is cleared.
91     value_ = absl::string_view();
92   }
93 }
94 
OnData(const char * data,size_t len)95 bool HpackDecoderStringBuffer::OnData(const char* data, size_t len) {
96   QUICHE_DVLOG(2) << "HpackDecoderStringBuffer::OnData state=" << state_
97                   << ", backing=" << backing_;
98   QUICHE_DCHECK_EQ(state_, State::COLLECTING);
99   QUICHE_DCHECK_LE(len, remaining_len_);
100   remaining_len_ -= len;
101 
102   if (is_huffman_encoded_) {
103     QUICHE_DCHECK_EQ(backing_, Backing::BUFFERED);
104     return decoder_.Decode(absl::string_view(data, len), &buffer_);
105   }
106 
107   if (backing_ == Backing::RESET) {
108     // This is the first call to OnData. If data contains the entire string,
109     // don't copy the string. If we later find that the HPACK entry is split
110     // across input buffers, then we'll copy the string into buffer_.
111     if (remaining_len_ == 0) {
112       value_ = absl::string_view(data, len);
113       backing_ = Backing::UNBUFFERED;
114       return true;
115     }
116 
117     // We need to buffer the string because it is split across input buffers.
118     // Reserve space in buffer_ for the entire string.
119     backing_ = Backing::BUFFERED;
120     buffer_.reserve(remaining_len_ + len);
121     buffer_.assign(data, len);
122     return true;
123   }
124 
125   // This is not the first call to OnData for this string, so it should be
126   // buffered.
127   QUICHE_DCHECK_EQ(backing_, Backing::BUFFERED);
128 
129   // Append to the current contents of the buffer.
130   buffer_.append(data, len);
131   return true;
132 }
133 
OnEnd()134 bool HpackDecoderStringBuffer::OnEnd() {
135   QUICHE_DVLOG(2) << "HpackDecoderStringBuffer::OnEnd";
136   QUICHE_DCHECK_EQ(state_, State::COLLECTING);
137   QUICHE_DCHECK_EQ(0u, remaining_len_);
138 
139   if (is_huffman_encoded_) {
140     QUICHE_DCHECK_EQ(backing_, Backing::BUFFERED);
141     // Did the Huffman encoding of the string end properly?
142     if (!decoder_.InputProperlyTerminated()) {
143       return false;  // No, it didn't.
144     }
145     value_ = buffer_;
146   } else if (backing_ == Backing::BUFFERED) {
147     value_ = buffer_;
148   }
149   state_ = State::COMPLETE;
150   return true;
151 }
152 
BufferStringIfUnbuffered()153 void HpackDecoderStringBuffer::BufferStringIfUnbuffered() {
154   QUICHE_DVLOG(3) << "HpackDecoderStringBuffer::BufferStringIfUnbuffered state="
155                   << state_ << ", backing=" << backing_;
156   if (state_ != State::RESET && backing_ == Backing::UNBUFFERED) {
157     QUICHE_DVLOG(2)
158         << "HpackDecoderStringBuffer buffering std::string of length "
159         << value_.size();
160     buffer_.assign(value_.data(), value_.size());
161     if (state_ == State::COMPLETE) {
162       value_ = buffer_;
163     }
164     backing_ = Backing::BUFFERED;
165   }
166 }
167 
IsBuffered() const168 bool HpackDecoderStringBuffer::IsBuffered() const {
169   QUICHE_DVLOG(3) << "HpackDecoderStringBuffer::IsBuffered";
170   return state_ != State::RESET && backing_ == Backing::BUFFERED;
171 }
172 
BufferedLength() const173 size_t HpackDecoderStringBuffer::BufferedLength() const {
174   QUICHE_DVLOG(3) << "HpackDecoderStringBuffer::BufferedLength";
175   return IsBuffered() ? buffer_.size() : 0;
176 }
177 
str() const178 absl::string_view HpackDecoderStringBuffer::str() const {
179   QUICHE_DVLOG(3) << "HpackDecoderStringBuffer::str";
180   QUICHE_DCHECK_EQ(state_, State::COMPLETE);
181   return value_;
182 }
183 
GetStringIfComplete() const184 absl::string_view HpackDecoderStringBuffer::GetStringIfComplete() const {
185   if (state_ != State::COMPLETE) {
186     return {};
187   }
188   return str();
189 }
190 
ReleaseString()191 std::string HpackDecoderStringBuffer::ReleaseString() {
192   QUICHE_DVLOG(3) << "HpackDecoderStringBuffer::ReleaseString";
193   QUICHE_DCHECK_EQ(state_, State::COMPLETE);
194   QUICHE_DCHECK_EQ(backing_, Backing::BUFFERED);
195   if (state_ == State::COMPLETE) {
196     state_ = State::RESET;
197     if (backing_ == Backing::BUFFERED) {
198       return std::move(buffer_);
199     } else {
200       return std::string(value_);
201     }
202   }
203   return "";
204 }
205 
OutputDebugStringTo(std::ostream & out) const206 void HpackDecoderStringBuffer::OutputDebugStringTo(std::ostream& out) const {
207   out << "{state=" << state_;
208   if (state_ != State::RESET) {
209     out << ", backing=" << backing_;
210     out << ", remaining_len=" << remaining_len_;
211     out << ", is_huffman_encoded=" << is_huffman_encoded_;
212     if (backing_ == Backing::BUFFERED) {
213       out << ", buffer: " << buffer_;
214     } else {
215       out << ", value: " << value_;
216     }
217   }
218   out << "}";
219 }
220 
operator <<(std::ostream & out,const HpackDecoderStringBuffer & v)221 std::ostream& operator<<(std::ostream& out, const HpackDecoderStringBuffer& v) {
222   v.OutputDebugStringTo(out);
223   return out;
224 }
225 
226 }  // namespace http2
227