| // 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_estimate_memory_usage.h" | |
| #include "http2/platform/api/http2_flag_utils.h" | |
| #include "http2/platform/api/http2_flags.h" | |
| #include "http2/platform/api/http2_logging.h" | |
| #include "http2/platform/api/http2_macros.h" | |
| #include "http2/platform/api/http2_string_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) { | |
| listener_ = HTTP2_DIE_IF_NULL(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(); | |
| } | |
| size_t HpackWholeEntryBuffer::EstimateMemoryUsage() const { | |
| return Http2EstimateMemoryUsage(name_) + Http2EstimateMemoryUsage(value_); | |
| } | |
| 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" | |
| << Http2HexDump(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" | |
| << Http2HexDump(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 |