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 {
namespace {
// The default header listener.
void NoOpListener(StringPiece /*name*/, StringPiece /*value*/) {}
// The default HPACK indexing policy.
bool DefaultPolicy(StringPiece name, StringPiece /* value */) {
if (name.empty()) {
......@@ -76,6 +79,7 @@ HpackEncoder::HpackEncoder(const HpackHuffmanTable& table)
: output_stream_(),
huffman_table_(table),
min_table_size_setting_received_(std::numeric_limits<size_t>::max()),
listener_(NoOpListener),
should_index_(DefaultPolicy),
allow_huffman_compression_(true),
should_emit_table_size_(false) {}
......@@ -121,6 +125,7 @@ bool HpackEncoder::EncodeHeaderSetWithoutCompression(
allow_huffman_compression_ = false;
MaybeEmitTableSize();
for (const auto& header : header_set) {
listener_(header.first, header.second);
// Note that cookies are not crumbled in this case.
EmitNonIndexedLiteral(header);
}
......@@ -146,6 +151,7 @@ void HpackEncoder::EncodeRepresentations(RepresentationIterator* iter,
MaybeEmitTableSize();
while (iter->HasNext()) {
const auto header = iter->Next();
listener_(header.first, header.second);
const HpackEntry* entry =
header_table_.GetByNameAndValue(header.first, header.second);
if (entry != nullptr) {
......
......@@ -37,6 +37,11 @@ class NET_EXPORT_PRIVATE HpackEncoder {
using Representation = std::pair<base::StringPiece, base::StringPiece>;
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
// pair should be inserted into the HPACK dynamic table.
using IndexingPolicy =
......@@ -74,6 +79,10 @@ class NET_EXPORT_PRIVATE HpackEncoder {
// name-value pairs into the dynamic table.
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(
std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) {
header_table_.set_debug_visitor(std::move(visitor));
......@@ -115,6 +124,7 @@ class NET_EXPORT_PRIVATE HpackEncoder {
const HpackHuffmanTable& huffman_table_;
size_t min_table_size_setting_received_;
HeaderListener listener_;
IndexingPolicy should_index_;
bool allow_huffman_compression_;
bool should_emit_table_size_;
......
......@@ -7,6 +7,7 @@
#include <map>
#include <string>
#include "net/base/arena.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -14,6 +15,8 @@ namespace net {
using base::StringPiece;
using std::string;
using std::vector;
using std::pair;
using testing::ElementsAre;
namespace test {
......@@ -76,6 +79,7 @@ namespace {
using std::map;
using testing::ElementsAre;
using testing::Pair;
class HpackEncoderTest : public ::testing::Test {
protected:
......@@ -84,7 +88,8 @@ class HpackEncoderTest : public ::testing::Test {
HpackEncoderTest()
: encoder_(ObtainHpackHuffmanTable()),
peer_(&encoder_),
static_(peer_.table()->GetByIndex(1)) {}
static_(peer_.table()->GetByIndex(1)),
headers_storage_(1024 /* block size */) {}
void SetUp() override {
// Populate dynamic entries into the table fixture. For simplicity each
......@@ -101,6 +106,14 @@ class HpackEncoderTest : public ::testing::Test {
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) {
expected_.AppendPrefix(kIndexedOpcode);
expected_.AppendUint32(index);
......@@ -155,15 +168,24 @@ class HpackEncoderTest : public ::testing::Test {
const HpackEntry* cookie_a_;
const HpackEntry* cookie_c_;
UnsafeArena headers_storage_;
vector<pair<StringPiece, StringPiece>> headers_observed_;
HpackOutputStream expected_;
};
TEST_F(HpackEncoderTest, SingleDynamicIndex) {
encoder_.SetHeaderListener([this](StringPiece name, StringPiece value) {
this->SaveHeaders(name, value);
});
ExpectIndex(IndexOf(key_2_));
SpdyHeaderBlock headers;
headers[key_2_->name().as_string()] = key_2_->value().as_string();
CompareWithExpectedEncoding(headers);
EXPECT_THAT(headers_observed_,
ElementsAre(Pair(key_2_->name(), key_2_->value())));
}
TEST_F(HpackEncoderTest, SingleStaticIndex) {
......@@ -268,6 +290,10 @@ TEST_F(HpackEncoderTest, StringsDynamicallySelectHuffmanCoding) {
}
TEST_F(HpackEncoderTest, EncodingWithoutCompression) {
encoder_.SetHeaderListener([this](StringPiece name, StringPiece value) {
this->SaveHeaders(name, value);
});
// Implementation should internally disable.
peer_.set_allow_huffman_compression(true);
......@@ -284,9 +310,18 @@ TEST_F(HpackEncoderTest, EncodingWithoutCompression) {
expected_.TakeString(&expected_out);
encoder_.EncodeHeaderSetWithoutCompression(headers, &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) {
encoder_.SetHeaderListener([this](StringPiece name, StringPiece value) {
this->SaveHeaders(name, value);
});
// Pass 1.
{
SpdyHeaderBlock headers;
......@@ -339,6 +374,19 @@ TEST_F(HpackEncoderTest, MultipleEncodingPasses) {
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) {
......
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