blob: 6a200085cb74a74103b09f6d26031c413adce5e7 [file] [log] [blame]
QUICHE teamfd50a402018-12-07 22:54:05 -05001// 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 "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_string_buffer.h"
6
7#include <utility>
8
QUICHE teamfd50a402018-12-07 22:54:05 -05009#include "net/third_party/quiche/src/http2/platform/api/http2_bug_tracker.h"
10#include "net/third_party/quiche/src/http2/platform/api/http2_estimate_memory_usage.h"
QUICHE team61940b42019-03-07 23:32:27 -050011#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
QUICHE teamfd50a402018-12-07 22:54:05 -050012
13namespace http2 {
14
15std::ostream& operator<<(std::ostream& out,
16 const HpackDecoderStringBuffer::State v) {
17 switch (v) {
18 case HpackDecoderStringBuffer::State::RESET:
19 return out << "RESET";
20 case HpackDecoderStringBuffer::State::COLLECTING:
21 return out << "COLLECTING";
22 case HpackDecoderStringBuffer::State::COMPLETE:
23 return out << "COMPLETE";
24 }
25 // Since the value doesn't come over the wire, only a programming bug should
26 // result in reaching this point.
27 int unknown = static_cast<int>(v);
28 HTTP2_BUG << "Invalid HpackDecoderStringBuffer::State: " << unknown;
29 return out << "HpackDecoderStringBuffer::State(" << unknown << ")";
30}
31
32std::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 HTTP2_BUG << "Invalid HpackDecoderStringBuffer::Backing: " << v2;
48 return out << "HpackDecoderStringBuffer::Backing(" << v2 << ")";
49}
50
51HpackDecoderStringBuffer::HpackDecoderStringBuffer()
52 : remaining_len_(0),
53 is_huffman_encoded_(false),
54 state_(State::RESET),
55 backing_(Backing::RESET) {}
56HpackDecoderStringBuffer::~HpackDecoderStringBuffer() = default;
57
58void HpackDecoderStringBuffer::Reset() {
QUICHE team61940b42019-03-07 23:32:27 -050059 HTTP2_DVLOG(3) << "HpackDecoderStringBuffer::Reset";
QUICHE teamfd50a402018-12-07 22:54:05 -050060 state_ = State::RESET;
61}
62
63void HpackDecoderStringBuffer::Set(Http2StringPiece value, bool is_static) {
QUICHE team61940b42019-03-07 23:32:27 -050064 HTTP2_DVLOG(2) << "HpackDecoderStringBuffer::Set";
QUICHE teamfd50a402018-12-07 22:54:05 -050065 DCHECK_EQ(state_, State::RESET);
66 value_ = value;
67 state_ = State::COMPLETE;
68 backing_ = is_static ? Backing::STATIC : Backing::UNBUFFERED;
69 // TODO(jamessynge): Determine which of these two fields must be set.
70 remaining_len_ = 0;
71 is_huffman_encoded_ = false;
72}
73
74void HpackDecoderStringBuffer::OnStart(bool huffman_encoded, size_t len) {
QUICHE team61940b42019-03-07 23:32:27 -050075 HTTP2_DVLOG(2) << "HpackDecoderStringBuffer::OnStart";
QUICHE teamfd50a402018-12-07 22:54:05 -050076 DCHECK_EQ(state_, State::RESET);
77
78 remaining_len_ = len;
79 is_huffman_encoded_ = huffman_encoded;
80 state_ = State::COLLECTING;
81
82 if (huffman_encoded) {
83 // We don't set, clear or use value_ for buffered strings until OnEnd.
84 decoder_.Reset();
85 buffer_.clear();
86 backing_ = Backing::BUFFERED;
87
88 // Reserve space in buffer_ for the uncompressed string, assuming the
89 // maximum expansion. The shortest Huffman codes in the RFC are 5 bits long,
90 // which then expand to 8 bits during decoding (i.e. each code is for one
91 // plain text octet, aka byte), so the maximum size is 60% longer than the
92 // encoded size.
93 len = len * 8 / 5;
94 if (buffer_.capacity() < len) {
95 buffer_.reserve(len);
96 }
97 } else {
98 // Assume for now that we won't need to use buffer_, so don't reserve space
99 // in it.
100 backing_ = Backing::RESET;
101 // OnData is not called for empty (zero length) strings, so make sure that
102 // value_ is cleared.
103 value_ = Http2StringPiece();
104 }
105}
106
107bool HpackDecoderStringBuffer::OnData(const char* data, size_t len) {
QUICHE team61940b42019-03-07 23:32:27 -0500108 HTTP2_DVLOG(2) << "HpackDecoderStringBuffer::OnData state=" << state_
109 << ", backing=" << backing_;
QUICHE teamfd50a402018-12-07 22:54:05 -0500110 DCHECK_EQ(state_, State::COLLECTING);
111 DCHECK_LE(len, remaining_len_);
112 remaining_len_ -= len;
113
114 if (is_huffman_encoded_) {
115 DCHECK_EQ(backing_, Backing::BUFFERED);
116 return decoder_.Decode(Http2StringPiece(data, len), &buffer_);
117 }
118
119 if (backing_ == Backing::RESET) {
120 // This is the first call to OnData. If data contains the entire string,
121 // don't copy the string. If we later find that the HPACK entry is split
122 // across input buffers, then we'll copy the string into buffer_.
123 if (remaining_len_ == 0) {
124 value_ = Http2StringPiece(data, len);
125 backing_ = Backing::UNBUFFERED;
126 return true;
127 }
128
129 // We need to buffer the string because it is split across input buffers.
130 // Reserve space in buffer_ for the entire string.
131 backing_ = Backing::BUFFERED;
132 buffer_.reserve(remaining_len_ + len);
133 buffer_.assign(data, len);
134 return true;
135 }
136
137 // This is not the first call to OnData for this string, so it should be
138 // buffered.
139 DCHECK_EQ(backing_, Backing::BUFFERED);
140
141 // Append to the current contents of the buffer.
142 buffer_.append(data, len);
143 return true;
144}
145
146bool HpackDecoderStringBuffer::OnEnd() {
QUICHE team61940b42019-03-07 23:32:27 -0500147 HTTP2_DVLOG(2) << "HpackDecoderStringBuffer::OnEnd";
QUICHE teamfd50a402018-12-07 22:54:05 -0500148 DCHECK_EQ(state_, State::COLLECTING);
149 DCHECK_EQ(0u, remaining_len_);
150
151 if (is_huffman_encoded_) {
152 DCHECK_EQ(backing_, Backing::BUFFERED);
153 // Did the Huffman encoding of the string end properly?
154 if (!decoder_.InputProperlyTerminated()) {
155 return false; // No, it didn't.
156 }
157 value_ = buffer_;
158 } else if (backing_ == Backing::BUFFERED) {
159 value_ = buffer_;
160 }
161 state_ = State::COMPLETE;
162 return true;
163}
164
165void HpackDecoderStringBuffer::BufferStringIfUnbuffered() {
QUICHE team61940b42019-03-07 23:32:27 -0500166 HTTP2_DVLOG(3) << "HpackDecoderStringBuffer::BufferStringIfUnbuffered state="
167 << state_ << ", backing=" << backing_;
QUICHE teamfd50a402018-12-07 22:54:05 -0500168 if (state_ != State::RESET && backing_ == Backing::UNBUFFERED) {
QUICHE team61940b42019-03-07 23:32:27 -0500169 HTTP2_DVLOG(2)
bnc47904002019-08-16 11:49:48 -0700170 << "HpackDecoderStringBuffer buffering std::string of length "
QUICHE team61940b42019-03-07 23:32:27 -0500171 << value_.size();
QUICHE teamfd50a402018-12-07 22:54:05 -0500172 buffer_.assign(value_.data(), value_.size());
173 if (state_ == State::COMPLETE) {
174 value_ = buffer_;
175 }
176 backing_ = Backing::BUFFERED;
177 }
178}
179
180bool HpackDecoderStringBuffer::IsBuffered() const {
QUICHE team61940b42019-03-07 23:32:27 -0500181 HTTP2_DVLOG(3) << "HpackDecoderStringBuffer::IsBuffered";
QUICHE teamfd50a402018-12-07 22:54:05 -0500182 return state_ != State::RESET && backing_ == Backing::BUFFERED;
183}
184
185size_t HpackDecoderStringBuffer::BufferedLength() const {
QUICHE team61940b42019-03-07 23:32:27 -0500186 HTTP2_DVLOG(3) << "HpackDecoderStringBuffer::BufferedLength";
QUICHE teamfd50a402018-12-07 22:54:05 -0500187 return IsBuffered() ? buffer_.size() : 0;
188}
189
190Http2StringPiece HpackDecoderStringBuffer::str() const {
QUICHE team61940b42019-03-07 23:32:27 -0500191 HTTP2_DVLOG(3) << "HpackDecoderStringBuffer::str";
QUICHE teamfd50a402018-12-07 22:54:05 -0500192 DCHECK_EQ(state_, State::COMPLETE);
193 return value_;
194}
195
bnc47904002019-08-16 11:49:48 -0700196std::string HpackDecoderStringBuffer::ReleaseString() {
QUICHE team61940b42019-03-07 23:32:27 -0500197 HTTP2_DVLOG(3) << "HpackDecoderStringBuffer::ReleaseString";
QUICHE teamfd50a402018-12-07 22:54:05 -0500198 DCHECK_EQ(state_, State::COMPLETE);
199 DCHECK_EQ(backing_, Backing::BUFFERED);
200 if (state_ == State::COMPLETE) {
201 state_ = State::RESET;
202 if (backing_ == Backing::BUFFERED) {
203 return std::move(buffer_);
204 } else {
bnc47904002019-08-16 11:49:48 -0700205 return std::string(value_);
QUICHE teamfd50a402018-12-07 22:54:05 -0500206 }
207 }
208 return "";
209}
210
211void HpackDecoderStringBuffer::OutputDebugStringTo(std::ostream& out) const {
212 out << "{state=" << state_;
213 if (state_ != State::RESET) {
214 out << ", backing=" << backing_;
215 out << ", remaining_len=" << remaining_len_;
216 out << ", is_huffman_encoded=" << is_huffman_encoded_;
217 if (backing_ == Backing::BUFFERED) {
218 out << ", buffer: " << buffer_;
219 } else {
220 out << ", value: " << value_;
221 }
222 }
223 out << "}";
224}
225
226size_t HpackDecoderStringBuffer::EstimateMemoryUsage() const {
227 return Http2EstimateMemoryUsage(buffer_);
228}
229
230std::ostream& operator<<(std::ostream& out, const HpackDecoderStringBuffer& v) {
231 v.OutputDebugStringTo(out);
232 return out;
233}
234
235} // namespace http2