xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_decoder_tables.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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_decoder_tables.h"
6 
7 #include "absl/strings/str_cat.h"
8 #include "quiche/http2/hpack/http2_hpack_constants.h"
9 #include "quiche/common/platform/api/quiche_logging.h"
10 
11 namespace http2 {
12 namespace {
13 
MakeStaticTable()14 std::vector<HpackStringPair>* MakeStaticTable() {
15   auto* ptr = new std::vector<HpackStringPair>();
16   ptr->reserve(kFirstDynamicTableIndex);
17   ptr->emplace_back("", "");
18 
19 #define STATIC_TABLE_ENTRY(name, value, index)               \
20   QUICHE_DCHECK_EQ(ptr->size(), static_cast<size_t>(index)); \
21   ptr->emplace_back(name, value)
22 
23 #include "quiche/http2/hpack/hpack_static_table_entries.inc"
24 
25 #undef STATIC_TABLE_ENTRY
26 
27   return ptr;
28 }
29 
GetStaticTable()30 const std::vector<HpackStringPair>* GetStaticTable() {
31   static const std::vector<HpackStringPair>* const g_static_table =
32       MakeStaticTable();
33   return g_static_table;
34 }
35 
36 }  // namespace
37 
HpackStringPair(std::string name,std::string value)38 HpackStringPair::HpackStringPair(std::string name, std::string value)
39     : name(std::move(name)), value(std::move(value)) {
40   QUICHE_DVLOG(3) << DebugString() << " ctor";
41 }
42 
~HpackStringPair()43 HpackStringPair::~HpackStringPair() {
44   QUICHE_DVLOG(3) << DebugString() << " dtor";
45 }
46 
DebugString() const47 std::string HpackStringPair::DebugString() const {
48   return absl::StrCat("HpackStringPair(name=", name, ", value=", value, ")");
49 }
50 
operator <<(std::ostream & os,const HpackStringPair & p)51 std::ostream& operator<<(std::ostream& os, const HpackStringPair& p) {
52   os << p.DebugString();
53   return os;
54 }
55 
HpackDecoderStaticTable(const std::vector<HpackStringPair> * table)56 HpackDecoderStaticTable::HpackDecoderStaticTable(
57     const std::vector<HpackStringPair>* table)
58     : table_(table) {}
59 
HpackDecoderStaticTable()60 HpackDecoderStaticTable::HpackDecoderStaticTable() : table_(GetStaticTable()) {}
61 
Lookup(size_t index) const62 const HpackStringPair* HpackDecoderStaticTable::Lookup(size_t index) const {
63   if (0 < index && index < kFirstDynamicTableIndex) {
64     return &((*table_)[index]);
65   }
66   return nullptr;
67 }
68 
HpackDecoderDynamicTable()69 HpackDecoderDynamicTable::HpackDecoderDynamicTable()
70     : insert_count_(kFirstDynamicTableIndex - 1) {}
71 HpackDecoderDynamicTable::~HpackDecoderDynamicTable() = default;
72 
DynamicTableSizeUpdate(size_t size_limit)73 void HpackDecoderDynamicTable::DynamicTableSizeUpdate(size_t size_limit) {
74   QUICHE_DVLOG(3) << "HpackDecoderDynamicTable::DynamicTableSizeUpdate "
75                   << size_limit;
76   EnsureSizeNoMoreThan(size_limit);
77   QUICHE_DCHECK_LE(current_size_, size_limit);
78   size_limit_ = size_limit;
79 }
80 
81 // TODO(jamessynge): Check somewhere before here that names received from the
82 // peer are valid (e.g. are lower-case, no whitespace, etc.).
Insert(std::string name,std::string value)83 void HpackDecoderDynamicTable::Insert(std::string name, std::string value) {
84   HpackStringPair entry(std::move(name), std::move(value));
85   size_t entry_size = entry.size();
86   QUICHE_DVLOG(2) << "InsertEntry of size=" << entry_size
87                   << "\n     name: " << entry.name
88                   << "\n    value: " << entry.value;
89   if (entry_size > size_limit_) {
90     QUICHE_DVLOG(2) << "InsertEntry: entry larger than table, removing "
91                     << table_.size() << " entries, of total size "
92                     << current_size_ << " bytes.";
93     table_.clear();
94     current_size_ = 0;
95     return;
96   }
97   ++insert_count_;
98   size_t insert_limit = size_limit_ - entry_size;
99   EnsureSizeNoMoreThan(insert_limit);
100   table_.push_front(entry);
101   current_size_ += entry_size;
102   QUICHE_DVLOG(2) << "InsertEntry: current_size_=" << current_size_;
103   QUICHE_DCHECK_GE(current_size_, entry_size);
104   QUICHE_DCHECK_LE(current_size_, size_limit_);
105 }
106 
Lookup(size_t index) const107 const HpackStringPair* HpackDecoderDynamicTable::Lookup(size_t index) const {
108   if (index < table_.size()) {
109     return &table_[index];
110   }
111   return nullptr;
112 }
113 
EnsureSizeNoMoreThan(size_t limit)114 void HpackDecoderDynamicTable::EnsureSizeNoMoreThan(size_t limit) {
115   QUICHE_DVLOG(2) << "EnsureSizeNoMoreThan limit=" << limit
116                   << ", current_size_=" << current_size_;
117   // Not the most efficient choice, but any easy way to start.
118   while (current_size_ > limit) {
119     RemoveLastEntry();
120   }
121   QUICHE_DCHECK_LE(current_size_, limit);
122 }
123 
RemoveLastEntry()124 void HpackDecoderDynamicTable::RemoveLastEntry() {
125   QUICHE_DCHECK(!table_.empty());
126   if (!table_.empty()) {
127     QUICHE_DVLOG(2) << "RemoveLastEntry current_size_=" << current_size_
128                     << ", last entry size=" << table_.back().size();
129     QUICHE_DCHECK_GE(current_size_, table_.back().size());
130     current_size_ -= table_.back().size();
131     table_.pop_back();
132     // Empty IFF current_size_ == 0.
133     QUICHE_DCHECK_EQ(table_.empty(), current_size_ == 0);
134   }
135 }
136 
137 HpackDecoderTables::HpackDecoderTables() = default;
138 HpackDecoderTables::~HpackDecoderTables() = default;
139 
Lookup(size_t index) const140 const HpackStringPair* HpackDecoderTables::Lookup(size_t index) const {
141   if (index < kFirstDynamicTableIndex) {
142     return static_table_.Lookup(index);
143   } else {
144     return dynamic_table_.Lookup(index - kFirstDynamicTableIndex);
145   }
146 }
147 
148 }  // namespace http2
149