• 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_whole_entry_buffer.h"
6 
7 #include "absl/strings/str_cat.h"
8 #include "quiche/common/platform/api/quiche_flag_utils.h"
9 #include "quiche/common/platform/api/quiche_logging.h"
10 #include "quiche/common/quiche_text_utils.h"
11 
12 namespace http2 {
13 
HpackWholeEntryBuffer(HpackWholeEntryListener * listener,size_t max_string_size_bytes)14 HpackWholeEntryBuffer::HpackWholeEntryBuffer(HpackWholeEntryListener* listener,
15                                              size_t max_string_size_bytes)
16     : max_string_size_bytes_(max_string_size_bytes) {
17   set_listener(listener);
18 }
19 HpackWholeEntryBuffer::~HpackWholeEntryBuffer() = default;
20 
set_listener(HpackWholeEntryListener * listener)21 void HpackWholeEntryBuffer::set_listener(HpackWholeEntryListener* listener) {
22   QUICHE_CHECK(listener);
23   listener_ = listener;
24 }
25 
set_max_string_size_bytes(size_t max_string_size_bytes)26 void HpackWholeEntryBuffer::set_max_string_size_bytes(
27     size_t max_string_size_bytes) {
28   max_string_size_bytes_ = max_string_size_bytes;
29 }
30 
BufferStringsIfUnbuffered()31 void HpackWholeEntryBuffer::BufferStringsIfUnbuffered() {
32   name_.BufferStringIfUnbuffered();
33   value_.BufferStringIfUnbuffered();
34 }
35 
OnIndexedHeader(size_t index)36 void HpackWholeEntryBuffer::OnIndexedHeader(size_t index) {
37   QUICHE_DVLOG(2) << "HpackWholeEntryBuffer::OnIndexedHeader: index=" << index;
38   listener_->OnIndexedHeader(index);
39 }
40 
OnStartLiteralHeader(HpackEntryType entry_type,size_t maybe_name_index)41 void HpackWholeEntryBuffer::OnStartLiteralHeader(HpackEntryType entry_type,
42                                                  size_t maybe_name_index) {
43   QUICHE_DVLOG(2) << "HpackWholeEntryBuffer::OnStartLiteralHeader: entry_type="
44                   << entry_type << ",  maybe_name_index=" << maybe_name_index;
45   entry_type_ = entry_type;
46   maybe_name_index_ = maybe_name_index;
47 }
48 
OnNameStart(bool huffman_encoded,size_t len)49 void HpackWholeEntryBuffer::OnNameStart(bool huffman_encoded, size_t len) {
50   QUICHE_DVLOG(2) << "HpackWholeEntryBuffer::OnNameStart: huffman_encoded="
51                   << (huffman_encoded ? "true" : "false") << ",  len=" << len;
52   QUICHE_DCHECK_EQ(maybe_name_index_, 0u);
53   if (!error_detected_) {
54     if (len > max_string_size_bytes_) {
55       QUICHE_DVLOG(1) << "Name length (" << len
56                       << ") is longer than permitted ("
57                       << max_string_size_bytes_ << ")";
58       ReportError(HpackDecodingError::kNameTooLong, "");
59       QUICHE_CODE_COUNT_N(decompress_failure_3, 18, 23);
60       return;
61     }
62     name_.OnStart(huffman_encoded, len);
63   }
64 }
65 
OnNameData(const char * data,size_t len)66 void HpackWholeEntryBuffer::OnNameData(const char* data, size_t len) {
67   QUICHE_DVLOG(2) << "HpackWholeEntryBuffer::OnNameData: len=" << len
68                   << " data:\n"
69                   << quiche::QuicheTextUtils::HexDump(
70                          absl::string_view(data, len));
71   QUICHE_DCHECK_EQ(maybe_name_index_, 0u);
72   if (!error_detected_ && !name_.OnData(data, len)) {
73     ReportError(HpackDecodingError::kNameHuffmanError, "");
74     QUICHE_CODE_COUNT_N(decompress_failure_3, 19, 23);
75   }
76 }
77 
OnNameEnd()78 void HpackWholeEntryBuffer::OnNameEnd() {
79   QUICHE_DVLOG(2) << "HpackWholeEntryBuffer::OnNameEnd";
80   QUICHE_DCHECK_EQ(maybe_name_index_, 0u);
81   if (!error_detected_ && !name_.OnEnd()) {
82     ReportError(HpackDecodingError::kNameHuffmanError, "");
83     QUICHE_CODE_COUNT_N(decompress_failure_3, 20, 23);
84   }
85 }
86 
OnValueStart(bool huffman_encoded,size_t len)87 void HpackWholeEntryBuffer::OnValueStart(bool huffman_encoded, size_t len) {
88   QUICHE_DVLOG(2) << "HpackWholeEntryBuffer::OnValueStart: huffman_encoded="
89                   << (huffman_encoded ? "true" : "false") << ",  len=" << len;
90   if (!error_detected_) {
91     if (len > max_string_size_bytes_) {
92       std::string detailed_error = absl::StrCat(
93           "Value length (", len, ") of [", name_.GetStringIfComplete(),
94           "] is longer than permitted (", max_string_size_bytes_, ")");
95       QUICHE_DVLOG(1) << detailed_error;
96       ReportError(HpackDecodingError::kValueTooLong, detailed_error);
97       QUICHE_CODE_COUNT_N(decompress_failure_3, 21, 23);
98       return;
99     }
100     value_.OnStart(huffman_encoded, len);
101   }
102 }
103 
OnValueData(const char * data,size_t len)104 void HpackWholeEntryBuffer::OnValueData(const char* data, size_t len) {
105   QUICHE_DVLOG(2) << "HpackWholeEntryBuffer::OnValueData: len=" << len
106                   << " data:\n"
107                   << quiche::QuicheTextUtils::HexDump(
108                          absl::string_view(data, len));
109   if (!error_detected_ && !value_.OnData(data, len)) {
110     ReportError(HpackDecodingError::kValueHuffmanError, "");
111     QUICHE_CODE_COUNT_N(decompress_failure_3, 22, 23);
112   }
113 }
114 
OnValueEnd()115 void HpackWholeEntryBuffer::OnValueEnd() {
116   QUICHE_DVLOG(2) << "HpackWholeEntryBuffer::OnValueEnd";
117   if (error_detected_) {
118     return;
119   }
120   if (!value_.OnEnd()) {
121     ReportError(HpackDecodingError::kValueHuffmanError, "");
122     QUICHE_CODE_COUNT_N(decompress_failure_3, 23, 23);
123     return;
124   }
125   if (maybe_name_index_ == 0) {
126     listener_->OnLiteralNameAndValue(entry_type_, &name_, &value_);
127     name_.Reset();
128   } else {
129     listener_->OnNameIndexAndLiteralValue(entry_type_, maybe_name_index_,
130                                           &value_);
131   }
132   value_.Reset();
133 }
134 
OnDynamicTableSizeUpdate(size_t size)135 void HpackWholeEntryBuffer::OnDynamicTableSizeUpdate(size_t size) {
136   QUICHE_DVLOG(2) << "HpackWholeEntryBuffer::OnDynamicTableSizeUpdate: size="
137                   << size;
138   listener_->OnDynamicTableSizeUpdate(size);
139 }
140 
ReportError(HpackDecodingError error,std::string detailed_error)141 void HpackWholeEntryBuffer::ReportError(HpackDecodingError error,
142                                         std::string detailed_error) {
143   if (!error_detected_) {
144     QUICHE_DVLOG(1) << "HpackWholeEntryBuffer::ReportError: "
145                     << HpackDecodingErrorToString(error);
146     error_detected_ = true;
147     listener_->OnHpackDecodeError(error, detailed_error);
148     listener_ = HpackWholeEntryNoOpListener::NoOpListener();
149   }
150 }
151 
152 }  // namespace http2
153