blob: 8a4e17a0f537f99676e75a125f01881fcac7883f [file] [log] [blame]
QUICHE team82dee2f2019-01-18 12:35:12 -05001// Copyright 2017 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/spdy/core/hpack/hpack_decoder_adapter.h"
6
QUICHE team82dee2f2019-01-18 12:35:12 -05007#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
8#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
9#include "net/third_party/quiche/src/spdy/platform/api/spdy_estimate_memory_usage.h"
renjietang6932faf2020-01-22 13:03:14 -080010#include "net/third_party/quiche/src/spdy/platform/api/spdy_flags.h"
QUICHE teamded03512019-03-07 14:45:11 -080011#include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h"
QUICHE team82dee2f2019-01-18 12:35:12 -050012
13using ::http2::DecodeBuffer;
QUICHE team82dee2f2019-01-18 12:35:12 -050014using ::http2::HpackString;
15
16namespace spdy {
17namespace {
18const size_t kMaxDecodeBufferSizeBytes = 32 * 1024; // 32 KB
19} // namespace
20
21HpackDecoderAdapter::HpackDecoderAdapter()
22 : hpack_decoder_(&listener_adapter_, kMaxDecodeBufferSizeBytes),
23 max_decode_buffer_size_bytes_(kMaxDecodeBufferSizeBytes),
QUICHE team62754842019-07-23 14:06:29 -070024 max_header_block_bytes_(0),
bnc9b561112020-02-07 07:57:05 -080025 header_block_started_(false),
26 error_(http2::HpackDecodingError::kOk) {}
QUICHE team82dee2f2019-01-18 12:35:12 -050027
28HpackDecoderAdapter::~HpackDecoderAdapter() = default;
29
30void HpackDecoderAdapter::ApplyHeaderTableSizeSetting(size_t size_setting) {
QUICHE teamded03512019-03-07 14:45:11 -080031 SPDY_DVLOG(2) << "HpackDecoderAdapter::ApplyHeaderTableSizeSetting";
QUICHE team82dee2f2019-01-18 12:35:12 -050032 hpack_decoder_.ApplyHeaderTableSizeSetting(size_setting);
33}
34
35void HpackDecoderAdapter::HandleControlFrameHeadersStart(
36 SpdyHeadersHandlerInterface* handler) {
QUICHE teamded03512019-03-07 14:45:11 -080037 SPDY_DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersStart";
QUICHE team82dee2f2019-01-18 12:35:12 -050038 DCHECK(!header_block_started_);
39 listener_adapter_.set_handler(handler);
40}
41
42bool HpackDecoderAdapter::HandleControlFrameHeadersData(
43 const char* headers_data,
44 size_t headers_data_length) {
QUICHE teamded03512019-03-07 14:45:11 -080045 SPDY_DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersData: len="
46 << headers_data_length;
QUICHE team82dee2f2019-01-18 12:35:12 -050047 if (!header_block_started_) {
48 // Initialize the decoding process here rather than in
49 // HandleControlFrameHeadersStart because that method is not always called.
50 header_block_started_ = true;
51 if (!hpack_decoder_.StartDecodingBlock()) {
52 header_block_started_ = false;
renjietang439c7692020-01-22 18:36:28 -080053 SPDY_CODE_COUNT_N(decompress_failure_2, 1, 5);
bnc9b561112020-02-07 07:57:05 -080054 error_ = hpack_decoder_.error();
QUICHE team82dee2f2019-01-18 12:35:12 -050055 return false;
56 }
57 }
58
59 // Sometimes we get a call with headers_data==nullptr and
60 // headers_data_length==0, in which case we need to avoid creating
61 // a DecodeBuffer, which would otherwise complain.
62 if (headers_data_length > 0) {
63 DCHECK_NE(headers_data, nullptr);
64 if (headers_data_length > max_decode_buffer_size_bytes_) {
QUICHE teamded03512019-03-07 14:45:11 -080065 SPDY_DVLOG(1) << "max_decode_buffer_size_bytes_ < headers_data_length: "
66 << max_decode_buffer_size_bytes_ << " < "
67 << headers_data_length;
renjietang439c7692020-01-22 18:36:28 -080068 SPDY_CODE_COUNT_N(decompress_failure_2, 2, 5);
bnc9b561112020-02-07 07:57:05 -080069 error_ = http2::HpackDecodingError::kFragmentTooLong;
QUICHE team82dee2f2019-01-18 12:35:12 -050070 return false;
71 }
72 listener_adapter_.AddToTotalHpackBytes(headers_data_length);
QUICHE team62754842019-07-23 14:06:29 -070073 if (max_header_block_bytes_ != 0 &&
74 listener_adapter_.total_hpack_bytes() > max_header_block_bytes_) {
renjietang439c7692020-01-22 18:36:28 -080075 SPDY_CODE_COUNT_N(decompress_failure, 3, 5);
bnc9b561112020-02-07 07:57:05 -080076 error_ = http2::HpackDecodingError::kCompressedHeaderSizeExceedsLimit;
QUICHE team62754842019-07-23 14:06:29 -070077 return false;
78 }
QUICHE team82dee2f2019-01-18 12:35:12 -050079 http2::DecodeBuffer db(headers_data, headers_data_length);
80 bool ok = hpack_decoder_.DecodeFragment(&db);
81 DCHECK(!ok || db.Empty()) << "Remaining=" << db.Remaining();
renjietang439c7692020-01-22 18:36:28 -080082 if (!ok) {
83 SPDY_CODE_COUNT_N(decompress_failure_2, 4, 5);
bnc9b561112020-02-07 07:57:05 -080084 error_ = hpack_decoder_.error();
renjietang439c7692020-01-22 18:36:28 -080085 }
QUICHE team82dee2f2019-01-18 12:35:12 -050086 return ok;
87 }
88 return true;
89}
90
91bool HpackDecoderAdapter::HandleControlFrameHeadersComplete(
92 size_t* compressed_len) {
QUICHE teamded03512019-03-07 14:45:11 -080093 SPDY_DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersComplete";
QUICHE team82dee2f2019-01-18 12:35:12 -050094 if (compressed_len != nullptr) {
95 *compressed_len = listener_adapter_.total_hpack_bytes();
96 }
97 if (!hpack_decoder_.EndDecodingBlock()) {
QUICHE teamded03512019-03-07 14:45:11 -080098 SPDY_DVLOG(3) << "EndDecodingBlock returned false";
renjietang439c7692020-01-22 18:36:28 -080099 SPDY_CODE_COUNT_N(decompress_failure_2, 5, 5);
bnc9b561112020-02-07 07:57:05 -0800100 error_ = hpack_decoder_.error();
QUICHE team82dee2f2019-01-18 12:35:12 -0500101 return false;
102 }
103 header_block_started_ = false;
104 return true;
105}
106
107const SpdyHeaderBlock& HpackDecoderAdapter::decoded_block() const {
108 return listener_adapter_.decoded_block();
109}
110
111void HpackDecoderAdapter::SetHeaderTableDebugVisitor(
112 std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) {
QUICHE teamded03512019-03-07 14:45:11 -0800113 SPDY_DVLOG(2) << "HpackDecoderAdapter::SetHeaderTableDebugVisitor";
QUICHE team82dee2f2019-01-18 12:35:12 -0500114 if (visitor != nullptr) {
115 listener_adapter_.SetHeaderTableDebugVisitor(std::move(visitor));
116 hpack_decoder_.set_tables_debug_listener(&listener_adapter_);
117 } else {
118 hpack_decoder_.set_tables_debug_listener(nullptr);
119 listener_adapter_.SetHeaderTableDebugVisitor(nullptr);
120 }
121}
122
123void HpackDecoderAdapter::set_max_decode_buffer_size_bytes(
124 size_t max_decode_buffer_size_bytes) {
QUICHE teamded03512019-03-07 14:45:11 -0800125 SPDY_DVLOG(2) << "HpackDecoderAdapter::set_max_decode_buffer_size_bytes";
QUICHE team82dee2f2019-01-18 12:35:12 -0500126 max_decode_buffer_size_bytes_ = max_decode_buffer_size_bytes;
127 hpack_decoder_.set_max_string_size_bytes(max_decode_buffer_size_bytes);
128}
129
QUICHE team62754842019-07-23 14:06:29 -0700130void HpackDecoderAdapter::set_max_header_block_bytes(
131 size_t max_header_block_bytes) {
132 max_header_block_bytes_ = max_header_block_bytes;
133}
134
QUICHE team82dee2f2019-01-18 12:35:12 -0500135size_t HpackDecoderAdapter::EstimateMemoryUsage() const {
136 return SpdyEstimateMemoryUsage(hpack_decoder_);
137}
138
139HpackDecoderAdapter::ListenerAdapter::ListenerAdapter() : handler_(nullptr) {}
140HpackDecoderAdapter::ListenerAdapter::~ListenerAdapter() = default;
141
142void HpackDecoderAdapter::ListenerAdapter::set_handler(
143 SpdyHeadersHandlerInterface* handler) {
144 handler_ = handler;
145}
146
147void HpackDecoderAdapter::ListenerAdapter::SetHeaderTableDebugVisitor(
148 std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) {
149 visitor_ = std::move(visitor);
150}
151
152void HpackDecoderAdapter::ListenerAdapter::OnHeaderListStart() {
QUICHE teamded03512019-03-07 14:45:11 -0800153 SPDY_DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeaderListStart";
QUICHE team82dee2f2019-01-18 12:35:12 -0500154 total_hpack_bytes_ = 0;
155 total_uncompressed_bytes_ = 0;
156 decoded_block_.clear();
157 if (handler_ != nullptr) {
158 handler_->OnHeaderBlockStart();
159 }
160}
161
zhongyieff02bb2019-12-13 14:38:48 -0800162void HpackDecoderAdapter::ListenerAdapter::OnHeader(const HpackString& name,
QUICHE team82dee2f2019-01-18 12:35:12 -0500163 const HpackString& value) {
QUICHE teamded03512019-03-07 14:45:11 -0800164 SPDY_DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeader:\n name: "
165 << name << "\n value: " << value;
QUICHE team82dee2f2019-01-18 12:35:12 -0500166 total_uncompressed_bytes_ += name.size() + value.size();
167 if (handler_ == nullptr) {
QUICHE teamded03512019-03-07 14:45:11 -0800168 SPDY_DVLOG(3) << "Adding to decoded_block";
QUICHE team82dee2f2019-01-18 12:35:12 -0500169 decoded_block_.AppendValueOrAddHeader(name.ToStringPiece(),
170 value.ToStringPiece());
171 } else {
QUICHE teamded03512019-03-07 14:45:11 -0800172 SPDY_DVLOG(3) << "Passing to handler";
QUICHE team82dee2f2019-01-18 12:35:12 -0500173 handler_->OnHeader(name.ToStringPiece(), value.ToStringPiece());
174 }
175}
176
177void HpackDecoderAdapter::ListenerAdapter::OnHeaderListEnd() {
QUICHE teamded03512019-03-07 14:45:11 -0800178 SPDY_DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeaderListEnd";
QUICHE team82dee2f2019-01-18 12:35:12 -0500179 // We don't clear the SpdyHeaderBlock here to allow access to it until the
180 // next HPACK block is decoded.
181 if (handler_ != nullptr) {
182 handler_->OnHeaderBlockEnd(total_uncompressed_bytes_, total_hpack_bytes_);
183 handler_ = nullptr;
184 }
185}
186
187void HpackDecoderAdapter::ListenerAdapter::OnHeaderErrorDetected(
bnc7f82d042020-01-03 12:18:53 -0800188 quiche::QuicheStringPiece error_message) {
QUICHE teamded03512019-03-07 14:45:11 -0800189 SPDY_VLOG(1) << error_message;
QUICHE team82dee2f2019-01-18 12:35:12 -0500190}
191
192int64_t HpackDecoderAdapter::ListenerAdapter::OnEntryInserted(
zhongyieff02bb2019-12-13 14:38:48 -0800193 const http2::HpackStringPair& entry,
QUICHE team82dee2f2019-01-18 12:35:12 -0500194 size_t insert_count) {
QUICHE teamded03512019-03-07 14:45:11 -0800195 SPDY_DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnEntryInserted: "
zhongyieff02bb2019-12-13 14:38:48 -0800196 << entry << ", insert_count=" << insert_count;
QUICHE team82dee2f2019-01-18 12:35:12 -0500197 if (visitor_ == nullptr) {
198 return 0;
199 }
zhongyieff02bb2019-12-13 14:38:48 -0800200 HpackEntry hpack_entry(entry.name.ToStringPiece(),
201 entry.value.ToStringPiece(),
202 /*is_static*/ false, insert_count);
203 int64_t time_added = visitor_->OnNewEntry(hpack_entry);
QUICHE teamded03512019-03-07 14:45:11 -0800204 SPDY_DVLOG(2)
QUICHE team82dee2f2019-01-18 12:35:12 -0500205 << "HpackDecoderAdapter::ListenerAdapter::OnEntryInserted: time_added="
206 << time_added;
207 return time_added;
208}
209
210void HpackDecoderAdapter::ListenerAdapter::OnUseEntry(
zhongyieff02bb2019-12-13 14:38:48 -0800211 const http2::HpackStringPair& entry,
QUICHE team82dee2f2019-01-18 12:35:12 -0500212 size_t insert_count,
213 int64_t time_added) {
zhongyieff02bb2019-12-13 14:38:48 -0800214 SPDY_DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnUseEntry: " << entry
QUICHE teamded03512019-03-07 14:45:11 -0800215 << ", insert_count=" << insert_count
216 << ", time_added=" << time_added;
QUICHE team82dee2f2019-01-18 12:35:12 -0500217 if (visitor_ != nullptr) {
zhongyieff02bb2019-12-13 14:38:48 -0800218 HpackEntry hpack_entry(entry.name.ToStringPiece(),
219 entry.value.ToStringPiece(), /*is_static*/ false,
220 insert_count);
221 hpack_entry.set_time_added(time_added);
222 visitor_->OnUseEntry(hpack_entry);
QUICHE team82dee2f2019-01-18 12:35:12 -0500223 }
224}
225
226} // namespace spdy