| 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 | |
| 9 #include <algorithm> | |
| 10 #include <cstdint> | |
| 11 #include <limits> | |
| 12 | |
| 13 #include "base/logging.h" | |
| 14 #include "base/memory/ptr_util.h" | |
| 15 #include "net/spdy/hpack/hpack_constants.h" | |
| 16 #include "net/spdy/mock_spdy_framer_visitor.h" | |
| 17 #include "net/spdy/spdy_frame_builder.h" | |
| 18 #include "net/spdy/spdy_frame_reader.h" | |
| 19 #include "net/spdy/spdy_protocol.h" | |
| 20 #include "net/spdy/spdy_test_utils.h" | |
| 21 | |
| 22 using ::base::MakeUnique; | |
| 23 using ::testing::AssertionFailure; | |
| 24 using ::testing::AssertionResult; | |
| 25 using ::testing::AssertionSuccess; | |
| 26 | |
| 27 namespace net { | |
| 28 namespace test { | |
| 29 | |
| 30 // Specify whether to process headers as request or response in visitor-related | |
| 31 // params. | |
| 32 enum class HeaderDirection { REQUEST, RESPONSE }; | |
| 33 | |
| 34 // Types of HTTP/2 frames, per RFC 7540. | |
| 35 // TODO(jamessynge): Switch to using //net/http2/http2_constants.h when ready. | |
| 36 enum Http2FrameType { | |
| 37 DATA = 0, | |
| 38 HEADERS = 1, | |
| 39 PRIORITY = 2, | |
| 40 RST_STREAM = 3, | |
| 41 SETTINGS = 4, | |
| 42 PUSH_PROMISE = 5, | |
| 43 PING = 6, | |
| 44 GOAWAY = 7, | |
| 45 WINDOW_UPDATE = 8, | |
| 46 CONTINUATION = 9, | |
| 47 ALTSVC = 10, | |
| 48 | |
| 49 // Not a frame type. | |
| 50 UNSET = -1, | |
| 51 UNKNOWN = -2, | |
| 52 }; | |
| 53 | |
| 54 // TODO(jamessynge): Switch to using //net/http2/http2_constants.h when ready. | |
| 55 const char* Http2FrameTypeToString(Http2FrameType v) { | |
| 56 switch (v) { | |
| 57 case DATA: | |
| 58 return "DATA"; | |
| 59 case HEADERS: | |
| 60 return "HEADERS"; | |
| 61 case PRIORITY: | |
| 62 return "PRIORITY"; | |
| 63 case RST_STREAM: | |
| 64 return "RST_STREAM"; | |
| 65 case SETTINGS: | |
| 66 return "SETTINGS"; | |
| 67 case PUSH_PROMISE: | |
| 68 return "PUSH_PROMISE"; | |
| 69 case PING: | |
| 70 return "PING"; | |
| 71 case GOAWAY: | |
| 72 return "GOAWAY"; | |
| 73 case WINDOW_UPDATE: | |
| 74 return "WINDOW_UPDATE"; | |
| 75 case CONTINUATION: | |
| 76 return "CONTINUATION"; | |
| 77 case ALTSVC: | |
| 78 return "ALTSVC"; | |
| 79 case UNSET: | |
| 80 return "UNSET"; | |
| 81 case UNKNOWN: | |
| 82 return "UNKNOWN"; | |
| 83 default: | |
| 84 return "Invalid Http2FrameType"; | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 // TODO(jamessynge): Switch to using //net/http2/http2_constants.h when ready. | |
| 89 inline std::ostream& operator<<(std::ostream& out, Http2FrameType v) { | |
| 90 return out << Http2FrameTypeToString(v); | |
| 91 } | |
| 92 | |
| 93 // Flag bits in the flag field of the common header of HTTP/2 frames | |
| 94 // (see https://httpwg.github.io/specs/rfc7540.html#FrameHeader for details on | |
| 95 // the fixed 9-octet header structure shared by all frames). | |
| 96 // Flag bits are only valid for specified frame types. | |
| 97 // TODO(jamessynge): Switch to using //net/http2/http2_constants.h when ready. | |
| 98 enum Http2HeaderFlag { | |
| 99 NO_FLAGS = 0, | |
| 100 | |
| 101 END_STREAM_FLAG = 0x1, | |
| 102 ACK_FLAG = 0x1, | |
| 103 END_HEADERS_FLAG = 0x4, | |
| 104 PADDED_FLAG = 0x8, | |
| 105 PRIORITY_FLAG = 0x20, | |
| 106 }; | |
| 107 | |
| 108 // Returns name of frame type. | |
| 109 // TODO(jamessynge): Switch to using //net/http2/http2_constants.h when ready. | |
| 110 const char* Http2FrameTypeToString(Http2FrameType v); | |
| 111 | |
| 112 void SpdyDeframerVisitorInterface::OnPingAck( | |
| 113 std::unique_ptr<SpdyPingIR> frame) { | |
| 114 OnPing(std::move(frame)); | |
| 115 } | |
| 116 | |
| 117 void SpdyDeframerVisitorInterface::OnSettingsAck( | |
| 118 std::unique_ptr<SpdySettingsIR> frame) { | |
| 119 OnSettings(std::move(frame), nullptr); | |
| 120 } | |
| 121 | |
| 122 class SpdyTestDeframerImpl : public SpdyTestDeframer, | |
| 123 public SpdyHeadersHandlerInterface { | |
| 124 public: | |
| 125 explicit SpdyTestDeframerImpl( | |
| 126 std::unique_ptr<SpdyDeframerVisitorInterface> listener) | |
| 127 : listener_(std::move(listener)) { | |
| 128 CHECK(listener_); | |
| 129 } | |
| 130 ~SpdyTestDeframerImpl() override {} | |
| 131 | |
| 132 bool AtFrameEnd() override; | |
| 133 | |
| 134 // Callbacks defined in SpdyFramerVisitorInterface. These are in the | |
| 135 // alphabetical order for ease of navigation, and are not in same order | |
| 136 // as in SpdyFramerVisitorInterface. | |
| 137 void OnAltSvc(SpdyStreamId stream_id, | |
| 138 SpdyStringPiece origin, | |
| 139 const SpdyAltSvcWireFormat::AlternativeServiceVector& | |
| 140 altsvc_vector) override; | |
| 141 void OnContinuation(SpdyStreamId stream_id, bool end) override; | |
| 142 SpdyHeadersHandlerInterface* OnHeaderFrameStart( | |
| 143 SpdyStreamId stream_id) override; | |
| 144 void OnHeaderFrameEnd(SpdyStreamId stream_id, bool end_headers) override; | |
| 145 void OnDataFrameHeader(SpdyStreamId stream_id, | |
| 146 size_t length, | |
| 147 bool fin) override; | |
| 148 void OnError(SpdyFramer* framer) override; | |
| 149 void OnGoAway(SpdyStreamId last_accepted_stream_id, | |
| 150 SpdyErrorCode error_code) override; | |
| 151 bool OnGoAwayFrameData(const char* goaway_data, size_t len) override; | |
| 152 void OnHeaders(SpdyStreamId stream_id, | |
| 153 bool has_priority, | |
| 154 int weight, | |
| 155 SpdyStreamId parent_stream_id, | |
| 156 bool exclusive, | |
| 157 bool fin, | |
| 158 bool end) override; | |
| 159 void OnPing(SpdyPingId unique_id, bool is_ack) override; | |
| 160 void OnPriority(SpdyStreamId stream_id, | |
| 161 SpdyStreamId parent_stream_id, | |
| 162 int weight, | |
| 163 bool exclusive) override; | |
| 164 void OnPushPromise(SpdyStreamId stream_id, | |
| 165 SpdyStreamId promised_stream_id, | |
| 166 bool end) override; | |
| 167 void OnRstStream(SpdyStreamId stream_id, SpdyErrorCode error_code) override; | |
| 168 void OnSetting(SpdySettingsIds id, uint32_t value) override; | |
| 169 void OnSettings(bool clear_persisted) override; | |
| 170 void OnSettingsAck() override; | |
| 171 void OnSettingsEnd() override; | |
| 172 void OnStreamFrameData(SpdyStreamId stream_id, | |
| 173 const char* data, | |
| 174 size_t len) override; | |
| 175 void OnStreamEnd(SpdyStreamId stream_id) override; | |
| 176 void OnStreamPadding(SpdyStreamId stream_id, size_t len) override; | |
| 177 bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override; | |
| 178 void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override; | |
| 179 | |
| 180 // Callbacks defined in SpdyHeadersHandlerInterface. | |
| 181 | |
| 182 void OnHeaderBlockStart() override; | |
| 183 void OnHeader(SpdyStringPiece key, SpdyStringPiece value) override; | |
| 184 void OnHeaderBlockEnd(size_t header_bytes_parsed) override; | |
| 185 void OnHeaderBlockEnd(size_t header_bytes_parsed, | |
| 186 size_t compressed_header_bytes_parsed) override; | |
| 187 | |
| 188 protected: | |
| 189 void AtDataEnd(); | |
| 190 void AtGoAwayEnd(); | |
| 191 void AtHeadersEnd(); | |
| 192 void AtPushPromiseEnd(); | |
| 193 | |
| 194 // Per-physical frame state. | |
| 195 // Frame type of the frame currently being processed. | |
| 196 Http2FrameType frame_type_ = UNSET; | |
| 197 // Stream id of the frame currently being processed. | |
| 198 SpdyStreamId stream_id_; | |
| 199 // Did the most recent frame header include the END_HEADERS flag? | |
| 200 bool end_ = false; | |
| 201 // Did the most recent frame header include the ack flag? | |
| 202 bool ack_ = false; | |
| 203 | |
| 204 // Per-HPACK block state. Only valid while processing a HEADERS or | |
| 205 // PUSH_PROMISE frame, and its CONTINUATION frames. | |
| 206 // Did the most recent HEADERS or PUSH_PROMISE include the END_STREAM flag? | |
| 207 // Note that this does not necessarily indicate that the current frame is | |
| 208 // the last frame for the stream (may be followed by CONTINUATION frames, | |
| 209 // may only half close). | |
| 210 bool fin_ = false; | |
| 211 bool got_hpack_end_ = false; | |
| 212 | |
| 213 std::unique_ptr<SpdyString> data_; | |
| 214 | |
| 215 // Total length of the data frame. | |
| 216 size_t data_len_ = 0; | |
| 217 | |
| 218 // Amount of skipped padding (i.e. total length of padding, including Pad | |
| 219 // Length field). | |
| 220 size_t padding_len_ = 0; | |
| 221 | |
| 222 std::unique_ptr<SpdyString> goaway_description_; | |
| 223 std::unique_ptr<StringPairVector> headers_; | |
| 224 std::unique_ptr<SettingVector> settings_; | |
| 225 std::unique_ptr<TestHeadersHandler> headers_handler_; | |
| 226 | |
| 227 std::unique_ptr<SpdyGoAwayIR> goaway_ir_; | |
| 228 std::unique_ptr<SpdyHeadersIR> headers_ir_; | |
| 229 std::unique_ptr<SpdyPushPromiseIR> push_promise_ir_; | |
| 230 std::unique_ptr<SpdySettingsIR> settings_ir_; | |
| 231 | |
| 232 private: | |
| 233 std::unique_ptr<SpdyDeframerVisitorInterface> listener_; | |
| 234 | |
| 235 DISALLOW_COPY_AND_ASSIGN(SpdyTestDeframerImpl); | |
| 236 }; | |
| 237 | |
| 238 // static | |
| 239 std::unique_ptr<SpdyTestDeframer> SpdyTestDeframer::CreateConverter( | |
| 240 std::unique_ptr<SpdyDeframerVisitorInterface> listener) { | |
| 241 return MakeUnique<SpdyTestDeframerImpl>(std::move(listener)); | |
| 242 } | |
| 243 | |
| 244 void SpdyTestDeframerImpl::AtDataEnd() { | |
| 245 DVLOG(1) << "AtDataEnd"; | |
| 246 CHECK_EQ(data_len_, padding_len_ + data_->size()); | |
| 247 auto ptr = MakeUnique<SpdyDataIR>(stream_id_, std::move(*data_)); | |
| 248 CHECK_EQ(0u, data_->size()); | |
| 249 data_.reset(); | |
| 250 | |
| 251 CHECK_LE(0u, padding_len_); | |
| 252 CHECK_LE(padding_len_, 256u); | |
| 253 if (padding_len_ > 0) { | |
| 254 ptr->set_padding_len(padding_len_); | |
| 255 } | |
| 256 padding_len_ = 0; | |
| 257 | |
| 258 ptr->set_fin(fin_); | |
| 259 listener_->OnData(std::move(ptr)); | |
| 260 frame_type_ = UNSET; | |
| 261 fin_ = false; | |
| 262 data_len_ = 0; | |
| 263 } | |
| 264 | |
| 265 void SpdyTestDeframerImpl::AtGoAwayEnd() { | |
| 266 DVLOG(1) << "AtDataEnd"; | |
| 267 CHECK_EQ(frame_type_, GOAWAY); | |
| 268 CHECK(goaway_description_); | |
| 269 if (goaway_description_->empty()) { | |
| 270 listener_->OnGoAway(std::move(goaway_ir_)); | |
| 271 } else { | |
| 272 listener_->OnGoAway(MakeUnique<SpdyGoAwayIR>( | |
| 273 goaway_ir_->last_good_stream_id(), goaway_ir_->error_code(), | |
| 274 std::move(*goaway_description_))); | |
| 275 CHECK_EQ(0u, goaway_description_->size()); | |
| 276 } | |
| 277 goaway_description_.reset(); | |
| 278 goaway_ir_.reset(); | |
| 279 frame_type_ = UNSET; | |
| 280 } | |
| 281 | |
| 282 void SpdyTestDeframerImpl::AtHeadersEnd() { | |
| 283 DVLOG(1) << "AtDataEnd"; | |
| 284 CHECK(frame_type_ == HEADERS || frame_type_ == CONTINUATION) | |
| 285 << " frame_type_=" << Http2FrameTypeToString(frame_type_); | |
| 286 CHECK(end_) << " frame_type_=" << Http2FrameTypeToString(frame_type_); | |
| 287 CHECK(got_hpack_end_); | |
| 288 | |
| 289 CHECK(headers_ir_); | |
| 290 CHECK(headers_); | |
| 291 CHECK(headers_handler_); | |
| 292 | |
| 293 CHECK_LE(0u, padding_len_); | |
| 294 CHECK_LE(padding_len_, 256u); | |
| 295 if (padding_len_ > 0) { | |
| 296 headers_ir_->set_padding_len(padding_len_); | |
| 297 } | |
| 298 padding_len_ = 0; | |
| 299 | |
| 300 headers_ir_->set_header_block(headers_handler_->decoded_block().Clone()); | |
| 301 headers_handler_.reset(); | |
| 302 listener_->OnHeaders(std::move(headers_ir_), std::move(headers_)); | |
| 303 | |
| 304 frame_type_ = UNSET; | |
| 305 fin_ = false; | |
| 306 end_ = false; | |
| 307 got_hpack_end_ = false; | |
| 308 } | |
| 309 | |
| 310 void SpdyTestDeframerImpl::AtPushPromiseEnd() { | |
| 311 DVLOG(1) << "AtDataEnd"; | |
| 312 CHECK(frame_type_ == PUSH_PROMISE || frame_type_ == CONTINUATION) | |
| 313 << " frame_type_=" << Http2FrameTypeToString(frame_type_); | |
| 314 CHECK(end_) << " frame_type_=" << Http2FrameTypeToString(frame_type_); | |
| 315 | |
| 316 CHECK(push_promise_ir_); | |
| 317 CHECK(headers_); | |
| 318 CHECK(headers_handler_); | |
| 319 | |
| 320 CHECK_EQ(headers_ir_.get(), nullptr); | |
| 321 | |
| 322 CHECK_LE(0u, padding_len_); | |
| 323 CHECK_LE(padding_len_, 256u); | |
| 324 if (padding_len_ > 0) { | |
| 325 push_promise_ir_->set_padding_len(padding_len_); | |
| 326 } | |
| 327 padding_len_ = 0; | |
| 328 | |
| 329 push_promise_ir_->set_header_block(headers_handler_->decoded_block().Clone()); | |
| 330 headers_handler_.reset(); | |
| 331 listener_->OnPushPromise(std::move(push_promise_ir_), std::move(headers_)); | |
| 332 | |
| 333 frame_type_ = UNSET; | |
| 334 end_ = false; | |
| 335 } | |
| 336 | |
| 337 bool SpdyTestDeframerImpl::AtFrameEnd() { | |
| 338 bool incomplete_logical_header = false; | |
| 339 // The caller says that the SpdyFrame has reached the end of the frame, | |
| 340 // so if we have any accumulated data, flush it. | |
| 341 switch (frame_type_) { | |
| 342 case DATA: | |
| 343 AtDataEnd(); | |
| 344 break; | |
| 345 | |
| 346 case GOAWAY: | |
| 347 AtGoAwayEnd(); | |
| 348 break; | |
| 349 | |
| 350 case HEADERS: | |
| 351 if (end_) { | |
| 352 AtHeadersEnd(); | |
| 353 } else { | |
| 354 incomplete_logical_header = true; | |
| 355 } | |
| 356 break; | |
| 357 | |
| 358 case PUSH_PROMISE: | |
| 359 if (end_) { | |
| 360 AtPushPromiseEnd(); | |
| 361 } else { | |
| 362 incomplete_logical_header = true; | |
| 363 } | |
| 364 break; | |
| 365 | |
| 366 case CONTINUATION: | |
| 367 if (end_) { | |
| 368 if (headers_ir_) { | |
| 369 AtHeadersEnd(); | |
| 370 } else if (push_promise_ir_) { | |
| 371 AtPushPromiseEnd(); | |
| 372 } else { | |
| 373 LOG(FATAL) << "Where is the SpdyFrameIR for the headers!"; | |
| 374 } | |
| 375 } else { | |
| 376 incomplete_logical_header = true; | |
| 377 } | |
| 378 break; | |
| 379 | |
| 380 case UNSET: | |
| 381 // Except for the frame types above, the others don't leave any record | |
| 382 // in the state of this object. Make sure nothing got left by accident. | |
| 383 CHECK_EQ(data_.get(), nullptr); | |
| 384 CHECK_EQ(goaway_description_.get(), nullptr); | |
| 385 CHECK_EQ(goaway_ir_.get(), nullptr); | |
| 386 CHECK_EQ(headers_.get(), nullptr); | |
| 387 CHECK_EQ(headers_handler_.get(), nullptr); | |
| 388 CHECK_EQ(headers_ir_.get(), nullptr); | |
| 389 CHECK_EQ(push_promise_ir_.get(), nullptr); | |
| 390 CHECK_EQ(settings_.get(), nullptr); | |
| 391 CHECK_EQ(settings_ir_.get(), nullptr); | |
| 392 break; | |
| 393 | |
| 394 default: | |
| 395 SPDY_BUG << "Expected UNSET, instead frame_type_==" << frame_type_; | |
| 396 return false; | |
| 397 } | |
| 398 frame_type_ = UNSET; | |
| 399 stream_id_ = 0; | |
| 400 end_ = false; | |
| 401 ack_ = false; | |
| 402 if (!incomplete_logical_header) { | |
| 403 fin_ = false; | |
| 404 } | |
| 405 return true; | |
| 406 } | |
| 407 | |
| 408 // Overridden methods from SpdyFramerVisitorInterface in alpha order... | |
| 409 | |
| 410 void SpdyTestDeframerImpl::OnAltSvc( | |
| 411 SpdyStreamId stream_id, | |
| 412 SpdyStringPiece origin, | |
| 413 const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) { | |
| 414 DVLOG(1) << "OnAltSvc stream_id: " << stream_id; | |
| 415 CHECK_EQ(frame_type_, UNSET) << " frame_type_=" | |
| 416 << Http2FrameTypeToString(frame_type_); | |
| 417 CHECK_GT(stream_id, 0u); | |
| 418 auto ptr = MakeUnique<SpdyAltSvcIR>(stream_id); | |
| 419 ptr->set_origin(SpdyString(origin)); | |
| 420 for (auto& altsvc : altsvc_vector) { | |
| 421 ptr->add_altsvc(altsvc); | |
| 422 } | |
| 423 listener_->OnAltSvc(std::move(ptr)); | |
| 424 } | |
| 425 | |
| 426 // A CONTINUATION frame contains a Header Block Fragment, and immediately | |
| 427 // follows another frame that contains a Header Block Fragment (HEADERS, | |
| 428 // PUSH_PROMISE or CONTINUATION). The last such frame has the END flag set. | |
| 429 // SpdyFramer ensures that the behavior is correct before calling the visitor. | |
| 430 void SpdyTestDeframerImpl::OnContinuation(SpdyStreamId stream_id, bool end) { | |
| 431 DVLOG(1) << "OnContinuation stream_id: " << stream_id; | |
| 432 CHECK_EQ(frame_type_, UNSET) << " frame_type_=" | |
| 433 << Http2FrameTypeToString(frame_type_); | |
| 434 CHECK_GT(stream_id, 0u); | |
| 435 CHECK_NE(nullptr, headers_.get()); | |
| 436 frame_type_ = CONTINUATION; | |
| 437 | |
| 438 stream_id_ = stream_id; | |
| 439 end_ = end; | |
| 440 } | |
| 441 | |
| 442 // Note that length includes the padding length (0 to 256, when the optional | |
| 443 // padding length field is counted). Padding comes after the payload, both | |
| 444 // for DATA frames and for control frames. | |
| 445 void SpdyTestDeframerImpl::OnDataFrameHeader(SpdyStreamId stream_id, | |
| 446 size_t length, | |
| 447 bool fin) { | |
| 448 DVLOG(1) << "OnDataFrameHeader stream_id: " << stream_id; | |
| 449 CHECK_EQ(frame_type_, UNSET) << " frame_type_=" | |
| 450 << Http2FrameTypeToString(frame_type_); | |
| 451 CHECK_GT(stream_id, 0u); | |
| 452 CHECK_EQ(data_.get(), nullptr); | |
| 453 frame_type_ = DATA; | |
| 454 | |
| 455 stream_id_ = stream_id; | |
| 456 fin_ = fin; | |
| 457 data_len_ = length; | |
| 458 data_.reset(new SpdyString()); | |
| 459 } | |
| 460 | |
| 461 // The SpdyFramer will not process any more data at this point. | |
| 462 void SpdyTestDeframerImpl::OnError(SpdyFramer* framer) { | |
| 463 DVLOG(1) << "SpdyFramer detected an error in the stream: " | |
| 464 << SpdyFramer::SpdyFramerErrorToString(framer->spdy_framer_error()) | |
| 465 << " frame_type_: " << Http2FrameTypeToString(frame_type_); | |
| 466 listener_->OnError(framer, this); | |
| 467 } | |
| 468 | |
| 469 // Received a GOAWAY frame from the peer. The last stream id it accepted from us | |
| 470 // is |last_accepted_stream_id|. |status| is a protocol defined error code. | |
| 471 // The frame may also contain data. After this OnGoAwayFrameData will be called | |
| 472 // for any non-zero amount of data, and after that it will be called with len==0 | |
| 473 // to indicate the end of the GOAWAY frame. | |
| 474 void SpdyTestDeframerImpl::OnGoAway(SpdyStreamId last_good_stream_id, | |
| 475 SpdyErrorCode error_code) { | |
| 476 DVLOG(1) << "OnGoAway last_good_stream_id: " << last_good_stream_id | |
| 477 << " error code: " << error_code; | |
| 478 CHECK_EQ(frame_type_, UNSET) << " frame_type_=" | |
| 479 << Http2FrameTypeToString(frame_type_); | |
| 480 frame_type_ = GOAWAY; | |
| 481 goaway_ir_ = MakeUnique<SpdyGoAwayIR>(last_good_stream_id, error_code, ""); | |
| 482 goaway_description_.reset(new SpdyString()); | |
| 483 } | |
| 484 | |
| 485 // If len==0 then we've reached the end of the GOAWAY frame. | |
| 486 bool SpdyTestDeframerImpl::OnGoAwayFrameData(const char* goaway_data, | |
| 487 size_t len) { | |
| 488 DVLOG(1) << "OnGoAwayFrameData"; | |
| 489 CHECK_EQ(frame_type_, GOAWAY) << " frame_type_=" | |
| 490 << Http2FrameTypeToString(frame_type_); | |
| 491 CHECK(goaway_description_); | |
| 492 goaway_description_->append(goaway_data, len); | |
| 493 return true; | |
| 494 } | |
| 495 | |
| 496 SpdyHeadersHandlerInterface* SpdyTestDeframerImpl::OnHeaderFrameStart( | |
| 497 SpdyStreamId stream_id) { | |
| 498 return this; | |
| 499 } | |
| 500 | |
| 501 void SpdyTestDeframerImpl::OnHeaderFrameEnd(SpdyStreamId stream_id, | |
| 502 bool end_headers) { | |
| 503 DVLOG(1) << "OnHeaderFrameEnd stream_id: " << stream_id | |
| 504 << " end_headers: " << (end_headers ? "true" : "false"); | |
| 505 } | |
| 506 | |
| 507 // Received the fixed portion of a HEADERS frame. Called before the variable | |
| 508 // length (including zero length) Header Block Fragment is processed. If fin | |
| 509 // is true then there will be no DATA or trailing HEADERS after this HEADERS | |
| 510 // frame. | |
| 511 // If end is true, then there will be no CONTINUATION frame(s) following this | |
| 512 // frame; else if true then there will be CONTINATION frames(s) immediately | |
| 513 // following this frame, terminated by a CONTINUATION frame with end==true. | |
| 514 void SpdyTestDeframerImpl::OnHeaders(SpdyStreamId stream_id, | |
| 515 bool has_priority, | |
| 516 int weight, | |
| 517 SpdyStreamId parent_stream_id, | |
| 518 bool exclusive, | |
| 519 bool fin, | |
| 520 bool end) { | |
| 521 DVLOG(1) << "OnHeaders stream_id: " << stream_id; | |
| 522 CHECK_EQ(frame_type_, UNSET) << " frame_type_=" | |
| 523 << Http2FrameTypeToString(frame_type_); | |
| 524 CHECK_GT(stream_id, 0u); | |
| 525 frame_type_ = HEADERS; | |
| 526 | |
| 527 stream_id_ = stream_id; | |
| 528 fin_ = fin; | |
| 529 end_ = end; | |
| 530 | |
| 531 headers_.reset(new StringPairVector()); | |
| 532 headers_handler_.reset(new TestHeadersHandler()); | |
| 533 headers_ir_ = MakeUnique<SpdyHeadersIR>(stream_id); | |
| 534 headers_ir_->set_fin(fin); | |
| 535 if (has_priority) { | |
| 536 headers_ir_->set_has_priority(true); | |
| 537 headers_ir_->set_weight(weight); | |
| 538 headers_ir_->set_parent_stream_id(parent_stream_id); | |
| 539 headers_ir_->set_exclusive(exclusive); | |
| 540 } | |
| 541 } | |
| 542 | |
| 543 // The HTTP/2 protocol refers to the payload, |unique_id| here, as 8 octets of | |
| 544 // opaque data that is to be echoed back to the sender, with the ACK bit added. | |
| 545 // It isn't defined as a counter, | |
| 546 // or frame id, as the SpdyPingId naming might imply. | |
| 547 // Responding to a PING is supposed to be at the highest priority. | |
| 548 void SpdyTestDeframerImpl::OnPing(uint64_t unique_id, bool is_ack) { | |
| 549 DVLOG(1) << "OnPing unique_id: " << unique_id | |
| 550 << " is_ack: " << (is_ack ? "true" : "false"); | |
| 551 CHECK_EQ(frame_type_, UNSET) << " frame_type_=" | |
| 552 << Http2FrameTypeToString(frame_type_); | |
| 553 auto ptr = MakeUnique<SpdyPingIR>(unique_id); | |
| 554 if (is_ack) { | |
| 555 ptr->set_is_ack(is_ack); | |
| 556 listener_->OnPingAck(std::move(ptr)); | |
| 557 } else { | |
| 558 listener_->OnPing(std::move(ptr)); | |
| 559 } | |
| 560 } | |
| 561 | |
| 562 void SpdyTestDeframerImpl::OnPriority(SpdyStreamId stream_id, | |
| 563 SpdyStreamId parent_stream_id, | |
| 564 int weight, | |
| 565 bool exclusive) { | |
| 566 DVLOG(1) << "OnPriority stream_id: " << stream_id; | |
| 567 CHECK_EQ(frame_type_, UNSET) << " frame_type_=" | |
| 568 << Http2FrameTypeToString(frame_type_); | |
| 569 CHECK_GT(stream_id, 0u); | |
| 570 | |
| 571 listener_->OnPriority(MakeUnique<SpdyPriorityIR>(stream_id, parent_stream_id, | |
| 572 weight, exclusive)); | |
| 573 } | |
| 574 | |
| 575 void SpdyTestDeframerImpl::OnPushPromise(SpdyStreamId stream_id, | |
| 576 SpdyStreamId promised_stream_id, | |
| 577 bool end) { | |
| 578 DVLOG(1) << "OnPushPromise stream_id: " << stream_id; | |
| 579 CHECK_EQ(frame_type_, UNSET) << " frame_type_=" | |
| 580 << Http2FrameTypeToString(frame_type_); | |
| 581 CHECK_GT(stream_id, 0u); | |
| 582 | |
| 583 frame_type_ = PUSH_PROMISE; | |
| 584 stream_id_ = stream_id; | |
| 585 end_ = end; | |
| 586 | |
| 587 headers_.reset(new StringPairVector()); | |
| 588 headers_handler_.reset(new TestHeadersHandler()); | |
| 589 push_promise_ir_ = | |
| 590 MakeUnique<SpdyPushPromiseIR>(stream_id, promised_stream_id); | |
| 591 } | |
| 592 | |
| 593 // Closes the specified stream. After this the sender may still send PRIORITY | |
| 594 // frames for this stream, which we can ignore. | |
| 595 void SpdyTestDeframerImpl::OnRstStream(SpdyStreamId stream_id, | |
| 596 SpdyErrorCode error_code) { | |
| 597 DVLOG(1) << "OnRstStream stream_id: " << stream_id | |
| 598 << " error code: " << error_code; | |
| 599 CHECK_EQ(frame_type_, UNSET) << " frame_type_=" | |
| 600 << Http2FrameTypeToString(frame_type_); | |
| 601 CHECK_GT(stream_id, 0u); | |
| 602 | |
| 603 listener_->OnRstStream(MakeUnique<SpdyRstStreamIR>(stream_id, error_code)); | |
| 604 } | |
| 605 | |
| 606 // Called for an individual setting. There is no negotiation, the sender is | |
| 607 // stating the value that the sender is using. | |
| 608 void SpdyTestDeframerImpl::OnSetting(SpdySettingsIds id, uint32_t value) { | |
| 609 DVLOG(1) << "OnSetting id: " << id << std::hex << " value: " << value; | |
| 610 CHECK_EQ(frame_type_, SETTINGS) << " frame_type_=" | |
| 611 << Http2FrameTypeToString(frame_type_); | |
| 612 CHECK(settings_); | |
| 613 settings_->push_back(std::make_pair(id, value)); | |
| 614 settings_ir_->AddSetting(id, value); | |
| 615 } | |
| 616 | |
| 617 // Called at the start of a SETTINGS frame with setting entries, but not the | |
| 618 // (required) ACK of a SETTINGS frame. There is no stream_id because | |
| 619 // the settings apply to the entire connection, not to an individual stream. | |
| 620 // The |clear_persisted| flag is a pre-HTTP/2 remnant. | |
| 621 void SpdyTestDeframerImpl::OnSettings(bool /*clear_persisted*/) { | |
| 622 DVLOG(1) << "OnSettings"; | |
| 623 CHECK_EQ(frame_type_, UNSET) << " frame_type_=" | |
| 624 << Http2FrameTypeToString(frame_type_); | |
| 625 CHECK_EQ(nullptr, settings_ir_.get()); | |
| 626 CHECK_EQ(nullptr, settings_.get()); | |
| 627 frame_type_ = SETTINGS; | |
| 628 ack_ = false; | |
| 629 | |
| 630 settings_.reset(new SettingVector()); | |
| 631 settings_ir_.reset(new SpdySettingsIR()); | |
| 632 } | |
| 633 | |
| 634 void SpdyTestDeframerImpl::OnSettingsAck() { | |
| 635 DVLOG(1) << "OnSettingsAck"; | |
| 636 CHECK_EQ(frame_type_, UNSET) << " frame_type_=" | |
| 637 << Http2FrameTypeToString(frame_type_); | |
| 638 auto ptr = MakeUnique<SpdySettingsIR>(); | |
| 639 ptr->set_is_ack(true); | |
| 640 listener_->OnSettingsAck(std::move(ptr)); | |
| 641 } | |
| 642 | |
| 643 void SpdyTestDeframerImpl::OnSettingsEnd() { | |
| 644 DVLOG(1) << "OnSettingsEnd"; | |
| 645 CHECK_EQ(frame_type_, SETTINGS) << " frame_type_=" | |
| 646 << Http2FrameTypeToString(frame_type_); | |
| 647 CHECK(!ack_); | |
| 648 CHECK_NE(nullptr, settings_ir_.get()); | |
| 649 CHECK_NE(nullptr, settings_.get()); | |
| 650 listener_->OnSettings(std::move(settings_ir_), std::move(settings_)); | |
| 651 frame_type_ = UNSET; | |
| 652 } | |
| 653 | |
| 654 // Called for a zero length DATA frame with the END_STREAM flag set, or at the | |
| 655 // end a complete HPACK block (and its padding) that started with a HEADERS | |
| 656 // frame with the END_STREAM flag set. Doesn't apply to PUSH_PROMISE frames | |
| 657 // because they don't have END_STREAM flags. | |
| 658 void SpdyTestDeframerImpl::OnStreamEnd(SpdyStreamId stream_id) { | |
| 659 DVLOG(1) << "OnStreamEnd stream_id: " << stream_id; | |
| 660 CHECK_EQ(stream_id_, stream_id); | |
| 661 CHECK(frame_type_ == DATA || frame_type_ == HEADERS || | |
| 662 frame_type_ == CONTINUATION) | |
| 663 << " frame_type_=" << Http2FrameTypeToString(frame_type_); | |
| 664 CHECK(fin_); | |
| 665 } | |
| 666 | |
| 667 // The data arg points into the non-padding payload of a DATA frame. | |
| 668 // This must be a DATA frame (i.e. this method will not be | |
| 669 // called for HEADERS or CONTINUATION frames). | |
| 670 // This method may be called multiple times for a single DATA frame, depending | |
| 671 // upon buffer boundaries. | |
| 672 void SpdyTestDeframerImpl::OnStreamFrameData(SpdyStreamId stream_id, | |
| 673 const char* data, | |
| 674 size_t len) { | |
| 675 DVLOG(1) << "OnStreamFrameData stream_id: " << stream_id | |
| 676 << " len: " << len; | |
| 677 CHECK_EQ(stream_id_, stream_id); | |
| 678 CHECK_EQ(frame_type_, DATA); | |
| 679 data_->append(data, len); | |
| 680 } | |
| 681 | |
| 682 // Called when padding is skipped over, including the padding length field at | |
| 683 // the start of the frame payload, and the actual padding at the end. len will | |
| 684 // be in the range 1 to 255. | |
| 685 void SpdyTestDeframerImpl::OnStreamPadding(SpdyStreamId stream_id, size_t len) { | |
| 686 DVLOG(1) << "OnStreamPadding stream_id: " << stream_id << " len: " << len; | |
| 687 CHECK(frame_type_ == DATA || frame_type_ == HEADERS || | |
| 688 frame_type_ == PUSH_PROMISE) | |
| 689 << " frame_type_=" << Http2FrameTypeToString(frame_type_); | |
| 690 CHECK_EQ(stream_id_, stream_id); | |
| 691 CHECK_LE(1u, len); | |
| 692 CHECK_GE(255u, len); | |
| 693 padding_len_ += len; | |
| 694 CHECK_LE(padding_len_, 256u) << "len=" << len; | |
| 695 } | |
| 696 | |
| 697 // WINDOW_UPDATE is supposed to be hop-by-hop, according to the spec. | |
| 698 // stream_id is 0 if the update applies to the connection, else stream_id | |
| 699 // will be the id of a stream previously seen, which maybe half or fully | |
| 700 // closed. | |
| 701 void SpdyTestDeframerImpl::OnWindowUpdate(SpdyStreamId stream_id, | |
| 702 int delta_window_size) { | |
| 703 DVLOG(1) << "OnWindowUpdate stream_id: " << stream_id | |
| 704 << " delta_window_size: " << delta_window_size; | |
| 705 CHECK_EQ(frame_type_, UNSET) << " frame_type_=" | |
| 706 << Http2FrameTypeToString(frame_type_); | |
| 707 CHECK_NE(0, delta_window_size); | |
| 708 | |
| 709 listener_->OnWindowUpdate( | |
| 710 MakeUnique<SpdyWindowUpdateIR>(stream_id, delta_window_size)); | |
| 711 } | |
| 712 | |
| 713 // Return true to indicate that the stream_id is valid; if not valid then | |
| 714 // SpdyFramer considers the connection corrupted. Requires keeping track | |
| 715 // of the set of currently open streams. For now we'll assume that unknown | |
| 716 // frame types are unsupported. | |
| 717 bool SpdyTestDeframerImpl::OnUnknownFrame(SpdyStreamId stream_id, | |
| 718 uint8_t frame_type) { | |
| 719 DVLOG(1) << "OnAltSvc stream_id: " << stream_id; | |
| 720 CHECK_EQ(frame_type_, UNSET) << " frame_type_=" | |
| 721 << Http2FrameTypeToString(frame_type_); | |
| 722 frame_type_ = UNKNOWN; | |
| 723 | |
| 724 stream_id_ = stream_id; | |
| 725 return false; | |
| 726 } | |
| 727 | |
| 728 // Callbacks defined in SpdyHeadersHandlerInterface. | |
| 729 | |
| 730 void SpdyTestDeframerImpl::OnHeaderBlockStart() { | |
| 731 CHECK(frame_type_ == HEADERS || frame_type_ == PUSH_PROMISE) | |
| 732 << " frame_type_=" << Http2FrameTypeToString(frame_type_); | |
| 733 CHECK(headers_); | |
| 734 CHECK_EQ(0u, headers_->size()); | |
| 735 got_hpack_end_ = false; | |
| 736 } | |
| 737 | |
| 738 void SpdyTestDeframerImpl::OnHeader(SpdyStringPiece key, | |
| 739 SpdyStringPiece value) { | |
| 740 CHECK(frame_type_ == HEADERS || frame_type_ == CONTINUATION || | |
| 741 frame_type_ == PUSH_PROMISE) | |
| 742 << " frame_type_=" << Http2FrameTypeToString(frame_type_); | |
| 743 CHECK(!got_hpack_end_); | |
| 744 CHECK(headers_); | |
| 745 headers_->emplace_back(SpdyString(key), SpdyString(value)); | |
| 746 CHECK(headers_handler_); | |
| 747 headers_handler_->OnHeader(key, value); | |
| 748 } | |
| 749 | |
| 750 void SpdyTestDeframerImpl::OnHeaderBlockEnd(size_t header_bytes_parsed) { | |
| 751 CHECK(headers_); | |
| 752 CHECK(frame_type_ == HEADERS || frame_type_ == CONTINUATION || | |
| 753 frame_type_ == PUSH_PROMISE) | |
| 754 << " frame_type_=" << Http2FrameTypeToString(frame_type_); | |
| 755 CHECK(end_); | |
| 756 CHECK(!got_hpack_end_); | |
| 757 got_hpack_end_ = true; | |
| 758 } | |
| 759 | |
| 760 void SpdyTestDeframerImpl::OnHeaderBlockEnd( | |
| 761 size_t /* header_bytes_parsed */, | |
| 762 size_t /* compressed_header_bytes_parsed */) { | |
| 763 CHECK(headers_); | |
| 764 CHECK(frame_type_ == HEADERS || frame_type_ == CONTINUATION || | |
| 765 frame_type_ == PUSH_PROMISE) | |
| 766 << " frame_type_=" << Http2FrameTypeToString(frame_type_); | |
| 767 CHECK(end_); | |
| 768 CHECK(!got_hpack_end_); | |
| 769 got_hpack_end_ = true; | |
| 770 } | |
| 771 | |
| 772 class LoggingSpdyDeframerDelegate : public SpdyDeframerVisitorInterface { | |
| 773 public: | |
| 774 explicit LoggingSpdyDeframerDelegate( | |
| 775 std::unique_ptr<SpdyDeframerVisitorInterface> wrapped) | |
| 776 : wrapped_(std::move(wrapped)) { | |
| 777 if (!wrapped_) { | |
| 778 wrapped_ = MakeUnique<SpdyDeframerVisitorInterface>(); | |
| 779 } | |
| 780 } | |
| 781 ~LoggingSpdyDeframerDelegate() override {} | |
| 782 | |
| 783 void OnAltSvc(std::unique_ptr<SpdyAltSvcIR> frame) override { | |
| 784 DVLOG(1) << "LoggingSpdyDeframerDelegate::OnAltSvc"; | |
| 785 wrapped_->OnAltSvc(std::move(frame)); | |
| 786 } | |
| 787 void OnData(std::unique_ptr<SpdyDataIR> frame) override { | |
| 788 DVLOG(1) << "LoggingSpdyDeframerDelegate::OnData"; | |
| 789 wrapped_->OnData(std::move(frame)); | |
| 790 } | |
| 791 void OnGoAway(std::unique_ptr<SpdyGoAwayIR> frame) override { | |
| 792 DVLOG(1) << "LoggingSpdyDeframerDelegate::OnGoAway"; | |
| 793 wrapped_->OnGoAway(std::move(frame)); | |
| 794 } | |
| 795 | |
| 796 // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which | |
| 797 // significantly modifies the headers, so the actual header entries (name | |
| 798 // and value strings) are provided in a vector. | |
| 799 void OnHeaders(std::unique_ptr<SpdyHeadersIR> frame, | |
| 800 std::unique_ptr<StringPairVector> headers) override { | |
| 801 DVLOG(1) << "LoggingSpdyDeframerDelegate::OnHeaders"; | |
| 802 wrapped_->OnHeaders(std::move(frame), std::move(headers)); | |
| 803 } | |
| 804 | |
| 805 void OnPing(std::unique_ptr<SpdyPingIR> frame) override { | |
| 806 DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPing"; | |
| 807 wrapped_->OnPing(std::move(frame)); | |
| 808 } | |
| 809 void OnPingAck(std::unique_ptr<SpdyPingIR> frame) override { | |
| 810 DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPingAck"; | |
| 811 wrapped_->OnPingAck(std::move(frame)); | |
| 812 } | |
| 813 | |
| 814 void OnPriority(std::unique_ptr<SpdyPriorityIR> frame) override { | |
| 815 DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPriority"; | |
| 816 wrapped_->OnPriority(std::move(frame)); | |
| 817 } | |
| 818 | |
| 819 // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which | |
| 820 // significantly modifies the headers, so the actual header entries (name | |
| 821 // and value strings) are provided in a vector. | |
| 822 void OnPushPromise(std::unique_ptr<SpdyPushPromiseIR> frame, | |
| 823 std::unique_ptr<StringPairVector> headers) override { | |
| 824 DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPushPromise"; | |
| 825 wrapped_->OnPushPromise(std::move(frame), std::move(headers)); | |
| 826 } | |
| 827 | |
| 828 void OnRstStream(std::unique_ptr<SpdyRstStreamIR> frame) override { | |
| 829 DVLOG(1) << "LoggingSpdyDeframerDelegate::OnRstStream"; | |
| 830 wrapped_->OnRstStream(std::move(frame)); | |
| 831 } | |
| 832 | |
| 833 // SpdySettingsIR has a map for settings, so loses info about the order of | |
| 834 // settings, and whether the same setting appeared more than once, so the | |
| 835 // the actual settings (parameter and value) are provided in a vector. | |
| 836 void OnSettings(std::unique_ptr<SpdySettingsIR> frame, | |
| 837 std::unique_ptr<SettingVector> settings) override { | |
| 838 DVLOG(1) << "LoggingSpdyDeframerDelegate::OnSettings"; | |
| 839 wrapped_->OnSettings(std::move(frame), std::move(settings)); | |
| 840 } | |
| 841 | |
| 842 // A settings frame with an ACK has no content, but for uniformity passing | |
| 843 // a frame with the ACK flag set. | |
| 844 void OnSettingsAck(std::unique_ptr<SpdySettingsIR> frame) override { | |
| 845 DVLOG(1) << "LoggingSpdyDeframerDelegate::OnSettingsAck"; | |
| 846 wrapped_->OnSettingsAck(std::move(frame)); | |
| 847 } | |
| 848 | |
| 849 void OnWindowUpdate(std::unique_ptr<SpdyWindowUpdateIR> frame) override { | |
| 850 DVLOG(1) << "LoggingSpdyDeframerDelegate::OnWindowUpdate"; | |
| 851 wrapped_->OnWindowUpdate(std::move(frame)); | |
| 852 } | |
| 853 | |
| 854 // The SpdyFramer will not process any more data at this point. | |
| 855 void OnError(SpdyFramer* framer, SpdyTestDeframer* deframer) override { | |
| 856 DVLOG(1) << "LoggingSpdyDeframerDelegate::OnError"; | |
| 857 wrapped_->OnError(framer, deframer); | |
| 858 } | |
| 859 | |
| 860 private: | |
| 861 std::unique_ptr<SpdyDeframerVisitorInterface> wrapped_; | |
| 862 }; | |
| 863 | |
| 864 // static | |
| 865 std::unique_ptr<SpdyDeframerVisitorInterface> | |
| 866 SpdyDeframerVisitorInterface::LogBeforeVisiting( | |
| 867 std::unique_ptr<SpdyDeframerVisitorInterface> wrapped_listener) { | |
| 868 return MakeUnique<LoggingSpdyDeframerDelegate>(std::move(wrapped_listener)); | |
| 869 } | |
| 870 | |
| 871 CollectedFrame::CollectedFrame() {} | |
| 872 | |
| 873 CollectedFrame::CollectedFrame(CollectedFrame&& other) | |
| 874 : frame_ir(std::move(other.frame_ir)), | |
| 875 headers(std::move(other.headers)), | |
| 876 settings(std::move(other.settings)), | |
| 877 error_reported(other.error_reported) {} | |
| 878 | |
| 879 CollectedFrame::~CollectedFrame() {} | |
| 880 | |
| 881 CollectedFrame& CollectedFrame::operator=(CollectedFrame&& other) { | |
| 882 frame_ir = std::move(other.frame_ir); | |
| 883 headers = std::move(other.headers); | |
| 884 settings = std::move(other.settings); | |
| 885 error_reported = other.error_reported; | |
| 886 return *this; | |
| 887 } | |
| 888 | |
| 889 AssertionResult CollectedFrame::VerifyHasHeaders( | |
| 890 const StringPairVector& expected_headers) const { | |
| 891 if (headers.get() == nullptr) | |
| 892 return AssertionFailure(); | |
| 893 if (*headers != expected_headers) | |
| 894 return AssertionFailure(); | |
| 895 | |
| 896 return AssertionSuccess(); | |
| 897 } | |
| 898 | |
| 899 AssertionResult CollectedFrame::VerifyHasSettings( | |
| 900 const SettingVector& expected_settings) const { | |
| 901 if (settings.get() == nullptr) | |
| 902 return AssertionFailure(); | |
| 903 if (*settings != expected_settings) | |
| 904 return AssertionFailure(); | |
| 905 | |
| 906 return AssertionSuccess(); | |
| 907 } | |
| 908 | |
| 909 DeframerCallbackCollector::DeframerCallbackCollector( | |
| 910 std::vector<CollectedFrame>* collected_frames) | |
| 911 : collected_frames_(collected_frames) { | |
| 912 CHECK(collected_frames); | |
| 913 } | |
| 914 | |
| 915 void DeframerCallbackCollector::OnAltSvc( | |
| 916 std::unique_ptr<SpdyAltSvcIR> frame_ir) { | |
| 917 CollectedFrame cf; | |
| 918 cf.frame_ir = std::move(frame_ir); | |
| 919 collected_frames_->push_back(std::move(cf)); | |
| 920 } | |
| 921 void DeframerCallbackCollector::OnData(std::unique_ptr<SpdyDataIR> frame_ir) { | |
| 922 CollectedFrame cf; | |
| 923 cf.frame_ir = std::move(frame_ir); | |
| 924 collected_frames_->push_back(std::move(cf)); | |
| 925 } | |
| 926 void DeframerCallbackCollector::OnGoAway( | |
| 927 std::unique_ptr<SpdyGoAwayIR> frame_ir) { | |
| 928 CollectedFrame cf; | |
| 929 cf.frame_ir = std::move(frame_ir); | |
| 930 collected_frames_->push_back(std::move(cf)); | |
| 931 } | |
| 932 | |
| 933 // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which | |
| 934 // significantly modifies the headers, so the actual header entries (name | |
| 935 // and value strings) are provided in a vector. | |
| 936 void DeframerCallbackCollector::OnHeaders( | |
| 937 std::unique_ptr<SpdyHeadersIR> frame_ir, | |
| 938 std::unique_ptr<StringPairVector> headers) { | |
| 939 CollectedFrame cf; | |
| 940 cf.frame_ir = std::move(frame_ir); | |
| 941 cf.headers = std::move(headers); | |
| 942 collected_frames_->push_back(std::move(cf)); | |
| 943 } | |
| 944 | |
| 945 void DeframerCallbackCollector::OnPing(std::unique_ptr<SpdyPingIR> frame_ir) { | |
| 946 EXPECT_TRUE(frame_ir && !frame_ir->is_ack()); | |
| 947 CollectedFrame cf; | |
| 948 cf.frame_ir = std::move(frame_ir); | |
| 949 collected_frames_->push_back(std::move(cf)); | |
| 950 } | |
| 951 | |
| 952 void DeframerCallbackCollector::OnPingAck( | |
| 953 std::unique_ptr<SpdyPingIR> frame_ir) { | |
| 954 EXPECT_TRUE(frame_ir && frame_ir->is_ack()); | |
| 955 CollectedFrame cf; | |
| 956 cf.frame_ir = std::move(frame_ir); | |
| 957 collected_frames_->push_back(std::move(cf)); | |
| 958 } | |
| 959 | |
| 960 void DeframerCallbackCollector::OnPriority( | |
| 961 std::unique_ptr<SpdyPriorityIR> frame_ir) { | |
| 962 CollectedFrame cf; | |
| 963 cf.frame_ir = std::move(frame_ir); | |
| 964 collected_frames_->push_back(std::move(cf)); | |
| 965 } | |
| 966 | |
| 967 // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which | |
| 968 // significantly modifies the headers, so the actual header entries (name | |
| 969 // and value strings) are provided in a vector. | |
| 970 void DeframerCallbackCollector::OnPushPromise( | |
| 971 std::unique_ptr<SpdyPushPromiseIR> frame_ir, | |
| 972 std::unique_ptr<StringPairVector> headers) { | |
| 973 CollectedFrame cf; | |
| 974 cf.frame_ir = std::move(frame_ir); | |
| 975 cf.headers = std::move(headers); | |
| 976 collected_frames_->push_back(std::move(cf)); | |
| 977 } | |
| 978 | |
| 979 void DeframerCallbackCollector::OnRstStream( | |
| 980 std::unique_ptr<SpdyRstStreamIR> frame_ir) { | |
| 981 CollectedFrame cf; | |
| 982 cf.frame_ir = std::move(frame_ir); | |
| 983 collected_frames_->push_back(std::move(cf)); | |
| 984 } | |
| 985 | |
| 986 // SpdySettingsIR has a map for settings, so loses info about the order of | |
| 987 // settings, and whether the same setting appeared more than once, so the | |
| 988 // the actual settings (parameter and value) are provided in a vector. | |
| 989 void DeframerCallbackCollector::OnSettings( | |
| 990 std::unique_ptr<SpdySettingsIR> frame_ir, | |
| 991 std::unique_ptr<SettingVector> settings) { | |
| 992 EXPECT_TRUE(frame_ir && !frame_ir->is_ack()); | |
| 993 CollectedFrame cf; | |
| 994 cf.frame_ir = std::move(frame_ir); | |
| 995 cf.settings = std::move(settings); | |
| 996 collected_frames_->push_back(std::move(cf)); | |
| 997 } | |
| 998 | |
| 999 // A settings frame_ir with an ACK has no content, but for uniformity passing | |
| 1000 // a frame_ir with the ACK flag set. | |
| 1001 void DeframerCallbackCollector::OnSettingsAck( | |
| 1002 std::unique_ptr<SpdySettingsIR> frame_ir) { | |
| 1003 EXPECT_TRUE(frame_ir && frame_ir->is_ack()); | |
| 1004 CollectedFrame cf; | |
| 1005 cf.frame_ir = std::move(frame_ir); | |
| 1006 collected_frames_->push_back(std::move(cf)); | |
| 1007 } | |
| 1008 | |
| 1009 void DeframerCallbackCollector::OnWindowUpdate( | |
| 1010 std::unique_ptr<SpdyWindowUpdateIR> frame_ir) { | |
| 1011 CollectedFrame cf; | |
| 1012 cf.frame_ir = std::move(frame_ir); | |
| 1013 collected_frames_->push_back(std::move(cf)); | |
| 1014 } | |
| 1015 | |
| 1016 // The SpdyFramer will not process any more data at this point. | |
| 1017 void DeframerCallbackCollector::OnError(SpdyFramer* framer, | |
| 1018 SpdyTestDeframer* deframer) { | |
| 1019 CollectedFrame cf; | |
| 1020 cf.error_reported = true; | |
| 1021 collected_frames_->push_back(std::move(cf)); | |
| 1022 } | |
| 1023 | |
| 1024 } // namespace test | |
| 1025 } // namespace net | |
| OLD | NEW |