blob: e546e23ede5c9e8bb318502f9d577560ed543697 [file] [log] [blame]
// 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;
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));
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";
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