OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "net/spdy/spdy_deframer_visitor.h" |
| 6 |
| 7 #include <stdlib.h> |
| 8 #include <string.h> |
| 9 |
| 10 #include <algorithm> |
| 11 #include <limits> |
| 12 |
| 13 #include "base/logging.h" |
| 14 #include "base/memory/ptr_util.h" |
| 15 #include "base/rand_util.h" |
| 16 #include "base/strings/string_piece.h" |
| 17 #include "net/spdy/hpack/hpack_constants.h" |
| 18 #include "net/spdy/mock_spdy_framer_visitor.h" |
| 19 #include "net/spdy/spdy_frame_builder.h" |
| 20 #include "net/spdy/spdy_frame_reader.h" |
| 21 #include "net/spdy/spdy_protocol.h" |
| 22 #include "net/spdy/spdy_protocol_test_utils.h" |
| 23 #include "net/spdy/spdy_test_utils.h" |
| 24 |
| 25 using ::base::MakeUnique; |
| 26 using ::std::string; |
| 27 |
| 28 namespace net { |
| 29 namespace test { |
| 30 namespace { |
| 31 |
| 32 class SpdyDeframerVisitorTest : public ::testing::Test { |
| 33 protected: |
| 34 SpdyDeframerVisitorTest() : encoder_(HTTP2), decoder_(HTTP2) { |
| 35 decoder_.set_process_single_input_frame(true); |
| 36 decoder_.set_use_new_methods_for_test(true); |
| 37 auto collector = MakeUnique<DeframerCallbackCollector>(&collected_frames_); |
| 38 auto log_and_collect = |
| 39 SpdyDeframerVisitorInterface::LogBeforeVisiting(std::move(collector)); |
| 40 deframer_ = SpdyTestDeframer::CreateConverter(std::move(log_and_collect)); |
| 41 decoder_.set_visitor(deframer_.get()); |
| 42 } |
| 43 |
| 44 bool DeframeInput(const char* input, size_t size) { |
| 45 size_t input_remaining = size; |
| 46 while (input_remaining > 0 && |
| 47 decoder_.error_code() == SpdyFramer::SPDY_NO_ERROR) { |
| 48 // To make the tests more interesting, we feed random (and small) chunks |
| 49 // into the framer. This simulates getting strange-sized reads from |
| 50 // the socket. |
| 51 const size_t kMaxReadSize = 32; |
| 52 size_t bytes_read = |
| 53 (base::RandGenerator(std::min(input_remaining, kMaxReadSize))) + 1; |
| 54 size_t bytes_processed = decoder_.ProcessInput(input, bytes_read); |
| 55 input_remaining -= bytes_processed; |
| 56 input += bytes_processed; |
| 57 if (decoder_.state() == SpdyFramer::SPDY_READY_FOR_FRAME) { |
| 58 deframer_->AtFrameEnd(); |
| 59 } |
| 60 } |
| 61 return (input_remaining == 0 && |
| 62 decoder_.error_code() == SpdyFramer::SPDY_NO_ERROR); |
| 63 } |
| 64 |
| 65 SpdySerializedFrame SerializeFrame(const SpdyFrameIR& frame) { |
| 66 return encoder_.SerializeFrame(frame); |
| 67 } |
| 68 |
| 69 string SerializeFrames( |
| 70 const std::vector<std::unique_ptr<SpdyFrameIR>>& frames) { |
| 71 string result; |
| 72 for (const auto& frame_ptr : frames) { |
| 73 auto sf = SerializeFrame(*frame_ptr); |
| 74 base::StringPiece(sf.data(), sf.size()).AppendToString(&result); |
| 75 } |
| 76 return result; |
| 77 } |
| 78 |
| 79 // bool |
| 80 |
| 81 SpdyFramer encoder_; |
| 82 SpdyFramer decoder_; |
| 83 std::vector<CollectedFrame> collected_frames_; |
| 84 std::unique_ptr<SpdyTestDeframer> deframer_; |
| 85 }; |
| 86 |
| 87 TEST_F(SpdyDeframerVisitorTest, DataFrame) { |
| 88 const char kFrameData[] = { |
| 89 0x00, 0x00, 0x0d, // Length = 13. |
| 90 0x00, // DATA |
| 91 0x08, // PADDED |
| 92 0x00, 0x00, 0x00, 0x01, // Stream 1 |
| 93 0x07, // Pad length field. |
| 94 'h', 'e', 'l', 'l', // Data |
| 95 'o', // More Data |
| 96 0x00, 0x00, 0x00, 0x00, // Padding |
| 97 0x00, 0x00, 0x00 // More Padding |
| 98 }; |
| 99 |
| 100 EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); |
| 101 ASSERT_EQ(1u, collected_frames_.size()); |
| 102 const CollectedFrame& cf0 = collected_frames_[0]; |
| 103 ASSERT_NE(cf0.frame_ir, nullptr); |
| 104 |
| 105 SpdyDataIR expected_ir(1, "hello"); |
| 106 expected_ir.set_padding_len(8); |
| 107 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); |
| 108 } |
| 109 |
| 110 TEST_F(SpdyDeframerVisitorTest, HeaderFrameWithContinuation) { |
| 111 const char kFrameData[] = { |
| 112 0x00, 0x00, 0x05, // Payload Length: 5 |
| 113 0x01, // Type: HEADERS |
| 114 0x09, // Flags: PADDED | END_STREAM |
| 115 0x00, 0x00, 0x00, 0x01, // Stream: 1 |
| 116 0x04, // Padding Length: 4 |
| 117 0x00, 0x00, 0x00, 0x00, // Padding |
| 118 /* Second Frame */ |
| 119 0x00, 0x00, 0x12, // Payload Length: 18 |
| 120 0x09, // Type: CONTINUATION |
| 121 0x04, // Flags: END_HEADERS |
| 122 0x00, 0x00, 0x00, 0x01, // Stream: 1 |
| 123 0x00, // Unindexed, literal name & value |
| 124 0x03, 0x62, 0x61, 0x72, // Name len and name (3, "bar") |
| 125 0x03, 0x66, 0x6f, 0x6f, // Value len and value (3, "foo") |
| 126 0x00, // Unindexed, literal name & value |
| 127 0x03, 0x66, 0x6f, 0x6f, // Name len and name (3, "foo") |
| 128 0x03, 0x62, 0x61, 0x72, // Value len and value (3, "bar") |
| 129 }; |
| 130 |
| 131 EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); |
| 132 ASSERT_EQ(1u, collected_frames_.size()); |
| 133 const CollectedFrame& cf0 = collected_frames_[0]; |
| 134 |
| 135 StringPairVector headers; |
| 136 headers.push_back({"bar", "foo"}); |
| 137 headers.push_back({"foo", "bar"}); |
| 138 |
| 139 EXPECT_TRUE(cf0.VerifyHasHeaders(headers)); |
| 140 |
| 141 SpdyHeadersIR expected_ir(1); |
| 142 // Yet again SpdyFramerVisitorInterface is lossy: it doesn't call OnPadding |
| 143 // for HEADERS, just for DATA. Sigh. |
| 144 // expected_ir.set_padding_len(5); |
| 145 expected_ir.set_fin(true); |
| 146 for (const auto& nv : headers) { |
| 147 expected_ir.SetHeader(nv.first, nv.second); |
| 148 } |
| 149 |
| 150 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); |
| 151 |
| 152 // Confirm that mismatches are also detected. |
| 153 headers.push_back({"baz", "bing"}); |
| 154 EXPECT_FALSE(cf0.VerifyHasHeaders(headers)); |
| 155 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); |
| 156 |
| 157 headers.pop_back(); |
| 158 EXPECT_TRUE(cf0.VerifyHasHeaders(headers)); |
| 159 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); |
| 160 |
| 161 expected_ir.SetHeader("baz", "bing"); |
| 162 EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); |
| 163 EXPECT_TRUE(cf0.VerifyHasHeaders(headers)); |
| 164 } |
| 165 |
| 166 TEST_F(SpdyDeframerVisitorTest, PriorityFrame) { |
| 167 const char kFrameData[] = { |
| 168 0x00, 0x00, 0x05, // Length: 5 |
| 169 0x02, // Type: PRIORITY |
| 170 0x00, // Flags: none |
| 171 0x00, 0x00, 0x00, 0x65, // Stream: 101 |
| 172 0x80u, 0x00, 0x00, 0x01, // Parent: 1 (Exclusive) |
| 173 0x10, // Weight: 17 |
| 174 }; |
| 175 |
| 176 EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); |
| 177 ASSERT_EQ(1u, collected_frames_.size()); |
| 178 const CollectedFrame& cf0 = collected_frames_[0]; |
| 179 |
| 180 SpdyPriorityIR expected_ir(101, 1, 17, true); |
| 181 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); |
| 182 |
| 183 // Confirm that mismatches are also detected. |
| 184 expected_ir.set_weight(16); |
| 185 EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); |
| 186 expected_ir.set_weight(17); |
| 187 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); |
| 188 |
| 189 expected_ir.set_parent_stream_id(50); |
| 190 EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); |
| 191 expected_ir.set_parent_stream_id(1); |
| 192 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); |
| 193 |
| 194 expected_ir.set_stream_id(201); |
| 195 EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); |
| 196 expected_ir.set_stream_id(101); |
| 197 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); |
| 198 |
| 199 expected_ir.set_exclusive(false); |
| 200 EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); |
| 201 expected_ir.set_exclusive(true); |
| 202 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); |
| 203 } |
| 204 |
| 205 TEST_F(SpdyDeframerVisitorTest, DISABLED_RstStreamFrame) { |
| 206 // TODO(jamessynge): Please implement. |
| 207 } |
| 208 |
| 209 TEST_F(SpdyDeframerVisitorTest, SettingsFrame) { |
| 210 // Settings frame with two entries for the same parameter but with different |
| 211 // values. The last one will be in the decoded SpdySettingsIR, but the vector |
| 212 // of settings will have both, in the same order. |
| 213 const char kFrameData[] = { |
| 214 0x00, 0x00, 0x0c, // Length |
| 215 0x04, // Type (SETTINGS) |
| 216 0x00, // Flags |
| 217 0x00, 0x00, 0x00, 0x00, // Stream id (must be zero) |
| 218 0x00, 0x04, // Setting id (SETTINGS_INITIAL_WINDOW_SIZE) |
| 219 0x0a, 0x0b, 0x0c, 0x0d, // Setting value |
| 220 0x00, 0x04, // Setting id (SETTINGS_INITIAL_WINDOW_SIZE) |
| 221 0x00, 0x00, 0x00, 0xffu // Setting value |
| 222 }; |
| 223 |
| 224 EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); |
| 225 ASSERT_EQ(1u, collected_frames_.size()); |
| 226 const CollectedFrame& cf0 = collected_frames_[0]; |
| 227 ASSERT_NE(cf0.frame_ir, nullptr); |
| 228 |
| 229 SpdySettingsIR expected_ir; |
| 230 expected_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, true, true, 255); |
| 231 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); |
| 232 |
| 233 SettingVector expected_settings; |
| 234 expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 0x0a0b0c0d}); |
| 235 expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 255}); |
| 236 |
| 237 EXPECT_TRUE(cf0.VerifyHasSettings(expected_settings)); |
| 238 |
| 239 // Confirm that mismatches are also detected. |
| 240 expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 65536}); |
| 241 EXPECT_FALSE(cf0.VerifyHasSettings(expected_settings)); |
| 242 |
| 243 expected_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, true, true, 65536); |
| 244 EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); |
| 245 |
| 246 SpdySettingsIR unexpected_ir; |
| 247 unexpected_ir.set_is_ack(true); |
| 248 EXPECT_FALSE(cf0.VerifyHasFrame(unexpected_ir)); |
| 249 } |
| 250 |
| 251 TEST_F(SpdyDeframerVisitorTest, DISABLED_PushPromiseFrame) { |
| 252 // TODO(jamessynge): Please implement. |
| 253 } |
| 254 |
| 255 TEST_F(SpdyDeframerVisitorTest, DISABLED_PingFrame) { |
| 256 // TODO(jamessynge): Please implement. |
| 257 } |
| 258 |
| 259 TEST_F(SpdyDeframerVisitorTest, DISABLED_GoAwayFrame) { |
| 260 // TODO(jamessynge): Please implement. |
| 261 } |
| 262 |
| 263 TEST_F(SpdyDeframerVisitorTest, DISABLED_WindowUpdateFrame) { |
| 264 // TODO(jamessynge): Please implement. |
| 265 } |
| 266 |
| 267 TEST_F(SpdyDeframerVisitorTest, DISABLED_AltSvcFrame) { |
| 268 // TODO(jamessynge): Please implement. |
| 269 } |
| 270 |
| 271 } // namespace |
| 272 } // namespace test |
| 273 } // namespace net |
OLD | NEW |