Commit 668b150d authored by yasong's avatar yasong Committed by Commit bot

Adds a listener interface to HpackEncoder. Not used in production. Not protected.

This CL lands server change 129028211 by birenroy.

BUG=488484

Review-Url: https://codereview.chromium.org/2237113005
Cr-Commit-Position: refs/heads/master@{#419236}
parent 219c2a7a
...@@ -56,6 +56,9 @@ class HpackEncoder::RepresentationIterator { ...@@ -56,6 +56,9 @@ class HpackEncoder::RepresentationIterator {
namespace { namespace {
// The default header listener.
void NoOpListener(StringPiece /*name*/, StringPiece /*value*/) {}
// The default HPACK indexing policy. // The default HPACK indexing policy.
bool DefaultPolicy(StringPiece name, StringPiece /* value */) { bool DefaultPolicy(StringPiece name, StringPiece /* value */) {
if (name.empty()) { if (name.empty()) {
...@@ -76,6 +79,7 @@ HpackEncoder::HpackEncoder(const HpackHuffmanTable& table) ...@@ -76,6 +79,7 @@ HpackEncoder::HpackEncoder(const HpackHuffmanTable& table)
: output_stream_(), : output_stream_(),
huffman_table_(table), huffman_table_(table),
min_table_size_setting_received_(std::numeric_limits<size_t>::max()), min_table_size_setting_received_(std::numeric_limits<size_t>::max()),
listener_(NoOpListener),
should_index_(DefaultPolicy), should_index_(DefaultPolicy),
allow_huffman_compression_(true), allow_huffman_compression_(true),
should_emit_table_size_(false) {} should_emit_table_size_(false) {}
...@@ -121,6 +125,7 @@ bool HpackEncoder::EncodeHeaderSetWithoutCompression( ...@@ -121,6 +125,7 @@ bool HpackEncoder::EncodeHeaderSetWithoutCompression(
allow_huffman_compression_ = false; allow_huffman_compression_ = false;
MaybeEmitTableSize(); MaybeEmitTableSize();
for (const auto& header : header_set) { for (const auto& header : header_set) {
listener_(header.first, header.second);
// Note that cookies are not crumbled in this case. // Note that cookies are not crumbled in this case.
EmitNonIndexedLiteral(header); EmitNonIndexedLiteral(header);
} }
...@@ -146,6 +151,7 @@ void HpackEncoder::EncodeRepresentations(RepresentationIterator* iter, ...@@ -146,6 +151,7 @@ void HpackEncoder::EncodeRepresentations(RepresentationIterator* iter,
MaybeEmitTableSize(); MaybeEmitTableSize();
while (iter->HasNext()) { while (iter->HasNext()) {
const auto header = iter->Next(); const auto header = iter->Next();
listener_(header.first, header.second);
const HpackEntry* entry = const HpackEntry* entry =
header_table_.GetByNameAndValue(header.first, header.second); header_table_.GetByNameAndValue(header.first, header.second);
if (entry != nullptr) { if (entry != nullptr) {
......
...@@ -37,6 +37,11 @@ class NET_EXPORT_PRIVATE HpackEncoder { ...@@ -37,6 +37,11 @@ class NET_EXPORT_PRIVATE HpackEncoder {
using Representation = std::pair<base::StringPiece, base::StringPiece>; using Representation = std::pair<base::StringPiece, base::StringPiece>;
using Representations = std::vector<Representation>; using Representations = std::vector<Representation>;
// Callers may provide a HeaderListener to be informed of header name-value
// pairs processed by this encoder.
typedef std::function<void(base::StringPiece, base::StringPiece)>
HeaderListener;
// An indexing policy should return true if the provided header name-value // An indexing policy should return true if the provided header name-value
// pair should be inserted into the HPACK dynamic table. // pair should be inserted into the HPACK dynamic table.
using IndexingPolicy = using IndexingPolicy =
...@@ -74,6 +79,10 @@ class NET_EXPORT_PRIVATE HpackEncoder { ...@@ -74,6 +79,10 @@ class NET_EXPORT_PRIVATE HpackEncoder {
// name-value pairs into the dynamic table. // name-value pairs into the dynamic table.
void SetIndexingPolicy(IndexingPolicy policy) { should_index_ = policy; } void SetIndexingPolicy(IndexingPolicy policy) { should_index_ = policy; }
// |listener| will be invoked for each header name-value pair processed by
// this encoder.
void SetHeaderListener(HeaderListener listener) { listener_ = listener; }
void SetHeaderTableDebugVisitor( void SetHeaderTableDebugVisitor(
std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) { std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) {
header_table_.set_debug_visitor(std::move(visitor)); header_table_.set_debug_visitor(std::move(visitor));
...@@ -115,6 +124,7 @@ class NET_EXPORT_PRIVATE HpackEncoder { ...@@ -115,6 +124,7 @@ class NET_EXPORT_PRIVATE HpackEncoder {
const HpackHuffmanTable& huffman_table_; const HpackHuffmanTable& huffman_table_;
size_t min_table_size_setting_received_; size_t min_table_size_setting_received_;
HeaderListener listener_;
IndexingPolicy should_index_; IndexingPolicy should_index_;
bool allow_huffman_compression_; bool allow_huffman_compression_;
bool should_emit_table_size_; bool should_emit_table_size_;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <map> #include <map>
#include <string> #include <string>
#include "net/base/arena.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -14,6 +15,8 @@ namespace net { ...@@ -14,6 +15,8 @@ namespace net {
using base::StringPiece; using base::StringPiece;
using std::string; using std::string;
using std::vector;
using std::pair;
using testing::ElementsAre; using testing::ElementsAre;
namespace test { namespace test {
...@@ -76,6 +79,7 @@ namespace { ...@@ -76,6 +79,7 @@ namespace {
using std::map; using std::map;
using testing::ElementsAre; using testing::ElementsAre;
using testing::Pair;
class HpackEncoderTest : public ::testing::Test { class HpackEncoderTest : public ::testing::Test {
protected: protected:
...@@ -84,7 +88,8 @@ class HpackEncoderTest : public ::testing::Test { ...@@ -84,7 +88,8 @@ class HpackEncoderTest : public ::testing::Test {
HpackEncoderTest() HpackEncoderTest()
: encoder_(ObtainHpackHuffmanTable()), : encoder_(ObtainHpackHuffmanTable()),
peer_(&encoder_), peer_(&encoder_),
static_(peer_.table()->GetByIndex(1)) {} static_(peer_.table()->GetByIndex(1)),
headers_storage_(1024 /* block size */) {}
void SetUp() override { void SetUp() override {
// Populate dynamic entries into the table fixture. For simplicity each // Populate dynamic entries into the table fixture. For simplicity each
...@@ -101,6 +106,14 @@ class HpackEncoderTest : public ::testing::Test { ...@@ -101,6 +106,14 @@ class HpackEncoderTest : public ::testing::Test {
peer_.set_allow_huffman_compression(false); peer_.set_allow_huffman_compression(false);
} }
void SaveHeaders(StringPiece name, StringPiece value) {
StringPiece n(headers_storage_.Memdup(name.data(), name.size()),
name.size());
StringPiece v(headers_storage_.Memdup(value.data(), value.size()),
value.size());
headers_observed_.push_back(make_pair(n, v));
}
void ExpectIndex(size_t index) { void ExpectIndex(size_t index) {
expected_.AppendPrefix(kIndexedOpcode); expected_.AppendPrefix(kIndexedOpcode);
expected_.AppendUint32(index); expected_.AppendUint32(index);
...@@ -155,15 +168,24 @@ class HpackEncoderTest : public ::testing::Test { ...@@ -155,15 +168,24 @@ class HpackEncoderTest : public ::testing::Test {
const HpackEntry* cookie_a_; const HpackEntry* cookie_a_;
const HpackEntry* cookie_c_; const HpackEntry* cookie_c_;
UnsafeArena headers_storage_;
vector<pair<StringPiece, StringPiece>> headers_observed_;
HpackOutputStream expected_; HpackOutputStream expected_;
}; };
TEST_F(HpackEncoderTest, SingleDynamicIndex) { TEST_F(HpackEncoderTest, SingleDynamicIndex) {
encoder_.SetHeaderListener([this](StringPiece name, StringPiece value) {
this->SaveHeaders(name, value);
});
ExpectIndex(IndexOf(key_2_)); ExpectIndex(IndexOf(key_2_));
SpdyHeaderBlock headers; SpdyHeaderBlock headers;
headers[key_2_->name().as_string()] = key_2_->value().as_string(); headers[key_2_->name().as_string()] = key_2_->value().as_string();
CompareWithExpectedEncoding(headers); CompareWithExpectedEncoding(headers);
EXPECT_THAT(headers_observed_,
ElementsAre(Pair(key_2_->name(), key_2_->value())));
} }
TEST_F(HpackEncoderTest, SingleStaticIndex) { TEST_F(HpackEncoderTest, SingleStaticIndex) {
...@@ -268,6 +290,10 @@ TEST_F(HpackEncoderTest, StringsDynamicallySelectHuffmanCoding) { ...@@ -268,6 +290,10 @@ TEST_F(HpackEncoderTest, StringsDynamicallySelectHuffmanCoding) {
} }
TEST_F(HpackEncoderTest, EncodingWithoutCompression) { TEST_F(HpackEncoderTest, EncodingWithoutCompression) {
encoder_.SetHeaderListener([this](StringPiece name, StringPiece value) {
this->SaveHeaders(name, value);
});
// Implementation should internally disable. // Implementation should internally disable.
peer_.set_allow_huffman_compression(true); peer_.set_allow_huffman_compression(true);
...@@ -284,9 +310,18 @@ TEST_F(HpackEncoderTest, EncodingWithoutCompression) { ...@@ -284,9 +310,18 @@ TEST_F(HpackEncoderTest, EncodingWithoutCompression) {
expected_.TakeString(&expected_out); expected_.TakeString(&expected_out);
encoder_.EncodeHeaderSetWithoutCompression(headers, &actual_out); encoder_.EncodeHeaderSetWithoutCompression(headers, &actual_out);
EXPECT_EQ(expected_out, actual_out); EXPECT_EQ(expected_out, actual_out);
EXPECT_THAT(headers_observed_,
ElementsAre(Pair(":path", "/index.html"),
Pair("cookie", "foo=bar; baz=bing"),
Pair("hello", "goodbye")));
} }
TEST_F(HpackEncoderTest, MultipleEncodingPasses) { TEST_F(HpackEncoderTest, MultipleEncodingPasses) {
encoder_.SetHeaderListener([this](StringPiece name, StringPiece value) {
this->SaveHeaders(name, value);
});
// Pass 1. // Pass 1.
{ {
SpdyHeaderBlock headers; SpdyHeaderBlock headers;
...@@ -339,6 +374,19 @@ TEST_F(HpackEncoderTest, MultipleEncodingPasses) { ...@@ -339,6 +374,19 @@ TEST_F(HpackEncoderTest, MultipleEncodingPasses) {
CompareWithExpectedEncoding(headers); CompareWithExpectedEncoding(headers);
} }
// clang-format off
EXPECT_THAT(headers_observed_,
ElementsAre(Pair("key1", "value1"),
Pair("cookie", "a=bb"),
Pair("key2", "value2"),
Pair("cookie", "c=dd"),
Pair("cookie", "e=ff"),
Pair("key2", "value2"),
Pair("cookie", "a=bb"),
Pair("cookie", "b=cc"),
Pair("cookie", "c=dd")));
// clang-format on
} }
TEST_F(HpackEncoderTest, PseudoHeadersFirst) { TEST_F(HpackEncoderTest, PseudoHeadersFirst) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment