Index: net/spdy/spdy_framer_test.cc |
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc |
index bbfd0259ee4fdf9f733f3b2690f507705462e721..4c751c2124acdff2ad691e78334d68ba53cc1d64 100644 |
--- a/net/spdy/spdy_framer_test.cc |
+++ b/net/spdy/spdy_framer_test.cc |
@@ -37,8 +37,6 @@ namespace net { |
namespace test { |
-static const size_t kMaxDecompressedSize = 1024; |
- |
class MockDebugVisitor : public SpdyFramerDebugVisitorInterface { |
public: |
MOCK_METHOD4(OnSendCompressedFrame, |
@@ -64,7 +62,7 @@ class SpdyFramerTestUtil { |
template <class SpdyFrameType> |
static SpdySerializedFrame DecompressFrame(SpdyFramer* framer, |
const SpdyFrameType& frame) { |
- NewDecompressionVisitor visitor; |
+ DecompressionVisitor visitor; |
framer->set_visitor(&visitor); |
CHECK_EQ(frame.size(), framer->ProcessInput(frame.data(), frame.size())); |
CHECK_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer->state()); |
@@ -74,9 +72,9 @@ class SpdyFramerTestUtil { |
return serializer.SerializeFrame(visitor.GetFrame()); |
} |
- class NewDecompressionVisitor : public SpdyFramerVisitorInterface { |
+ class DecompressionVisitor : public SpdyFramerVisitorInterface { |
public: |
- NewDecompressionVisitor() : finished_(false) {} |
+ DecompressionVisitor() : finished_(false) {} |
const SpdyFrameIR& GetFrame() const { |
CHECK(finished_); |
@@ -210,178 +208,6 @@ class SpdyFramerTestUtil { |
std::unique_ptr<SpdyFrameWithHeaderBlockIR> frame_; |
bool finished_; |
- DISALLOW_COPY_AND_ASSIGN(NewDecompressionVisitor); |
- }; |
- |
- class DecompressionVisitor : public SpdyFramerVisitorInterface { |
- public: |
- explicit DecompressionVisitor(SpdyMajorVersion version) |
- : version_(version), size_(0), finished_(false) {} |
- |
- void ResetBuffer() { |
- CHECK(buffer_.get() == NULL); |
- CHECK_EQ(0u, size_); |
- CHECK(!finished_); |
- buffer_.reset(new char[kMaxDecompressedSize]); |
- } |
- |
- void OnError(SpdyFramer* framer) override { LOG(FATAL); } |
- void OnDataFrameHeader(SpdyStreamId stream_id, |
- size_t length, |
- bool fin) override { |
- LOG(FATAL) << "Unexpected data frame header"; |
- } |
- void OnStreamFrameData(SpdyStreamId stream_id, |
- const char* data, |
- size_t len) override { |
- LOG(FATAL); |
- } |
- |
- void OnStreamEnd(SpdyStreamId stream_id) override { LOG(FATAL); } |
- |
- void OnStreamPadding(SpdyStreamId stream_id, size_t len) override { |
- LOG(FATAL); |
- } |
- |
- SpdyHeadersHandlerInterface* OnHeaderFrameStart( |
- SpdyStreamId stream_id) override { |
- LOG(FATAL) << "Not implemented."; |
- return nullptr; |
- } |
- |
- void OnHeaderFrameEnd(SpdyStreamId stream_id, bool end_headers) override { |
- LOG(FATAL) << "Not implemented."; |
- } |
- |
- bool OnControlFrameHeaderData(SpdyStreamId stream_id, |
- const char* header_data, |
- size_t len) override { |
- CHECK(buffer_.get() != NULL); |
- CHECK_GE(kMaxDecompressedSize, size_ + len); |
- CHECK(!finished_); |
- if (len != 0) { |
- memcpy(buffer_.get() + size_, header_data, len); |
- size_ += len; |
- } else { |
- // Done. |
- finished_ = true; |
- } |
- return true; |
- } |
- |
- void OnSynStream(SpdyStreamId stream_id, |
- SpdyStreamId associated_stream_id, |
- SpdyPriority priority, |
- bool fin, |
- bool unidirectional) override { |
- SpdyFramer framer(version_); |
- framer.set_enable_compression(false); |
- SpdySynStreamIR syn_stream(stream_id); |
- syn_stream.set_associated_to_stream_id(associated_stream_id); |
- syn_stream.set_priority(priority); |
- syn_stream.set_fin(fin); |
- syn_stream.set_unidirectional(unidirectional); |
- SpdySerializedFrame frame(framer.SerializeSynStream(syn_stream)); |
- ResetBuffer(); |
- memcpy(buffer_.get(), frame.data(), framer.GetSynStreamMinimumSize()); |
- size_ += framer.GetSynStreamMinimumSize(); |
- } |
- |
- void OnSynReply(SpdyStreamId stream_id, bool fin) override { |
- SpdyFramer framer(version_); |
- framer.set_enable_compression(false); |
- SpdyHeadersIR headers(stream_id); |
- headers.set_fin(fin); |
- SpdySerializedFrame frame(framer.SerializeHeaders(headers)); |
- ResetBuffer(); |
- memcpy(buffer_.get(), frame.data(), framer.GetHeadersMinimumSize()); |
- size_ += framer.GetSynStreamMinimumSize(); |
- } |
- |
- void OnRstStream(SpdyStreamId stream_id, |
- SpdyRstStreamStatus status) override { |
- LOG(FATAL); |
- } |
- void OnSetting(SpdySettingsIds id, uint8_t flags, uint32_t value) override { |
- LOG(FATAL); |
- } |
- void OnPing(SpdyPingId unique_id, bool is_ack) override { LOG(FATAL); } |
- void OnSettingsEnd() override { LOG(FATAL); } |
- void OnGoAway(SpdyStreamId last_accepted_stream_id, |
- SpdyGoAwayStatus status) override { |
- LOG(FATAL); |
- } |
- |
- void OnHeaders(SpdyStreamId stream_id, |
- bool has_priority, |
- int weight, |
- SpdyStreamId parent_stream_id, |
- bool exclusive, |
- bool fin, |
- bool end) override { |
- SpdyFramer framer(version_); |
- framer.set_enable_compression(false); |
- SpdyHeadersIR headers(stream_id); |
- headers.set_has_priority(has_priority); |
- headers.set_weight(weight); |
- headers.set_parent_stream_id(parent_stream_id); |
- headers.set_exclusive(exclusive); |
- headers.set_fin(fin); |
- SpdySerializedFrame frame(framer.SerializeHeaders(headers)); |
- ResetBuffer(); |
- memcpy(buffer_.get(), frame.data(), framer.GetHeadersMinimumSize()); |
- size_ += framer.GetHeadersMinimumSize(); |
- } |
- |
- void OnWindowUpdate(SpdyStreamId stream_id, |
- int delta_window_size) override { |
- LOG(FATAL); |
- } |
- |
- void OnPushPromise(SpdyStreamId stream_id, |
- SpdyStreamId promised_stream_id, |
- bool end) override { |
- SpdyFramer framer(version_); |
- framer.set_enable_compression(false); |
- SpdyPushPromiseIR push_promise(stream_id, promised_stream_id); |
- SpdySerializedFrame frame(framer.SerializePushPromise(push_promise)); |
- ResetBuffer(); |
- memcpy(buffer_.get(), frame.data(), framer.GetPushPromiseMinimumSize()); |
- size_ += framer.GetPushPromiseMinimumSize(); |
- } |
- |
- void OnContinuation(SpdyStreamId stream_id, bool end) override { |
- LOG(FATAL); |
- } |
- |
- void OnPriority(SpdyStreamId stream_id, |
- SpdyStreamId parent_stream_id, |
- int weight, |
- bool exclusive) override { |
- // Do nothing. |
- } |
- |
- bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override { |
- LOG(FATAL); |
- return false; |
- } |
- |
- char* ReleaseBuffer() { |
- CHECK(finished_); |
- return buffer_.release(); |
- } |
- |
- size_t size() const { |
- CHECK(finished_); |
- return size_; |
- } |
- |
- private: |
- SpdyMajorVersion version_; |
- std::unique_ptr<char[]> buffer_; |
- size_t size_; |
- bool finished_; |
- |
DISALLOW_COPY_AND_ASSIGN(DecompressionVisitor); |
}; |
@@ -1004,6 +830,73 @@ TEST_P(SpdyFramerTest, UndersizedHeaderBlockInBuffer) { |
EXPECT_EQ(0u, visitor.headers_.size()); |
} |
+// Test that we make all header field names (keys) lower case on encoding. |
+TEST_P(SpdyFramerTest, HeaderBlockToLowerCase) { |
+ // The HPACK encoding path does not lowercase field names. |
+ if (IsHttp2()) { |
+ return; |
+ } |
+ |
+ SpdyFramer framer(spdy_version_); |
+ framer.set_enable_compression(true); |
+ |
+ // Encode the header block into a Headers frame. |
+ SpdyHeadersIR headers_ir(1); |
+ headers_ir.SetHeader("aLpha", "beta"); |
+ headers_ir.SetHeader("GAMMA", "charlie"); |
+ headers_ir.SetHeader("foo", "Bar"); // Upper case values are okay. |
+ SpdySerializedFrame frame( |
+ SpdyFramerPeer::SerializeHeaders(&framer, headers_ir)); |
+ TestSpdyVisitor visitor(spdy_version_); |
+ visitor.use_compression_ = true; |
+ visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()), |
+ frame.size()); |
+ EXPECT_EQ(1, visitor.headers_frame_count_); |
+ EXPECT_EQ(headers_ir.header_block().size(), visitor.headers_.size()); |
+ EXPECT_EQ("beta", visitor.headers_["alpha"]); |
+ EXPECT_EQ("charlie", visitor.headers_["gamma"]); |
+ EXPECT_EQ("Bar", visitor.headers_["foo"]); |
+} |
+ |
+// Test that we treat incoming upper-case or mixed-case header values as |
+// malformed for HTTP2. |
+TEST_P(SpdyFramerTest, RejectUpperCaseHeaderBlockValue) { |
+ if (!IsHttp2()) { |
+ return; |
+ } |
+ |
+ SpdyFramer framer(spdy_version_); |
+ framer.set_enable_compression(false); |
+ |
+ SpdyFrameBuilder frame(1024, spdy_version_); |
+ frame.BeginNewFrame(framer, HEADERS, 0, 1); |
+ frame.WriteUInt32(1); |
+ frame.WriteStringPiece32("Name1"); |
+ frame.WriteStringPiece32("value1"); |
+ frame.RewriteLength(framer); |
+ |
+ SpdyFrameBuilder frame2(1024, spdy_version_); |
+ frame2.BeginNewFrame(framer, HEADERS, 0, 1); |
+ frame2.WriteUInt32(2); |
+ frame2.WriteStringPiece32("name1"); |
+ frame2.WriteStringPiece32("value1"); |
+ frame2.WriteStringPiece32("nAmE2"); |
+ frame2.WriteStringPiece32("value2"); |
+ frame2.RewriteLength(framer); |
+ |
+ SpdySerializedFrame control_frame(frame.take()); |
+ StringPiece serialized_headers = GetSerializedHeaders(control_frame, framer); |
+ SpdySerializedFrame control_frame2(frame2.take()); |
+ StringPiece serialized_headers2 = |
+ GetSerializedHeaders(control_frame2, framer); |
+ |
+ SpdyHeaderBlock new_headers; |
+ EXPECT_FALSE(framer.ParseHeaderBlockInBuffer( |
+ serialized_headers.data(), serialized_headers.size(), &new_headers)); |
+ EXPECT_FALSE(framer.ParseHeaderBlockInBuffer( |
+ serialized_headers2.data(), serialized_headers2.size(), &new_headers)); |
+} |
+ |
// Test that we can encode and decode stream dependency values in a header |
// frame. |
TEST_P(SpdyFramerTest, HeaderStreamDependencyValues) { |
@@ -4756,7 +4649,7 @@ TEST_P(SpdyFramerTest, ReadHeadersWithContinuation) { |
const unsigned char kInput[] = { |
0x00, 0x00, 0x14, // Length: 20 |
0x01, // Type: HEADERS |
- 0x09, // Flags: FIN, PADDED |
+ 0x08, // Flags: PADDED |
0x00, 0x00, 0x00, 0x01, // Stream: 1 |
0x03, // PadLen: 3 trailing bytes |
0x00, // Unindexed Entry |
@@ -4800,6 +4693,65 @@ TEST_P(SpdyFramerTest, ReadHeadersWithContinuation) { |
EXPECT_EQ(0, visitor.error_count_); |
EXPECT_EQ(1, visitor.headers_frame_count_); |
EXPECT_EQ(2, visitor.continuation_count_); |
+ EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); |
+ EXPECT_EQ(0, visitor.end_of_stream_count_); |
+ |
+ EXPECT_THAT( |
+ visitor.headers_, |
+ testing::ElementsAre(testing::Pair("cookie", "foo=bar; baz=bing; "), |
+ testing::Pair("name", "value"))); |
+} |
+ |
+TEST_P(SpdyFramerTest, ReadHeadersWithContinuationAndFin) { |
+ if (!IsHttp2()) { |
+ return; |
+ } |
+ // frame-format off |
+ const unsigned char kInput[] = { |
+ 0x00, 0x00, 0x10, // Length: 20 |
+ 0x01, // Type: HEADERS |
+ 0x01, // Flags: END_STREAM |
+ 0x00, 0x00, 0x00, 0x01, // Stream: 1 |
+ 0x00, // Unindexed Entry |
+ 0x06, // Name Len: 6 |
+ 'c', 'o', 'o', 'k', 'i', 'e', // Name |
+ 0x07, // Value Len: 7 |
+ 'f', 'o', 'o', '=', 'b', 'a', 'r', // Value |
+ |
+ 0x00, 0x00, 0x14, // Length: 20 |
+ 0x09, // Type: CONTINUATION |
+ 0x00, // Flags: none |
+ 0x00, 0x00, 0x00, 0x01, // Stream: 1 |
+ 0x00, // Unindexed Entry |
+ 0x06, // Name Len: 6 |
+ 'c', 'o', 'o', 'k', 'i', 'e', // Name |
+ 0x08, // Value Len: 7 |
+ 'b', 'a', 'z', '=', 'b', 'i', 'n', 'g', // Value |
+ 0x00, // Unindexed Entry |
+ 0x06, // Name Len: 6 |
+ 'c', // Name (split) |
+ |
+ 0x00, 0x00, 0x12, // Length: 18 |
+ 0x09, // Type: CONTINUATION |
+ 0x04, // Flags: END_HEADERS |
+ 0x00, 0x00, 0x00, 0x01, // Stream: 1 |
+ 'o', 'o', 'k', 'i', 'e', // Name (continued) |
+ 0x00, // Value Len: 0 |
+ 0x00, // Unindexed Entry |
+ 0x04, // Name Len: 4 |
+ 'n', 'a', 'm', 'e', // Name |
+ 0x05, // Value Len: 5 |
+ 'v', 'a', 'l', 'u', 'e', // Value |
+ }; |
+ // frame-format on |
+ |
+ SpdyFramer framer(spdy_version_); |
+ TestSpdyVisitor visitor(spdy_version_); |
+ visitor.SimulateInFramer(kInput, sizeof(kInput)); |
+ |
+ EXPECT_EQ(0, visitor.error_count_); |
+ EXPECT_EQ(1, visitor.headers_frame_count_); |
+ EXPECT_EQ(2, visitor.continuation_count_); |
EXPECT_EQ(1, visitor.fin_flag_count_); |
EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); |
EXPECT_EQ(1, visitor.end_of_stream_count_); |
@@ -5800,9 +5752,7 @@ TEST_P(SpdyFramerTest, PushPromiseFrameFlags) { |
bool end = flags & PUSH_PROMISE_FLAG_END_PUSH_PROMISE; |
EXPECT_CALL(debug_visitor, |
OnReceiveCompressedFrame(client_id, PUSH_PROMISE, _)); |
- EXPECT_CALL(visitor, |
- OnPushPromise(client_id, promised_id, |
- flags & PUSH_PROMISE_FLAG_END_PUSH_PROMISE)); |
+ EXPECT_CALL(visitor, OnPushPromise(client_id, promised_id, end)); |
EXPECT_CALL(visitor, OnHeaderFrameStart(client_id)).Times(1); |
if (end) { |
EXPECT_CALL(visitor, OnHeaderFrameEnd(client_id, _)).Times(1); |