1 // 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 "quiche/spdy/core/hpack/hpack_decoder_adapter.h"
6
7 #include <cstddef>
8 #include <string>
9
10 #include "absl/strings/string_view.h"
11 #include "quiche/http2/decoder/decode_buffer.h"
12 #include "quiche/http2/hpack/decoder/hpack_decoding_error.h"
13 #include "quiche/common/platform/api/quiche_logging.h"
14 #include "quiche/spdy/core/http2_header_block.h"
15 #include "quiche/spdy/core/spdy_headers_handler_interface.h"
16
17 namespace spdy {
18 namespace {
19 const size_t kMaxDecodeBufferSizeBytes = 32 * 1024; // 32 KB
20 } // namespace
21
HpackDecoderAdapter()22 HpackDecoderAdapter::HpackDecoderAdapter()
23 : hpack_decoder_(&listener_adapter_, kMaxDecodeBufferSizeBytes),
24 max_decode_buffer_size_bytes_(kMaxDecodeBufferSizeBytes),
25 max_header_block_bytes_(0),
26 header_block_started_(false),
27 error_(http2::HpackDecodingError::kOk) {}
28
29 HpackDecoderAdapter::~HpackDecoderAdapter() = default;
30
ApplyHeaderTableSizeSetting(size_t size_setting)31 void HpackDecoderAdapter::ApplyHeaderTableSizeSetting(size_t size_setting) {
32 QUICHE_DVLOG(2) << "HpackDecoderAdapter::ApplyHeaderTableSizeSetting";
33 hpack_decoder_.ApplyHeaderTableSizeSetting(size_setting);
34 }
35
GetCurrentHeaderTableSizeSetting() const36 size_t HpackDecoderAdapter::GetCurrentHeaderTableSizeSetting() const {
37 return hpack_decoder_.GetCurrentHeaderTableSizeSetting();
38 }
39
HandleControlFrameHeadersStart(SpdyHeadersHandlerInterface * handler)40 void HpackDecoderAdapter::HandleControlFrameHeadersStart(
41 SpdyHeadersHandlerInterface* handler) {
42 QUICHE_DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersStart";
43 QUICHE_DCHECK(!header_block_started_);
44 listener_adapter_.set_handler(handler);
45 }
46
HandleControlFrameHeadersData(const char * headers_data,size_t headers_data_length)47 bool HpackDecoderAdapter::HandleControlFrameHeadersData(
48 const char* headers_data, size_t headers_data_length) {
49 QUICHE_DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersData: len="
50 << headers_data_length;
51 if (!header_block_started_) {
52 // Initialize the decoding process here rather than in
53 // HandleControlFrameHeadersStart because that method is not always called.
54 header_block_started_ = true;
55 if (!hpack_decoder_.StartDecodingBlock()) {
56 header_block_started_ = false;
57 error_ = hpack_decoder_.error();
58 return false;
59 }
60 }
61
62 // Sometimes we get a call with headers_data==nullptr and
63 // headers_data_length==0, in which case we need to avoid creating
64 // a DecodeBuffer, which would otherwise complain.
65 if (headers_data_length > 0) {
66 QUICHE_DCHECK_NE(headers_data, nullptr);
67 if (headers_data_length > max_decode_buffer_size_bytes_) {
68 QUICHE_DVLOG(1) << "max_decode_buffer_size_bytes_ < headers_data_length: "
69 << max_decode_buffer_size_bytes_ << " < "
70 << headers_data_length;
71 error_ = http2::HpackDecodingError::kFragmentTooLong;
72 return false;
73 }
74 listener_adapter_.AddToTotalHpackBytes(headers_data_length);
75 if (max_header_block_bytes_ != 0 &&
76 listener_adapter_.total_hpack_bytes() > max_header_block_bytes_) {
77 error_ = http2::HpackDecodingError::kCompressedHeaderSizeExceedsLimit;
78 return false;
79 }
80 http2::DecodeBuffer db(headers_data, headers_data_length);
81 bool ok = hpack_decoder_.DecodeFragment(&db);
82 QUICHE_DCHECK(!ok || db.Empty()) << "Remaining=" << db.Remaining();
83 if (!ok) {
84 error_ = hpack_decoder_.error();
85 }
86 return ok;
87 }
88 return true;
89 }
90
HandleControlFrameHeadersComplete()91 bool HpackDecoderAdapter::HandleControlFrameHeadersComplete() {
92 QUICHE_DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersComplete";
93 if (!hpack_decoder_.EndDecodingBlock()) {
94 QUICHE_DVLOG(3) << "EndDecodingBlock returned false";
95 error_ = hpack_decoder_.error();
96 return false;
97 }
98 header_block_started_ = false;
99 return true;
100 }
101
set_max_decode_buffer_size_bytes(size_t max_decode_buffer_size_bytes)102 void HpackDecoderAdapter::set_max_decode_buffer_size_bytes(
103 size_t max_decode_buffer_size_bytes) {
104 QUICHE_DVLOG(2) << "HpackDecoderAdapter::set_max_decode_buffer_size_bytes";
105 max_decode_buffer_size_bytes_ = max_decode_buffer_size_bytes;
106 hpack_decoder_.set_max_string_size_bytes(max_decode_buffer_size_bytes);
107 }
108
set_max_header_block_bytes(size_t max_header_block_bytes)109 void HpackDecoderAdapter::set_max_header_block_bytes(
110 size_t max_header_block_bytes) {
111 max_header_block_bytes_ = max_header_block_bytes;
112 }
113
ListenerAdapter()114 HpackDecoderAdapter::ListenerAdapter::ListenerAdapter()
115 : no_op_handler_(nullptr), handler_(&no_op_handler_) {}
116 HpackDecoderAdapter::ListenerAdapter::~ListenerAdapter() = default;
117
set_handler(SpdyHeadersHandlerInterface * handler)118 void HpackDecoderAdapter::ListenerAdapter::set_handler(
119 SpdyHeadersHandlerInterface* handler) {
120 QUICHE_CHECK_NE(handler, nullptr);
121 handler_ = handler;
122 }
123
OnHeaderListStart()124 void HpackDecoderAdapter::ListenerAdapter::OnHeaderListStart() {
125 QUICHE_DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeaderListStart";
126 total_hpack_bytes_ = 0;
127 total_uncompressed_bytes_ = 0;
128 handler_->OnHeaderBlockStart();
129 }
130
OnHeader(absl::string_view name,absl::string_view value)131 void HpackDecoderAdapter::ListenerAdapter::OnHeader(absl::string_view name,
132 absl::string_view value) {
133 QUICHE_DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeader:\n name: "
134 << name << "\n value: " << value;
135 total_uncompressed_bytes_ += name.size() + value.size();
136 handler_->OnHeader(name, value);
137 }
138
OnHeaderListEnd()139 void HpackDecoderAdapter::ListenerAdapter::OnHeaderListEnd() {
140 QUICHE_DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeaderListEnd";
141 handler_->OnHeaderBlockEnd(total_uncompressed_bytes_, total_hpack_bytes_);
142 handler_ = &no_op_handler_;
143 }
144
OnHeaderErrorDetected(absl::string_view error_message)145 void HpackDecoderAdapter::ListenerAdapter::OnHeaderErrorDetected(
146 absl::string_view error_message) {
147 QUICHE_VLOG(1) << error_message;
148 }
149
150 } // namespace spdy
151