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