Return index instead of HpackEntry* from HpackHeaderTable::GetByName*().
This allows HpackHeaderTable::IndexOf() to be removed. It will also allow for
internal storage to be changed in a later CL.
PiperOrigin-RevId: 363217057
Change-Id: I87430171b6b2946bda8e7ee630100caaf0dc59b9
diff --git a/spdy/core/hpack/hpack_encoder.cc b/spdy/core/hpack/hpack_encoder.cc
index 4aecc73..42777a4 100644
--- a/spdy/core/hpack/hpack_encoder.cc
+++ b/spdy/core/hpack/hpack_encoder.cc
@@ -137,10 +137,10 @@
const auto header = iter->Next();
listener_(header.first, header.second);
if (enable_compression_) {
- const HpackEntry* entry =
+ size_t index =
header_table_.GetByNameAndValue(header.first, header.second);
- if (entry != nullptr) {
- EmitIndex(entry);
+ if (index != kHpackEntryNotFound) {
+ EmitIndex(index);
} else if (should_index_(header.first, header.second)) {
EmitIndexedLiteral(header);
} else {
@@ -154,10 +154,10 @@
output_stream_.TakeString(output);
}
-void HpackEncoder::EmitIndex(const HpackEntry* entry) {
- SPDY_DVLOG(2) << "Emitting index " << header_table_.IndexOf(entry);
+void HpackEncoder::EmitIndex(size_t index) {
+ SPDY_DVLOG(2) << "Emitting index " << index;
output_stream_.AppendPrefix(kIndexedOpcode);
- output_stream_.AppendUint32(header_table_.IndexOf(entry));
+ output_stream_.AppendUint32(index);
}
void HpackEncoder::EmitIndexedLiteral(const Representation& representation) {
@@ -173,9 +173,9 @@
SPDY_DVLOG(2) << "Emitting nonindexed literal: (" << representation.first
<< ", " << representation.second << ")";
output_stream_.AppendPrefix(kLiteralNoIndexOpcode);
- const HpackEntry* name_entry = header_table_.GetByName(representation.first);
- if (enable_compression && name_entry != nullptr) {
- output_stream_.AppendUint32(header_table_.IndexOf(name_entry));
+ size_t name_index = header_table_.GetByName(representation.first);
+ if (enable_compression && name_index != kHpackEntryNotFound) {
+ output_stream_.AppendUint32(name_index);
} else {
output_stream_.AppendUint32(0);
EmitString(representation.first);
@@ -184,9 +184,9 @@
}
void HpackEncoder::EmitLiteral(const Representation& representation) {
- const HpackEntry* name_entry = header_table_.GetByName(representation.first);
- if (name_entry != nullptr) {
- output_stream_.AppendUint32(header_table_.IndexOf(name_entry));
+ size_t name_index = header_table_.GetByName(representation.first);
+ if (name_index != kHpackEntryNotFound) {
+ output_stream_.AppendUint32(name_index);
} else {
output_stream_.AppendUint32(0);
EmitString(representation.first);
@@ -357,10 +357,10 @@
const Representation header = header_it_->Next();
encoder_->listener_(header.first, header.second);
if (enable_compression) {
- const HpackEntry* entry = encoder_->header_table_.GetByNameAndValue(
- header.first, header.second);
- if (entry != nullptr) {
- encoder_->EmitIndex(entry);
+ size_t index = encoder_->header_table_.GetByNameAndValue(header.first,
+ header.second);
+ if (index != kHpackEntryNotFound) {
+ encoder_->EmitIndex(index);
} else if (encoder_->should_index_(header.first, header.second)) {
encoder_->EmitIndexedLiteral(header);
} else {
diff --git a/spdy/core/hpack/hpack_encoder.h b/spdy/core/hpack/hpack_encoder.h
index 70fade8..d85b98e 100644
--- a/spdy/core/hpack/hpack_encoder.h
+++ b/spdy/core/hpack/hpack_encoder.h
@@ -108,7 +108,7 @@
void EncodeRepresentations(RepresentationIterator* iter, std::string* output);
// Emits a static/dynamic indexed representation (Section 7.1).
- void EmitIndex(const HpackEntry* entry);
+ void EmitIndex(size_t index);
// Emits a literal representation (Section 7.2).
void EmitIndexedLiteral(const Representation& representation);
diff --git a/spdy/core/hpack/hpack_encoder_test.cc b/spdy/core/hpack/hpack_encoder_test.cc
index 1498312..3f0fbaa 100644
--- a/spdy/core/hpack/hpack_encoder_test.cc
+++ b/spdy/core/hpack/hpack_encoder_test.cc
@@ -166,12 +166,6 @@
expected_.AppendPrefix(kIndexedOpcode);
expected_.AppendUint32(index);
}
- void ExpectIndexedLiteral(const HpackEntry* key_entry,
- absl::string_view value) {
- expected_.AppendPrefix(kLiteralIncrementalIndexOpcode);
- expected_.AppendUint32(peer_.table()->IndexOf(key_entry));
- ExpectString(&expected_, value);
- }
void ExpectIndexedLiteral(size_t key_index, absl::string_view value) {
expected_.AppendPrefix(kLiteralIncrementalIndexOpcode);
expected_.AppendUint32(key_index);
@@ -190,10 +184,10 @@
ExpectString(&expected_, name);
ExpectString(&expected_, value);
}
- void ExpectNonIndexedLiteralWithNameIndex(const HpackEntry* key_entry,
+ void ExpectNonIndexedLiteralWithNameIndex(size_t key_index,
absl::string_view value) {
expected_.AppendPrefix(kLiteralNoIndexOpcode);
- expected_.AppendUint32(peer_.table()->IndexOf(key_entry));
+ expected_.AppendUint32(key_index);
ExpectString(&expected_, value);
}
void ExpectString(HpackOutputStream* stream, absl::string_view str) {
diff --git a/spdy/core/hpack/hpack_entry_test.cc b/spdy/core/hpack/hpack_entry_test.cc
index dfb4888..ecd5565 100644
--- a/spdy/core/hpack/hpack_entry_test.cc
+++ b/spdy/core/hpack/hpack_entry_test.cc
@@ -30,14 +30,6 @@
}
void DropEntry() { --table_size_; }
- size_t IndexOf(const HpackEntry& entry) const {
- if (entry.IsStatic()) {
- return 1 + entry.InsertionIndex() + table_size_;
- } else {
- return total_insertions_ - entry.InsertionIndex();
- }
- }
-
size_t Size() {
return name_.size() + value_.size() + kHpackEntrySizeOverhead;
}
@@ -56,7 +48,6 @@
EXPECT_EQ(name_, entry.name());
EXPECT_EQ(value_, entry.value());
EXPECT_TRUE(entry.IsStatic());
- EXPECT_EQ(1u, IndexOf(entry));
EXPECT_EQ(Size(), entry.Size());
}
@@ -66,7 +57,6 @@
EXPECT_EQ(name_, entry.name());
EXPECT_EQ(value_, entry.value());
EXPECT_FALSE(entry.IsStatic());
- EXPECT_EQ(1u, IndexOf(entry));
EXPECT_EQ(Size(), entry.Size());
}
@@ -76,7 +66,6 @@
EXPECT_EQ(name_, entry.name());
EXPECT_EQ(value_, entry.value());
EXPECT_FALSE(entry.IsStatic());
- EXPECT_EQ(0u, IndexOf(entry));
EXPECT_EQ(Size(), entry.Size());
}
@@ -88,35 +77,6 @@
EXPECT_EQ(kHpackEntrySizeOverhead, entry.Size());
}
-TEST_F(HpackEntryTest, IndexUpdate) {
- HpackEntry static1(StaticEntry());
- HpackEntry static2(StaticEntry());
-
- EXPECT_EQ(1u, IndexOf(static1));
- EXPECT_EQ(2u, IndexOf(static2));
-
- HpackEntry dynamic1(DynamicEntry());
- HpackEntry dynamic2(DynamicEntry());
-
- EXPECT_EQ(1u, IndexOf(dynamic2));
- EXPECT_EQ(2u, IndexOf(dynamic1));
- EXPECT_EQ(3u, IndexOf(static1));
- EXPECT_EQ(4u, IndexOf(static2));
-
- DropEntry(); // Drops |dynamic1|.
-
- EXPECT_EQ(1u, IndexOf(dynamic2));
- EXPECT_EQ(2u, IndexOf(static1));
- EXPECT_EQ(3u, IndexOf(static2));
-
- HpackEntry dynamic3(DynamicEntry());
-
- EXPECT_EQ(1u, IndexOf(dynamic3));
- EXPECT_EQ(2u, IndexOf(dynamic2));
- EXPECT_EQ(3u, IndexOf(static1));
- EXPECT_EQ(4u, IndexOf(static2));
-}
-
} // namespace
} // namespace spdy
diff --git a/spdy/core/hpack/hpack_header_table.cc b/spdy/core/hpack/hpack_header_table.cc
index e720bab..e8e469b 100644
--- a/spdy/core/hpack/hpack_header_table.cc
+++ b/spdy/core/hpack/hpack_header_table.cc
@@ -57,48 +57,39 @@
return nullptr;
}
-const HpackEntry* HpackHeaderTable::GetByName(absl::string_view name) {
+size_t HpackHeaderTable::GetByName(absl::string_view name) {
{
auto it = static_name_index_.find(name);
if (it != static_name_index_.end()) {
- return it->second;
+ return 1 + it->second->InsertionIndex();
}
}
{
NameToEntryMap::const_iterator it = dynamic_name_index_.find(name);
if (it != dynamic_name_index_.end()) {
- return it->second;
+ return total_insertions_ - it->second->InsertionIndex() +
+ kStaticTableSize;
}
}
- return nullptr;
+ return kHpackEntryNotFound;
}
-const HpackEntry* HpackHeaderTable::GetByNameAndValue(absl::string_view name,
- absl::string_view value) {
+size_t HpackHeaderTable::GetByNameAndValue(absl::string_view name,
+ absl::string_view value) {
HpackEntry query(name, value);
{
auto it = static_index_.find(&query);
if (it != static_index_.end()) {
- return *it;
+ return 1 + (*it)->InsertionIndex();
}
}
{
auto it = dynamic_index_.find(&query);
if (it != dynamic_index_.end()) {
- return *it;
+ return total_insertions_ - (*it)->InsertionIndex() + kStaticTableSize;
}
}
- return nullptr;
-}
-
-size_t HpackHeaderTable::IndexOf(const HpackEntry* entry) const {
- if (entry->IsLookup()) {
- return 0;
- } else if (entry->IsStatic()) {
- return 1 + entry->InsertionIndex();
- } else {
- return total_insertions_ - entry->InsertionIndex() + kStaticTableSize;
- }
+ return kHpackEntryNotFound;
}
void HpackHeaderTable::SetMaxSize(size_t max_size) {
diff --git a/spdy/core/hpack/hpack_header_table.h b/spdy/core/hpack/hpack_header_table.h
index d522aaa..88a656f 100644
--- a/spdy/core/hpack/hpack_header_table.h
+++ b/spdy/core/hpack/hpack_header_table.h
@@ -25,6 +25,11 @@
class HpackHeaderTablePeer;
} // namespace test
+// Return value of GetByName() and GetByNameAndValue() if matching entry is not
+// found. This value is never used in HPACK for indexing entries, see
+// https://httpwg.org/specs/rfc7541.html#index.address.space.
+constexpr size_t kHpackEntryNotFound = 0;
+
// A data structure for the static table (2.3.1) and the dynamic table (2.3.2).
class QUICHE_EXPORT_PRIVATE HpackHeaderTable {
public:
@@ -64,18 +69,20 @@
size_t size() const { return size_; }
size_t max_size() const { return max_size_; }
+ // The HPACK indexing scheme used by GetByIndex(), GetByName(), and
+ // GetByNameAndValue() is defined at
+ // https://httpwg.org/specs/rfc7541.html#index.address.space.
+
// Returns the entry matching the index, or NULL.
const HpackEntry* GetByIndex(size_t index);
- // Returns the lowest-value entry having |name|, or NULL.
- const HpackEntry* GetByName(absl::string_view name);
+ // Returns the index of the lowest-index entry matching |name|,
+ // or kHpackEntryNotFound if no matching entry is found.
+ size_t GetByName(absl::string_view name);
- // Returns the lowest-index matching entry, or NULL.
- const HpackEntry* GetByNameAndValue(absl::string_view name,
- absl::string_view value);
-
- // Returns the index of an entry within this header table.
- size_t IndexOf(const HpackEntry* entry) const;
+ // Returns the index of the lowest-index entry matching |name| and |value|,
+ // or kHpackEntryNotFound if no matching entry is found.
+ size_t GetByNameAndValue(absl::string_view name, absl::string_view value);
// Sets the maximum size of the header table, evicting entries if
// necessary as described in 5.2.
@@ -144,8 +151,8 @@
size_t size_;
size_t max_size_;
- // Total number of table insertions which have occurred. Referenced by
- // IndexOf() for determination of an HpackEntry's table index.
+ // Total number of table insertions which have occurred,
+ // including initial static table insertions.
size_t total_insertions_;
};
diff --git a/spdy/core/hpack/hpack_header_table_test.cc b/spdy/core/hpack/hpack_header_table_test.cc
index 1cef8df..31d64b7 100644
--- a/spdy/core/hpack/hpack_header_table_test.cc
+++ b/spdy/core/hpack/hpack_header_table_test.cc
@@ -13,6 +13,7 @@
#include "common/platform/api/quiche_test.h"
#include "spdy/core/hpack/hpack_constants.h"
#include "spdy/core/hpack/hpack_entry.h"
+#include "spdy/core/hpack/hpack_static_table.h"
namespace spdy {
@@ -114,11 +115,10 @@
for (size_t i = 0; i != entries.size(); ++i) {
// Static table has 61 entries, dynamic entries follow those.
- size_t index = 61 + entries.size() - i;
+ size_t index = kStaticTableSize + entries.size() - i;
const HpackEntry* entry = table_.GetByIndex(index);
EXPECT_EQ(entries[i].name(), entry->name());
EXPECT_EQ(entries[i].value(), entry->value());
- EXPECT_EQ(index, table_.IndexOf(entry));
}
}
@@ -146,16 +146,18 @@
const HpackEntry* entry = &peer_.static_entries()[i];
EXPECT_TRUE(entry->IsStatic());
- EXPECT_EQ(entry, table_.GetByIndex(i + 1));
- EXPECT_EQ(entry, table_.GetByNameAndValue(entry->name(), entry->value()));
+
+ size_t index = i + 1;
+ EXPECT_EQ(entry, table_.GetByIndex(index));
+ EXPECT_EQ(index, table_.GetByNameAndValue(entry->name(), entry->value()));
}
}
TEST_F(HpackHeaderTableTest, BasicDynamicEntryInsertionAndEviction) {
size_t static_count = peer_.total_insertions();
- const HpackEntry* first_static_entry = table_.GetByIndex(1);
- EXPECT_EQ(1u, table_.IndexOf(first_static_entry));
+ const HpackEntry* first_static_entry = table_.GetByIndex(1);
+ EXPECT_EQ(first_static_entry, table_.GetByIndex(1));
const HpackEntry* entry = table_.TryAddEntry("header-key", "Header Value");
EXPECT_EQ("header-key", entry->name());
@@ -169,13 +171,11 @@
EXPECT_EQ(static_count + 1, peer_.total_insertions());
EXPECT_EQ(static_count + 1, peer_.index_size());
- // Index() of entries reflects the insertion.
- EXPECT_EQ(1u, table_.IndexOf(first_static_entry));
- // Static table has 61 entries.
- EXPECT_EQ(62u, table_.IndexOf(entry));
- EXPECT_EQ(first_static_entry, table_.GetByIndex(1));
EXPECT_EQ(entry, table_.GetByIndex(62));
+ // Index of |first_static_entry| does not change.
+ EXPECT_EQ(first_static_entry, table_.GetByIndex(1));
+
// Evict |entry|. Table counts are again updated appropriately.
peer_.Evict(1);
EXPECT_EQ(0u, table_.size());
@@ -184,8 +184,7 @@
EXPECT_EQ(static_count + 1, peer_.total_insertions());
EXPECT_EQ(static_count, peer_.index_size());
- // Index() of |first_static_entry| reflects the eviction.
- EXPECT_EQ(1u, table_.IndexOf(first_static_entry));
+ // Index of |first_static_entry| does not change.
EXPECT_EQ(first_static_entry, table_.GetByIndex(1));
}
@@ -193,10 +192,9 @@
const HpackEntry* first_static_entry = table_.GetByIndex(1);
// Static entries are queryable by name & value.
- EXPECT_EQ(first_static_entry, table_.GetByName(first_static_entry->name()));
- EXPECT_EQ(first_static_entry,
- table_.GetByNameAndValue(first_static_entry->name(),
- first_static_entry->value()));
+ EXPECT_EQ(1u, table_.GetByName(first_static_entry->name()));
+ EXPECT_EQ(1u, table_.GetByNameAndValue(first_static_entry->name(),
+ first_static_entry->value()));
// Create a mix of entries which duplicate names, and names & values of both
// dynamic and static entries.
@@ -221,38 +219,37 @@
EXPECT_EQ(first_static_entry, table_.GetByIndex(1));
// Querying by name returns the most recently added matching entry.
- EXPECT_EQ(entry5, table_.GetByName("key-1"));
- EXPECT_EQ(entry7, table_.GetByName("key-2"));
- EXPECT_EQ(entry2->name(),
- table_.GetByName(first_static_entry->name())->name());
- EXPECT_EQ(nullptr, table_.GetByName("not-present"));
+ EXPECT_EQ(64u, table_.GetByName("key-1"));
+ EXPECT_EQ(62u, table_.GetByName("key-2"));
+ EXPECT_EQ(1u, table_.GetByName(first_static_entry->name()));
+ EXPECT_EQ(kHpackEntryNotFound, table_.GetByName("not-present"));
// Querying by name & value returns the lowest-index matching entry among
// static entries, and the highest-index one among dynamic entries.
- EXPECT_EQ(entry3, table_.GetByNameAndValue("key-1", "Value One"));
- EXPECT_EQ(entry5, table_.GetByNameAndValue("key-1", "Value Two"));
- EXPECT_EQ(entry6, table_.GetByNameAndValue("key-2", "Value Three"));
- EXPECT_EQ(entry7, table_.GetByNameAndValue("key-2", "Value Four"));
- EXPECT_EQ(first_static_entry,
- table_.GetByNameAndValue(first_static_entry->name(),
- first_static_entry->value()));
- EXPECT_EQ(entry2,
+ EXPECT_EQ(66u, table_.GetByNameAndValue("key-1", "Value One"));
+ EXPECT_EQ(64u, table_.GetByNameAndValue("key-1", "Value Two"));
+ EXPECT_EQ(63u, table_.GetByNameAndValue("key-2", "Value Three"));
+ EXPECT_EQ(62u, table_.GetByNameAndValue("key-2", "Value Four"));
+ EXPECT_EQ(1u, table_.GetByNameAndValue(first_static_entry->name(),
+ first_static_entry->value()));
+ EXPECT_EQ(67u,
table_.GetByNameAndValue(first_static_entry->name(), "Value Four"));
- EXPECT_EQ(nullptr, table_.GetByNameAndValue("key-1", "Not Present"));
- EXPECT_EQ(nullptr, table_.GetByNameAndValue("not-present", "Value One"));
+ EXPECT_EQ(kHpackEntryNotFound,
+ table_.GetByNameAndValue("key-1", "Not Present"));
+ EXPECT_EQ(kHpackEntryNotFound,
+ table_.GetByNameAndValue("not-present", "Value One"));
// Evict |entry1|. Queries for its name & value now return the static entry.
// |entry2| remains queryable.
peer_.Evict(1);
- EXPECT_EQ(first_static_entry,
- table_.GetByNameAndValue(first_static_entry->name(),
- first_static_entry->value()));
- EXPECT_EQ(entry2,
+ EXPECT_EQ(1u, table_.GetByNameAndValue(first_static_entry->name(),
+ first_static_entry->value()));
+ EXPECT_EQ(67u,
table_.GetByNameAndValue(first_static_entry->name(), "Value Four"));
// Evict |entry2|. Queries by its name & value are not found.
peer_.Evict(1);
- EXPECT_EQ(nullptr,
+ EXPECT_EQ(kHpackEntryNotFound,
table_.GetByNameAndValue(first_static_entry->name(), "Value Four"));
}
@@ -373,7 +370,6 @@
const HpackEntry* new_entry =
table_.TryAddEntry(long_entry.name(), long_entry.value());
- EXPECT_EQ(62u, table_.IndexOf(new_entry));
EXPECT_EQ(2u, peer_.dynamic_entries().size());
EXPECT_EQ(table_.GetByIndex(63), survivor_entry);
EXPECT_EQ(table_.GetByIndex(62), new_entry);