summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables.cc
blob: 9f50ec784908593f7c946754396c0b37964d8644 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// 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_decoder_tables.h"

#include "absl/strings/str_cat.h"
#include "http2/hpack/http2_hpack_constants.h"
#include "http2/platform/api/http2_logging.h"

namespace http2 {
namespace {

std::vector<HpackStringPair>* MakeStaticTable() {
  auto* ptr = new std::vector<HpackStringPair>();
  ptr->reserve(kFirstDynamicTableIndex);
  ptr->emplace_back("", "");

#define STATIC_TABLE_ENTRY(name, value, index)               \
  QUICHE_DCHECK_EQ(ptr->size(), static_cast<size_t>(index)); \
  ptr->emplace_back(name, value)

#include "http2/hpack/hpack_static_table_entries.inc"

#undef STATIC_TABLE_ENTRY

  return ptr;
}

const std::vector<HpackStringPair>* GetStaticTable() {
  static const std::vector<HpackStringPair>* const g_static_table =
      MakeStaticTable();
  return g_static_table;
}

}  // namespace

HpackStringPair::HpackStringPair(std::string name, std::string value)
    : name(std::move(name)), value(std::move(value)) {
  HTTP2_DVLOG(3) << DebugString() << " ctor";
}

HpackStringPair::~HpackStringPair() {
  HTTP2_DVLOG(3) << DebugString() << " dtor";
}

std::string HpackStringPair::DebugString() const {
  return absl::StrCat("HpackStringPair(name=", name, ", value=", value, ")");
}

std::ostream& operator<<(std::ostream& os, const HpackStringPair& p) {
  os << p.DebugString();
  return os;
}

HpackDecoderStaticTable::HpackDecoderStaticTable(
    const std::vector<HpackStringPair>* table)
    : table_(table) {}

HpackDecoderStaticTable::HpackDecoderStaticTable() : table_(GetStaticTable()) {}

const HpackStringPair* HpackDecoderStaticTable::Lookup(size_t index) const {
  if (0 < index && index < kFirstDynamicTableIndex) {
    return &((*table_)[index]);
  }
  return nullptr;
}

HpackDecoderDynamicTable::HpackDecoderDynamicTable()
    : insert_count_(kFirstDynamicTableIndex - 1) {}
HpackDecoderDynamicTable::~HpackDecoderDynamicTable() = default;

void HpackDecoderDynamicTable::DynamicTableSizeUpdate(size_t size_limit) {
  HTTP2_DVLOG(3) << "HpackDecoderDynamicTable::DynamicTableSizeUpdate "
                 << size_limit;
  EnsureSizeNoMoreThan(size_limit);
  QUICHE_DCHECK_LE(current_size_, size_limit);
  size_limit_ = size_limit;
}

// TODO(jamessynge): Check somewhere before here that names received from the
// peer are valid (e.g. are lower-case, no whitespace, etc.).
void HpackDecoderDynamicTable::Insert(std::string name, std::string value) {
  HpackStringPair entry(std::move(name), std::move(value));
  size_t entry_size = entry.size();
  HTTP2_DVLOG(2) << "InsertEntry of size=" << entry_size
                 << "\n     name: " << entry.name
                 << "\n    value: " << entry.value;
  if (entry_size > size_limit_) {
    HTTP2_DVLOG(2) << "InsertEntry: entry larger than table, removing "
                   << table_.size() << " entries, of total size "
                   << current_size_ << " bytes.";
    table_.clear();
    current_size_ = 0;
    return;
  }
  ++insert_count_;
  size_t insert_limit = size_limit_ - entry_size;
  EnsureSizeNoMoreThan(insert_limit);
  table_.push_front(entry);
  current_size_ += entry_size;
  HTTP2_DVLOG(2) << "InsertEntry: current_size_=" << current_size_;
  QUICHE_DCHECK_GE(current_size_, entry_size);
  QUICHE_DCHECK_LE(current_size_, size_limit_);
}

const HpackStringPair* HpackDecoderDynamicTable::Lookup(size_t index) const {
  if (index < table_.size()) {
    return &table_[index];
  }
  return nullptr;
}

void HpackDecoderDynamicTable::EnsureSizeNoMoreThan(size_t limit) {
  HTTP2_DVLOG(2) << "EnsureSizeNoMoreThan limit=" << limit
                 << ", current_size_=" << current_size_;
  // Not the most efficient choice, but any easy way to start.
  while (current_size_ > limit) {
    RemoveLastEntry();
  }
  QUICHE_DCHECK_LE(current_size_, limit);
}

void HpackDecoderDynamicTable::RemoveLastEntry() {
  QUICHE_DCHECK(!table_.empty());
  if (!table_.empty()) {
    HTTP2_DVLOG(2) << "RemoveLastEntry current_size_=" << current_size_
                   << ", last entry size=" << table_.back().size();
    QUICHE_DCHECK_GE(current_size_, table_.back().size());
    current_size_ -= table_.back().size();
    table_.pop_back();
    // Empty IFF current_size_ == 0.
    QUICHE_DCHECK_EQ(table_.empty(), current_size_ == 0);
  }
}

HpackDecoderTables::HpackDecoderTables() = default;
HpackDecoderTables::~HpackDecoderTables() = default;

const HpackStringPair* HpackDecoderTables::Lookup(size_t index) const {
  if (index < kFirstDynamicTableIndex) {
    return static_table_.Lookup(index);
  } else {
    return dynamic_table_.Lookup(index - kFirstDynamicTableIndex);
  }
}

}  // namespace http2