Commit fc3abecc authored by bnc's avatar bnc Committed by Commit bot

HPACK: Split header fields in encoder.

Since '\0' delimited concatenation of header field values is not allowed any
more in HTTP/2 draft-14, but servers might prepare such headers, the HPACK
encoder should split them into multiple headers with identical names.

This lands server change 74384948 by bnc.

BUG=400336

Review URL: https://codereview.chromium.org/533073004

Cr-Commit-Position: refs/heads/master@{#293537}
parent 5dde0685
......@@ -37,11 +37,9 @@ bool HpackEncoder::EncodeHeaderSet(const std::map<string, string>& header_set,
// a map.
CookieToCrumbs(*it, &regular_headers);
} else if (it->first[0] == kPseudoHeaderPrefix) {
pseudo_headers.push_back(make_pair(
StringPiece(it->first), StringPiece(it->second)));
DecomposeRepresentation(*it, &pseudo_headers);
} else {
regular_headers.push_back(make_pair(
StringPiece(it->first), StringPiece(it->second)));
DecomposeRepresentation(*it, &regular_headers);
}
}
......@@ -200,4 +198,17 @@ void HpackEncoder::CookieToCrumbs(const Representation& cookie,
out->end());
}
// static
void HpackEncoder::DecomposeRepresentation(const Representation& header_field,
Representations* out) {
size_t pos = 0;
size_t end = 0;
while (end != StringPiece::npos) {
end = header_field.second.find('\0', pos);
out->push_back(make_pair(header_field.first,
header_field.second.substr(pos, end - pos)));
pos = end + 1;
}
}
} // namespace net
......@@ -7,6 +7,7 @@
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "base/basictypes.h"
......@@ -82,6 +83,10 @@ class NET_EXPORT_PRIVATE HpackEncoder {
static void CookieToCrumbs(const Representation& cookie,
Representations* crumbs_out);
// Crumbles other header field values at \0 delimiters.
static void DecomposeRepresentation(const Representation& header_field,
Representations* out);
HpackHeaderTable header_table_;
HpackOutputStream output_stream_;
......
......@@ -70,6 +70,16 @@ class HpackEncoderPeer {
out->push_back(tmp[i].second);
}
}
static void DecomposeRepresentation(StringPiece value,
std::vector<StringPiece>* out) {
Representations tmp;
HpackEncoder::DecomposeRepresentation(make_pair("foobar", value), &tmp);
out->clear();
for (size_t i = 0; i != tmp.size(); ++i) {
out->push_back(tmp[i].second);
}
}
private:
HpackEncoder* encoder_;
......@@ -413,6 +423,45 @@ TEST_F(HpackEncoderTest, UpdateCharacterCounts) {
EXPECT_EQ(9u, total_counts);
}
TEST_F(HpackEncoderTest, DecomposeRepresentation) {
test::HpackEncoderPeer peer(NULL);
std::vector<StringPiece> out;
peer.DecomposeRepresentation("", &out);
EXPECT_THAT(out, ElementsAre(""));
peer.DecomposeRepresentation("foobar", &out);
EXPECT_THAT(out, ElementsAre("foobar"));
peer.DecomposeRepresentation(StringPiece("foo\0bar", 7), &out);
EXPECT_THAT(out, ElementsAre("foo", "bar"));
peer.DecomposeRepresentation(StringPiece("\0foo\0bar", 8), &out);
EXPECT_THAT(out, ElementsAre("", "foo", "bar"));
peer.DecomposeRepresentation(StringPiece("foo\0bar\0", 8), &out);
EXPECT_THAT(out, ElementsAre("foo", "bar", ""));
peer.DecomposeRepresentation(StringPiece("\0foo\0bar\0", 9), &out);
EXPECT_THAT(out, ElementsAre("", "foo", "bar", ""));
}
// Test that encoded headers do not have \0-delimited multiple values, as this
// became disallowed in HTTP/2 draft-14.
TEST_F(HpackEncoderTest, CrumbleNullByteDelimitedValue) {
map<string, string> headers;
// A header field to be crumbled: "spam: foo\0bar".
headers["spam"] = string("foo\0bar", 7);
ExpectIndexedLiteral("spam", "foo");
expected_.AppendPrefix(kLiteralIncrementalIndexOpcode);
expected_.AppendUint32(62);
expected_.AppendPrefix(kStringLiteralIdentityEncoded);
expected_.AppendUint32(3);
expected_.AppendBytes("bar");
CompareWithExpectedEncoding(headers);
}
} // namespace
} // namespace net
......@@ -81,6 +81,7 @@ TEST_F(HpackRoundTripTest, ResponseFixtures) {
headers["location"] = "https://www.example.com";
headers["set-cookie"] = "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;"
" max-age=3600; version=1";
headers["multivalue"] = string("foo\0bar", 7);
EXPECT_TRUE(RoundTrip(headers));
}
}
......@@ -113,6 +114,7 @@ TEST_F(HpackRoundTripTest, RequestFixtures) {
headers[":scheme"] = "https";
headers["custom-key"] = "custom-value";
headers["cookie"] = "baz=bing; fizzle=fazzle; garbage";
headers["multivalue"] = string("foo\0bar", 7);
EXPECT_TRUE(RoundTrip(headers));
}
}
......@@ -157,8 +159,14 @@ TEST_F(HpackRoundTripTest, RandomizedExamples) {
name = names[name_index];
}
if (value_index >= values.size()) {
values.push_back(base::RandBytesAsString(
1 + SampleExponential(15, 75)));
string newvalue =
base::RandBytesAsString(1 + SampleExponential(15, 75));
// Currently order is not preserved in the encoder. In particular,
// when a value is decomposed at \0 delimiters, its parts might get
// encoded out of order if some but not all of them already exist in
// the header table. For now, avoid \0 bytes in values.
std::replace(newvalue.begin(), newvalue.end(), '\x00', '\x01');
values.push_back(newvalue);
value = values.back();
} else {
value = values[value_index];
......
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