• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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