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