| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "http2/hpack/decoder/hpack_whole_entry_buffer.h" |
| |
| #include "absl/strings/str_cat.h" |
| #include "http2/platform/api/http2_flag_utils.h" |
| #include "http2/platform/api/http2_flags.h" |
| #include "http2/platform/api/http2_logging.h" |
| #include "common/platform/api/quiche_logging.h" |
| #include "common/quiche_text_utils.h" |
| |
| namespace http2 { |
| |
| HpackWholeEntryBuffer::HpackWholeEntryBuffer(HpackWholeEntryListener* listener, |
| size_t max_string_size_bytes) |
| : max_string_size_bytes_(max_string_size_bytes) { |
| set_listener(listener); |
| } |
| HpackWholeEntryBuffer::~HpackWholeEntryBuffer() = default; |
| |
| void HpackWholeEntryBuffer::set_listener(HpackWholeEntryListener* listener) { |
| QUICHE_CHECK(listener); |
| listener_ = listener; |
| } |
| |
| void HpackWholeEntryBuffer::set_max_string_size_bytes( |
| size_t max_string_size_bytes) { |
| max_string_size_bytes_ = max_string_size_bytes; |
| } |
| |
| void HpackWholeEntryBuffer::BufferStringsIfUnbuffered() { |
| name_.BufferStringIfUnbuffered(); |
| value_.BufferStringIfUnbuffered(); |
| } |
| |
| void HpackWholeEntryBuffer::OnIndexedHeader(size_t index) { |
| HTTP2_DVLOG(2) << "HpackWholeEntryBuffer::OnIndexedHeader: index=" << index; |
| listener_->OnIndexedHeader(index); |
| } |
| |
| void HpackWholeEntryBuffer::OnStartLiteralHeader(HpackEntryType entry_type, |
| size_t maybe_name_index) { |
| HTTP2_DVLOG(2) << "HpackWholeEntryBuffer::OnStartLiteralHeader: entry_type=" |
| << entry_type << ", maybe_name_index=" << maybe_name_index; |
| entry_type_ = entry_type; |
| maybe_name_index_ = maybe_name_index; |
| } |
| |
| void HpackWholeEntryBuffer::OnNameStart(bool huffman_encoded, size_t len) { |
| HTTP2_DVLOG(2) << "HpackWholeEntryBuffer::OnNameStart: huffman_encoded=" |
| << (huffman_encoded ? "true" : "false") << ", len=" << len; |
| QUICHE_DCHECK_EQ(maybe_name_index_, 0u); |
| if (!error_detected_) { |
| if (len > max_string_size_bytes_) { |
| HTTP2_DVLOG(1) << "Name length (" << len << ") is longer than permitted (" |
| << max_string_size_bytes_ << ")"; |
| ReportError(HpackDecodingError::kNameTooLong, ""); |
| HTTP2_CODE_COUNT_N(decompress_failure_3, 18, 23); |
| return; |
| } |
| name_.OnStart(huffman_encoded, len); |
| } |
| } |
| |
| void HpackWholeEntryBuffer::OnNameData(const char* data, size_t len) { |
| HTTP2_DVLOG(2) << "HpackWholeEntryBuffer::OnNameData: len=" << len |
| << " data:\n" |
| << quiche::QuicheTextUtils::HexDump( |
| absl::string_view(data, len)); |
| QUICHE_DCHECK_EQ(maybe_name_index_, 0u); |
| if (!error_detected_ && !name_.OnData(data, len)) { |
| ReportError(HpackDecodingError::kNameHuffmanError, ""); |
| HTTP2_CODE_COUNT_N(decompress_failure_3, 19, 23); |
| } |
| } |
| |
| void HpackWholeEntryBuffer::OnNameEnd() { |
| HTTP2_DVLOG(2) << "HpackWholeEntryBuffer::OnNameEnd"; |
| QUICHE_DCHECK_EQ(maybe_name_index_, 0u); |
| if (!error_detected_ && !name_.OnEnd()) { |
| ReportError(HpackDecodingError::kNameHuffmanError, ""); |
| HTTP2_CODE_COUNT_N(decompress_failure_3, 20, 23); |
| } |
| } |
| |
| void HpackWholeEntryBuffer::OnValueStart(bool huffman_encoded, size_t len) { |
| HTTP2_DVLOG(2) << "HpackWholeEntryBuffer::OnValueStart: huffman_encoded=" |
| << (huffman_encoded ? "true" : "false") << ", len=" << len; |
| if (!error_detected_) { |
| if (len > max_string_size_bytes_) { |
| std::string detailed_error = absl::StrCat( |
| "Value length (", len, ") of [", name_.GetStringIfComplete(), |
| "] is longer than permitted (", max_string_size_bytes_, ")"); |
| HTTP2_DVLOG(1) << detailed_error; |
| ReportError(HpackDecodingError::kValueTooLong, detailed_error); |
| HTTP2_CODE_COUNT_N(decompress_failure_3, 21, 23); |
| return; |
| } |
| value_.OnStart(huffman_encoded, len); |
| } |
| } |
| |
| void HpackWholeEntryBuffer::OnValueData(const char* data, size_t len) { |
| HTTP2_DVLOG(2) << "HpackWholeEntryBuffer::OnValueData: len=" << len |
| << " data:\n" |
| << quiche::QuicheTextUtils::HexDump( |
| absl::string_view(data, len)); |
| if (!error_detected_ && !value_.OnData(data, len)) { |
| ReportError(HpackDecodingError::kValueHuffmanError, ""); |
| HTTP2_CODE_COUNT_N(decompress_failure_3, 22, 23); |
| } |
| } |
| |
| void HpackWholeEntryBuffer::OnValueEnd() { |
| HTTP2_DVLOG(2) << "HpackWholeEntryBuffer::OnValueEnd"; |
| if (error_detected_) { |
| return; |
| } |
| if (!value_.OnEnd()) { |
| ReportError(HpackDecodingError::kValueHuffmanError, ""); |
| HTTP2_CODE_COUNT_N(decompress_failure_3, 23, 23); |
| return; |
| } |
| if (maybe_name_index_ == 0) { |
| listener_->OnLiteralNameAndValue(entry_type_, &name_, &value_); |
| name_.Reset(); |
| } else { |
| listener_->OnNameIndexAndLiteralValue(entry_type_, maybe_name_index_, |
| &value_); |
| } |
| value_.Reset(); |
| } |
| |
| void HpackWholeEntryBuffer::OnDynamicTableSizeUpdate(size_t size) { |
| HTTP2_DVLOG(2) << "HpackWholeEntryBuffer::OnDynamicTableSizeUpdate: size=" |
| << size; |
| listener_->OnDynamicTableSizeUpdate(size); |
| } |
| |
| void HpackWholeEntryBuffer::ReportError(HpackDecodingError error, |
| std::string detailed_error) { |
| if (!error_detected_) { |
| HTTP2_DVLOG(1) << "HpackWholeEntryBuffer::ReportError: " |
| << HpackDecodingErrorToString(error); |
| error_detected_ = true; |
| listener_->OnHpackDecodeError(error, detailed_error); |
| listener_ = HpackWholeEntryNoOpListener::NoOpListener(); |
| } |
| } |
| |
| } // namespace http2 |