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 QUICHE_DVLOG(1) << "Value length (" << len << ") of ["
93 << name_.GetStringIfComplete()
94 << "] is longer than permitted ("
95 << max_string_size_bytes_ << ")";
96
97 ReportError(HpackDecodingError::kValueTooLong);
98 QUICHE_CODE_COUNT_N(decompress_failure_3, 21, 23);
99 return;
100 }
101 value_.OnStart(huffman_encoded, len);
102 }
103 }
104
OnValueData(const char * data,size_t len)105 void HpackWholeEntryBuffer::OnValueData(const char* data, size_t len) {
106 QUICHE_DVLOG(2) << "HpackWholeEntryBuffer::OnValueData: len=" << len
107 << " data:\n"
108 << quiche::QuicheTextUtils::HexDump(
109 absl::string_view(data, len));
110 if (!error_detected_ && !value_.OnData(data, len)) {
111 ReportError(HpackDecodingError::kValueHuffmanError);
112 QUICHE_CODE_COUNT_N(decompress_failure_3, 22, 23);
113 }
114 }
115
OnValueEnd()116 void HpackWholeEntryBuffer::OnValueEnd() {
117 QUICHE_DVLOG(2) << "HpackWholeEntryBuffer::OnValueEnd";
118 if (error_detected_) {
119 return;
120 }
121 if (!value_.OnEnd()) {
122 ReportError(HpackDecodingError::kValueHuffmanError);
123 QUICHE_CODE_COUNT_N(decompress_failure_3, 23, 23);
124 return;
125 }
126 if (maybe_name_index_ == 0) {
127 listener_->OnLiteralNameAndValue(entry_type_, &name_, &value_);
128 name_.Reset();
129 } else {
130 listener_->OnNameIndexAndLiteralValue(entry_type_, maybe_name_index_,
131 &value_);
132 }
133 value_.Reset();
134 }
135
OnDynamicTableSizeUpdate(size_t size)136 void HpackWholeEntryBuffer::OnDynamicTableSizeUpdate(size_t size) {
137 QUICHE_DVLOG(2) << "HpackWholeEntryBuffer::OnDynamicTableSizeUpdate: size="
138 << size;
139 listener_->OnDynamicTableSizeUpdate(size);
140 }
141
ReportError(HpackDecodingError error)142 void HpackWholeEntryBuffer::ReportError(HpackDecodingError error) {
143 if (!error_detected_) {
144 QUICHE_DVLOG(1) << "HpackWholeEntryBuffer::ReportError: "
145 << HpackDecodingErrorToString(error);
146 error_detected_ = true;
147 listener_->OnHpackDecodeError(error);
148 listener_ = HpackWholeEntryNoOpListener::NoOpListener();
149 }
150 }
151
152 } // namespace http2
153