| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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/buffered_spdy_framer.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <utility> | |
| 9 | |
| 10 #include "base/logging.h" | |
| 11 #include "net/spdy/spdy_test_util_common.h" | |
| 12 #include "testing/platform_test.h" | |
| 13 | |
| 14 namespace net { | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface { | |
| 19 public: | |
| 20 TestBufferedSpdyVisitor() | |
| 21 : buffered_spdy_framer_(), | |
| 22 error_count_(0), | |
| 23 setting_count_(0), | |
| 24 headers_frame_count_(0), | |
| 25 push_promise_frame_count_(0), | |
| 26 goaway_count_(0), | |
| 27 altsvc_count_(0), | |
| 28 header_stream_id_(static_cast<SpdyStreamId>(-1)), | |
| 29 promised_stream_id_(static_cast<SpdyStreamId>(-1)) {} | |
| 30 | |
| 31 void OnError(SpdyFramer::SpdyFramerError spdy_framer_error) override { | |
| 32 VLOG(1) << "SpdyFramer Error: " << spdy_framer_error; | |
| 33 error_count_++; | |
| 34 } | |
| 35 | |
| 36 void OnStreamError(SpdyStreamId stream_id, | |
| 37 const SpdyString& description) override { | |
| 38 VLOG(1) << "SpdyFramer Error on stream: " << stream_id << " " | |
| 39 << description; | |
| 40 error_count_++; | |
| 41 } | |
| 42 | |
| 43 void OnHeaders(SpdyStreamId stream_id, | |
| 44 bool has_priority, | |
| 45 int weight, | |
| 46 SpdyStreamId parent_stream_id, | |
| 47 bool exclusive, | |
| 48 bool fin, | |
| 49 SpdyHeaderBlock headers) override { | |
| 50 header_stream_id_ = stream_id; | |
| 51 EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream); | |
| 52 headers_frame_count_++; | |
| 53 headers_ = std::move(headers); | |
| 54 } | |
| 55 | |
| 56 void OnDataFrameHeader(SpdyStreamId stream_id, | |
| 57 size_t length, | |
| 58 bool fin) override { | |
| 59 ADD_FAILURE() << "Unexpected OnDataFrameHeader call."; | |
| 60 } | |
| 61 | |
| 62 void OnStreamFrameData(SpdyStreamId stream_id, | |
| 63 const char* data, | |
| 64 size_t len) override { | |
| 65 LOG(FATAL) << "Unexpected OnStreamFrameData call."; | |
| 66 } | |
| 67 | |
| 68 void OnStreamEnd(SpdyStreamId stream_id) override { | |
| 69 LOG(FATAL) << "Unexpected OnStreamEnd call."; | |
| 70 } | |
| 71 | |
| 72 void OnStreamPadding(SpdyStreamId stream_id, size_t len) override { | |
| 73 LOG(FATAL) << "Unexpected OnStreamPadding call."; | |
| 74 } | |
| 75 | |
| 76 void OnSettings() override {} | |
| 77 | |
| 78 void OnSetting(SpdySettingsIds id, uint32_t value) override { | |
| 79 setting_count_++; | |
| 80 } | |
| 81 | |
| 82 void OnPing(SpdyPingId unique_id, bool is_ack) override {} | |
| 83 | |
| 84 void OnRstStream(SpdyStreamId stream_id, SpdyErrorCode error_code) override {} | |
| 85 | |
| 86 void OnGoAway(SpdyStreamId last_accepted_stream_id, | |
| 87 SpdyErrorCode error_code, | |
| 88 SpdyStringPiece debug_data) override { | |
| 89 goaway_count_++; | |
| 90 goaway_last_accepted_stream_id_ = last_accepted_stream_id; | |
| 91 goaway_error_code_ = error_code; | |
| 92 goaway_debug_data_.assign(debug_data.data(), debug_data.size()); | |
| 93 } | |
| 94 | |
| 95 void OnDataFrameHeader(const SpdySerializedFrame* frame) { | |
| 96 LOG(FATAL) << "Unexpected OnDataFrameHeader call."; | |
| 97 } | |
| 98 | |
| 99 void OnRstStream(const SpdySerializedFrame& frame) {} | |
| 100 void OnGoAway(const SpdySerializedFrame& frame) {} | |
| 101 void OnPing(const SpdySerializedFrame& frame) {} | |
| 102 void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override {} | |
| 103 | |
| 104 void OnPushPromise(SpdyStreamId stream_id, | |
| 105 SpdyStreamId promised_stream_id, | |
| 106 SpdyHeaderBlock headers) override { | |
| 107 header_stream_id_ = stream_id; | |
| 108 EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream); | |
| 109 push_promise_frame_count_++; | |
| 110 promised_stream_id_ = promised_stream_id; | |
| 111 EXPECT_NE(promised_stream_id_, SpdyFramer::kInvalidStream); | |
| 112 headers_ = std::move(headers); | |
| 113 } | |
| 114 | |
| 115 void OnAltSvc(SpdyStreamId stream_id, | |
| 116 SpdyStringPiece origin, | |
| 117 const SpdyAltSvcWireFormat::AlternativeServiceVector& | |
| 118 altsvc_vector) override { | |
| 119 altsvc_count_++; | |
| 120 altsvc_stream_id_ = stream_id; | |
| 121 origin.CopyToString(&altsvc_origin_); | |
| 122 altsvc_vector_ = altsvc_vector; | |
| 123 } | |
| 124 | |
| 125 bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override { | |
| 126 return true; | |
| 127 } | |
| 128 | |
| 129 // Convenience function which runs a framer simulation with particular input. | |
| 130 void SimulateInFramer(const SpdySerializedFrame& frame) { | |
| 131 const char* input_ptr = frame.data(); | |
| 132 size_t input_remaining = frame.size(); | |
| 133 buffered_spdy_framer_.set_visitor(this); | |
| 134 while (input_remaining > 0 && | |
| 135 buffered_spdy_framer_.spdy_framer_error() == | |
| 136 SpdyFramer::SPDY_NO_ERROR) { | |
| 137 // To make the tests more interesting, we feed random (amd small) chunks | |
| 138 // into the framer. This simulates getting strange-sized reads from | |
| 139 // the socket. | |
| 140 const size_t kMaxReadSize = 32; | |
| 141 size_t bytes_read = | |
| 142 (rand() % std::min(input_remaining, kMaxReadSize)) + 1; | |
| 143 size_t bytes_processed = | |
| 144 buffered_spdy_framer_.ProcessInput(input_ptr, bytes_read); | |
| 145 input_remaining -= bytes_processed; | |
| 146 input_ptr += bytes_processed; | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 BufferedSpdyFramer buffered_spdy_framer_; | |
| 151 | |
| 152 // Counters from the visitor callbacks. | |
| 153 int error_count_; | |
| 154 int setting_count_; | |
| 155 int headers_frame_count_; | |
| 156 int push_promise_frame_count_; | |
| 157 int goaway_count_; | |
| 158 int altsvc_count_; | |
| 159 | |
| 160 // Header block streaming state: | |
| 161 SpdyStreamId header_stream_id_; | |
| 162 SpdyStreamId promised_stream_id_; | |
| 163 | |
| 164 // Headers from OnHeaders and OnPushPromise for verification. | |
| 165 SpdyHeaderBlock headers_; | |
| 166 | |
| 167 // OnGoAway parameters. | |
| 168 SpdyStreamId goaway_last_accepted_stream_id_; | |
| 169 SpdyErrorCode goaway_error_code_; | |
| 170 SpdyString goaway_debug_data_; | |
| 171 | |
| 172 // OnAltSvc parameters. | |
| 173 SpdyStreamId altsvc_stream_id_; | |
| 174 SpdyString altsvc_origin_; | |
| 175 SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector_; | |
| 176 }; | |
| 177 | |
| 178 } // namespace | |
| 179 | |
| 180 class BufferedSpdyFramerTest : public PlatformTest {}; | |
| 181 | |
| 182 TEST_F(BufferedSpdyFramerTest, OnSetting) { | |
| 183 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
| 184 SpdySettingsIR settings_ir; | |
| 185 settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 2); | |
| 186 settings_ir.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 3); | |
| 187 SpdySerializedFrame control_frame(framer.SerializeSettings(settings_ir)); | |
| 188 TestBufferedSpdyVisitor visitor; | |
| 189 | |
| 190 visitor.SimulateInFramer(control_frame); | |
| 191 EXPECT_EQ(0, visitor.error_count_); | |
| 192 EXPECT_EQ(2, visitor.setting_count_); | |
| 193 } | |
| 194 | |
| 195 TEST_F(BufferedSpdyFramerTest, HeaderListTooLarge) { | |
| 196 SpdyHeaderBlock headers; | |
| 197 SpdyString long_header_value(256 * 1024, 'x'); | |
| 198 headers["foo"] = long_header_value; | |
| 199 SpdyHeadersIR headers_ir(/*stream_id=*/1, std::move(headers)); | |
| 200 | |
| 201 BufferedSpdyFramer framer; | |
| 202 SpdySerializedFrame control_frame = framer.SerializeFrame(headers_ir); | |
| 203 | |
| 204 TestBufferedSpdyVisitor visitor; | |
| 205 visitor.SimulateInFramer(control_frame); | |
| 206 | |
| 207 EXPECT_EQ(1, visitor.error_count_); | |
| 208 EXPECT_EQ(0, visitor.headers_frame_count_); | |
| 209 EXPECT_EQ(0, visitor.push_promise_frame_count_); | |
| 210 EXPECT_EQ(SpdyHeaderBlock(), visitor.headers_); | |
| 211 } | |
| 212 | |
| 213 TEST_F(BufferedSpdyFramerTest, ValidHeadersAfterInvalidHeaders) { | |
| 214 SpdyHeaderBlock headers; | |
| 215 headers["invalid"] = "\r\n\r\n"; | |
| 216 | |
| 217 SpdyHeaderBlock headers2; | |
| 218 headers["alpha"] = "beta"; | |
| 219 | |
| 220 SpdyTestUtil spdy_test_util; | |
| 221 SpdySerializedFrame headers_frame( | |
| 222 spdy_test_util.ConstructSpdyReply(1, std::move(headers))); | |
| 223 SpdySerializedFrame headers_frame2( | |
| 224 spdy_test_util.ConstructSpdyReply(2, std::move(headers2))); | |
| 225 | |
| 226 TestBufferedSpdyVisitor visitor; | |
| 227 visitor.SimulateInFramer(headers_frame); | |
| 228 EXPECT_EQ(1, visitor.error_count_); | |
| 229 EXPECT_EQ(0, visitor.headers_frame_count_); | |
| 230 | |
| 231 visitor.SimulateInFramer(headers_frame2); | |
| 232 EXPECT_EQ(1, visitor.error_count_); | |
| 233 EXPECT_EQ(1, visitor.headers_frame_count_); | |
| 234 } | |
| 235 | |
| 236 TEST_F(BufferedSpdyFramerTest, ReadHeadersHeaderBlock) { | |
| 237 SpdyHeaderBlock headers; | |
| 238 headers["alpha"] = "beta"; | |
| 239 headers["gamma"] = "delta"; | |
| 240 SpdyHeadersIR headers_ir(/*stream_id=*/1, headers.Clone()); | |
| 241 | |
| 242 BufferedSpdyFramer framer; | |
| 243 SpdySerializedFrame control_frame = framer.SerializeFrame(headers_ir); | |
| 244 | |
| 245 TestBufferedSpdyVisitor visitor; | |
| 246 visitor.SimulateInFramer(control_frame); | |
| 247 EXPECT_EQ(0, visitor.error_count_); | |
| 248 EXPECT_EQ(1, visitor.headers_frame_count_); | |
| 249 EXPECT_EQ(0, visitor.push_promise_frame_count_); | |
| 250 EXPECT_EQ(headers, visitor.headers_); | |
| 251 } | |
| 252 | |
| 253 TEST_F(BufferedSpdyFramerTest, ReadPushPromiseHeaderBlock) { | |
| 254 SpdyHeaderBlock headers; | |
| 255 headers["alpha"] = "beta"; | |
| 256 headers["gamma"] = "delta"; | |
| 257 BufferedSpdyFramer framer; | |
| 258 SpdyPushPromiseIR push_promise_ir(/*stream_id=*/1, /*promised_stream_id=*/2, | |
| 259 headers.Clone()); | |
| 260 SpdySerializedFrame control_frame = framer.SerializeFrame(push_promise_ir); | |
| 261 | |
| 262 TestBufferedSpdyVisitor visitor; | |
| 263 visitor.SimulateInFramer(control_frame); | |
| 264 EXPECT_EQ(0, visitor.error_count_); | |
| 265 EXPECT_EQ(0, visitor.headers_frame_count_); | |
| 266 EXPECT_EQ(1, visitor.push_promise_frame_count_); | |
| 267 EXPECT_EQ(headers, visitor.headers_); | |
| 268 EXPECT_EQ(1u, visitor.header_stream_id_); | |
| 269 EXPECT_EQ(2u, visitor.promised_stream_id_); | |
| 270 } | |
| 271 | |
| 272 TEST_F(BufferedSpdyFramerTest, GoAwayDebugData) { | |
| 273 SpdyGoAwayIR go_ir(/*last_accepted_stream_id=*/2, ERROR_CODE_FRAME_SIZE_ERROR, | |
| 274 "foo"); | |
| 275 BufferedSpdyFramer framer; | |
| 276 SpdySerializedFrame goaway_frame = framer.SerializeFrame(go_ir); | |
| 277 | |
| 278 TestBufferedSpdyVisitor visitor; | |
| 279 visitor.SimulateInFramer(goaway_frame); | |
| 280 EXPECT_EQ(0, visitor.error_count_); | |
| 281 EXPECT_EQ(1, visitor.goaway_count_); | |
| 282 EXPECT_EQ(2u, visitor.goaway_last_accepted_stream_id_); | |
| 283 EXPECT_EQ(ERROR_CODE_FRAME_SIZE_ERROR, visitor.goaway_error_code_); | |
| 284 EXPECT_EQ("foo", visitor.goaway_debug_data_); | |
| 285 } | |
| 286 | |
| 287 // ALTSVC frame on stream 0 must have an origin. | |
| 288 TEST_F(BufferedSpdyFramerTest, OnAltSvcOnStreamZero) { | |
| 289 const SpdyStreamId altsvc_stream_id(0); | |
| 290 SpdyAltSvcIR altsvc_ir(altsvc_stream_id); | |
| 291 SpdyAltSvcWireFormat::AlternativeService alternative_service( | |
| 292 "quic", "alternative.example.org", 443, 86400, | |
| 293 SpdyAltSvcWireFormat::VersionVector()); | |
| 294 altsvc_ir.add_altsvc(alternative_service); | |
| 295 const char altsvc_origin[] = "https://www.example.org"; | |
| 296 altsvc_ir.set_origin(altsvc_origin); | |
| 297 BufferedSpdyFramer framer; | |
| 298 SpdySerializedFrame altsvc_frame(framer.SerializeFrame(altsvc_ir)); | |
| 299 | |
| 300 TestBufferedSpdyVisitor visitor; | |
| 301 visitor.SimulateInFramer(altsvc_frame); | |
| 302 EXPECT_EQ(0, visitor.error_count_); | |
| 303 EXPECT_EQ(1, visitor.altsvc_count_); | |
| 304 EXPECT_EQ(altsvc_stream_id, visitor.altsvc_stream_id_); | |
| 305 EXPECT_EQ(altsvc_origin, visitor.altsvc_origin_); | |
| 306 ASSERT_EQ(1u, visitor.altsvc_vector_.size()); | |
| 307 EXPECT_EQ(alternative_service, visitor.altsvc_vector_[0]); | |
| 308 } | |
| 309 | |
| 310 // ALTSVC frame on a non-zero stream must not have an origin. | |
| 311 TEST_F(BufferedSpdyFramerTest, OnAltSvcOnNonzeroStream) { | |
| 312 const SpdyStreamId altsvc_stream_id(1); | |
| 313 SpdyAltSvcIR altsvc_ir(altsvc_stream_id); | |
| 314 SpdyAltSvcWireFormat::AlternativeService alternative_service( | |
| 315 "quic", "alternative.example.org", 443, 86400, | |
| 316 SpdyAltSvcWireFormat::VersionVector()); | |
| 317 altsvc_ir.add_altsvc(alternative_service); | |
| 318 BufferedSpdyFramer framer; | |
| 319 SpdySerializedFrame altsvc_frame(framer.SerializeFrame(altsvc_ir)); | |
| 320 | |
| 321 TestBufferedSpdyVisitor visitor; | |
| 322 visitor.SimulateInFramer(altsvc_frame); | |
| 323 EXPECT_EQ(0, visitor.error_count_); | |
| 324 EXPECT_EQ(1, visitor.altsvc_count_); | |
| 325 EXPECT_EQ(altsvc_stream_id, visitor.altsvc_stream_id_); | |
| 326 EXPECT_TRUE(visitor.altsvc_origin_.empty()); | |
| 327 ASSERT_EQ(1u, visitor.altsvc_vector_.size()); | |
| 328 EXPECT_EQ(alternative_service, visitor.altsvc_vector_[0]); | |
| 329 } | |
| 330 | |
| 331 } // namespace net | |
| OLD | NEW |