diff options
Diffstat (limited to 'chromium/net/spdy/spdy_deframer_visitor_test.cc')
-rw-r--r-- | chromium/net/spdy/spdy_deframer_visitor_test.cc | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/chromium/net/spdy/spdy_deframer_visitor_test.cc b/chromium/net/spdy/spdy_deframer_visitor_test.cc new file mode 100644 index 00000000000..9b1a1f29e52 --- /dev/null +++ b/chromium/net/spdy/spdy_deframer_visitor_test.cc @@ -0,0 +1,273 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/spdy/spdy_deframer_visitor.h" + +#include <stdlib.h> +#include <string.h> + +#include <algorithm> +#include <limits> + +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/rand_util.h" +#include "base/strings/string_piece.h" +#include "net/spdy/hpack/hpack_constants.h" +#include "net/spdy/mock_spdy_framer_visitor.h" +#include "net/spdy/spdy_frame_builder.h" +#include "net/spdy/spdy_frame_reader.h" +#include "net/spdy/spdy_protocol.h" +#include "net/spdy/spdy_protocol_test_utils.h" +#include "net/spdy/spdy_test_utils.h" + +using ::base::MakeUnique; +using ::std::string; + +namespace net { +namespace test { +namespace { + +class SpdyDeframerVisitorTest : public ::testing::Test { + protected: + SpdyDeframerVisitorTest() : encoder_(HTTP2), decoder_(HTTP2) { + decoder_.set_process_single_input_frame(true); + decoder_.set_use_new_methods_for_test(true); + auto collector = MakeUnique<DeframerCallbackCollector>(&collected_frames_); + auto log_and_collect = + SpdyDeframerVisitorInterface::LogBeforeVisiting(std::move(collector)); + deframer_ = SpdyTestDeframer::CreateConverter(std::move(log_and_collect)); + decoder_.set_visitor(deframer_.get()); + } + + bool DeframeInput(const char* input, size_t size) { + size_t input_remaining = size; + while (input_remaining > 0 && + decoder_.error_code() == SpdyFramer::SPDY_NO_ERROR) { + // To make the tests more interesting, we feed random (and small) chunks + // into the framer. This simulates getting strange-sized reads from + // the socket. + const size_t kMaxReadSize = 32; + size_t bytes_read = + (base::RandGenerator(std::min(input_remaining, kMaxReadSize))) + 1; + size_t bytes_processed = decoder_.ProcessInput(input, bytes_read); + input_remaining -= bytes_processed; + input += bytes_processed; + if (decoder_.state() == SpdyFramer::SPDY_READY_FOR_FRAME) { + deframer_->AtFrameEnd(); + } + } + return (input_remaining == 0 && + decoder_.error_code() == SpdyFramer::SPDY_NO_ERROR); + } + + SpdySerializedFrame SerializeFrame(const SpdyFrameIR& frame) { + return encoder_.SerializeFrame(frame); + } + + string SerializeFrames( + const std::vector<std::unique_ptr<SpdyFrameIR>>& frames) { + string result; + for (const auto& frame_ptr : frames) { + auto sf = SerializeFrame(*frame_ptr); + base::StringPiece(sf.data(), sf.size()).AppendToString(&result); + } + return result; + } + + // bool + + SpdyFramer encoder_; + SpdyFramer decoder_; + std::vector<CollectedFrame> collected_frames_; + std::unique_ptr<SpdyTestDeframer> deframer_; +}; + +TEST_F(SpdyDeframerVisitorTest, DataFrame) { + const char kFrameData[] = { + 0x00, 0x00, 0x0d, // Length = 13. + 0x00, // DATA + 0x08, // PADDED + 0x00, 0x00, 0x00, 0x01, // Stream 1 + 0x07, // Pad length field. + 'h', 'e', 'l', 'l', // Data + 'o', // More Data + 0x00, 0x00, 0x00, 0x00, // Padding + 0x00, 0x00, 0x00 // More Padding + }; + + EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); + ASSERT_EQ(1u, collected_frames_.size()); + const CollectedFrame& cf0 = collected_frames_[0]; + ASSERT_NE(cf0.frame_ir, nullptr); + + SpdyDataIR expected_ir(1, "hello"); + expected_ir.set_padding_len(8); + EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); +} + +TEST_F(SpdyDeframerVisitorTest, HeaderFrameWithContinuation) { + const char kFrameData[] = { + 0x00, 0x00, 0x05, // Payload Length: 5 + 0x01, // Type: HEADERS + 0x09, // Flags: PADDED | END_STREAM + 0x00, 0x00, 0x00, 0x01, // Stream: 1 + 0x04, // Padding Length: 4 + 0x00, 0x00, 0x00, 0x00, // Padding + /* Second Frame */ + 0x00, 0x00, 0x12, // Payload Length: 18 + 0x09, // Type: CONTINUATION + 0x04, // Flags: END_HEADERS + 0x00, 0x00, 0x00, 0x01, // Stream: 1 + 0x00, // Unindexed, literal name & value + 0x03, 0x62, 0x61, 0x72, // Name len and name (3, "bar") + 0x03, 0x66, 0x6f, 0x6f, // Value len and value (3, "foo") + 0x00, // Unindexed, literal name & value + 0x03, 0x66, 0x6f, 0x6f, // Name len and name (3, "foo") + 0x03, 0x62, 0x61, 0x72, // Value len and value (3, "bar") + }; + + EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); + ASSERT_EQ(1u, collected_frames_.size()); + const CollectedFrame& cf0 = collected_frames_[0]; + + StringPairVector headers; + headers.push_back({"bar", "foo"}); + headers.push_back({"foo", "bar"}); + + EXPECT_TRUE(cf0.VerifyHasHeaders(headers)); + + SpdyHeadersIR expected_ir(1); + // Yet again SpdyFramerVisitorInterface is lossy: it doesn't call OnPadding + // for HEADERS, just for DATA. Sigh. + // expected_ir.set_padding_len(5); + expected_ir.set_fin(true); + for (const auto& nv : headers) { + expected_ir.SetHeader(nv.first, nv.second); + } + + EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); + + // Confirm that mismatches are also detected. + headers.push_back({"baz", "bing"}); + EXPECT_FALSE(cf0.VerifyHasHeaders(headers)); + EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); + + headers.pop_back(); + EXPECT_TRUE(cf0.VerifyHasHeaders(headers)); + EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); + + expected_ir.SetHeader("baz", "bing"); + EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); + EXPECT_TRUE(cf0.VerifyHasHeaders(headers)); +} + +TEST_F(SpdyDeframerVisitorTest, PriorityFrame) { + const char kFrameData[] = { + 0x00, 0x00, 0x05, // Length: 5 + 0x02, // Type: PRIORITY + 0x00, // Flags: none + 0x00, 0x00, 0x00, 0x65, // Stream: 101 + 0x80u, 0x00, 0x00, 0x01, // Parent: 1 (Exclusive) + 0x10, // Weight: 17 + }; + + EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); + ASSERT_EQ(1u, collected_frames_.size()); + const CollectedFrame& cf0 = collected_frames_[0]; + + SpdyPriorityIR expected_ir(101, 1, 17, true); + EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); + + // Confirm that mismatches are also detected. + expected_ir.set_weight(16); + EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); + expected_ir.set_weight(17); + EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); + + expected_ir.set_parent_stream_id(50); + EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); + expected_ir.set_parent_stream_id(1); + EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); + + expected_ir.set_stream_id(201); + EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); + expected_ir.set_stream_id(101); + EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); + + expected_ir.set_exclusive(false); + EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); + expected_ir.set_exclusive(true); + EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); +} + +TEST_F(SpdyDeframerVisitorTest, DISABLED_RstStreamFrame) { + // TODO(jamessynge): Please implement. +} + +TEST_F(SpdyDeframerVisitorTest, SettingsFrame) { + // Settings frame with two entries for the same parameter but with different + // values. The last one will be in the decoded SpdySettingsIR, but the vector + // of settings will have both, in the same order. + const char kFrameData[] = { + 0x00, 0x00, 0x0c, // Length + 0x04, // Type (SETTINGS) + 0x00, // Flags + 0x00, 0x00, 0x00, 0x00, // Stream id (must be zero) + 0x00, 0x04, // Setting id (SETTINGS_INITIAL_WINDOW_SIZE) + 0x0a, 0x0b, 0x0c, 0x0d, // Setting value + 0x00, 0x04, // Setting id (SETTINGS_INITIAL_WINDOW_SIZE) + 0x00, 0x00, 0x00, 0xffu // Setting value + }; + + EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); + ASSERT_EQ(1u, collected_frames_.size()); + const CollectedFrame& cf0 = collected_frames_[0]; + ASSERT_NE(cf0.frame_ir, nullptr); + + SpdySettingsIR expected_ir; + expected_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, true, true, 255); + EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); + + SettingVector expected_settings; + expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 0x0a0b0c0d}); + expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 255}); + + EXPECT_TRUE(cf0.VerifyHasSettings(expected_settings)); + + // Confirm that mismatches are also detected. + expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 65536}); + EXPECT_FALSE(cf0.VerifyHasSettings(expected_settings)); + + expected_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, true, true, 65536); + EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); + + SpdySettingsIR unexpected_ir; + unexpected_ir.set_is_ack(true); + EXPECT_FALSE(cf0.VerifyHasFrame(unexpected_ir)); +} + +TEST_F(SpdyDeframerVisitorTest, DISABLED_PushPromiseFrame) { + // TODO(jamessynge): Please implement. +} + +TEST_F(SpdyDeframerVisitorTest, DISABLED_PingFrame) { + // TODO(jamessynge): Please implement. +} + +TEST_F(SpdyDeframerVisitorTest, DISABLED_GoAwayFrame) { + // TODO(jamessynge): Please implement. +} + +TEST_F(SpdyDeframerVisitorTest, DISABLED_WindowUpdateFrame) { + // TODO(jamessynge): Please implement. +} + +TEST_F(SpdyDeframerVisitorTest, DISABLED_AltSvcFrame) { + // TODO(jamessynge): Please implement. +} + +} // namespace +} // namespace test +} // namespace net |