| 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/http2_frame_decoder_adapter.h" | |
| 6 | |
| 7 // Logging policy: If an error in the input is detected, VLOG(n) is used so that | |
| 8 // the option exists to debug the situation. Otherwise, this code mostly uses | |
| 9 // DVLOG so that the logging does not slow down production code when things are | |
| 10 // working OK. | |
| 11 | |
| 12 #include <stddef.h> | |
| 13 | |
| 14 #include <cstdint> | |
| 15 #include <cstring> | |
| 16 #include <utility> | |
| 17 | |
| 18 #include "base/logging.h" | |
| 19 #include "base/optional.h" | |
| 20 #include "base/sys_byteorder.h" | |
| 21 #include "net/http2/decoder/decode_buffer.h" | |
| 22 #include "net/http2/decoder/decode_status.h" | |
| 23 #include "net/http2/decoder/http2_frame_decoder.h" | |
| 24 #include "net/http2/decoder/http2_frame_decoder_listener.h" | |
| 25 #include "net/http2/http2_constants.h" | |
| 26 #include "net/http2/http2_structures.h" | |
| 27 #include "net/spdy/hpack/hpack_decoder_interface.h" | |
| 28 #include "net/spdy/hpack/hpack_header_table.h" | |
| 29 #include "net/spdy/platform/api/spdy_estimate_memory_usage.h" | |
| 30 #include "net/spdy/platform/api/spdy_string.h" | |
| 31 #include "net/spdy/spdy_alt_svc_wire_format.h" | |
| 32 #include "net/spdy/spdy_bug_tracker.h" | |
| 33 #include "net/spdy/spdy_frame_builder.h" | |
| 34 #include "net/spdy/spdy_header_block.h" | |
| 35 #include "net/spdy/spdy_headers_handler_interface.h" | |
| 36 #include "net/spdy/spdy_protocol.h" | |
| 37 | |
| 38 namespace net { | |
| 39 | |
| 40 namespace { | |
| 41 | |
| 42 const bool kHasPriorityFields = true; | |
| 43 const bool kNotHasPriorityFields = false; | |
| 44 | |
| 45 bool IsPaddable(Http2FrameType type) { | |
| 46 return type == Http2FrameType::DATA || type == Http2FrameType::HEADERS || | |
| 47 type == Http2FrameType::PUSH_PROMISE; | |
| 48 } | |
| 49 | |
| 50 SpdyFrameType ToSpdyFrameType(Http2FrameType type) { | |
| 51 return ParseFrameType(static_cast<uint8_t>(type)); | |
| 52 } | |
| 53 | |
| 54 uint64_t ToSpdyPingId(const Http2PingFields& ping) { | |
| 55 uint64_t v; | |
| 56 std::memcpy(&v, ping.opaque_data, Http2PingFields::EncodedSize()); | |
| 57 return base::NetToHost64(v); | |
| 58 } | |
| 59 | |
| 60 // Overwrites the fields of the header with invalid values, for the purpose | |
| 61 // of identifying reading of unset fields. Only takes effect for debug builds. | |
| 62 // In Address Sanatizer builds, it also marks the fields as un-readable. | |
| 63 void CorruptFrameHeader(Http2FrameHeader* header) { | |
| 64 #ifndef NDEBUG | |
| 65 // Beyond a valid payload length, which is 2^24 - 1. | |
| 66 header->payload_length = 0x1010dead; | |
| 67 // An unsupported frame type. | |
| 68 header->type = Http2FrameType(0x80); | |
| 69 DCHECK(!IsSupportedHttp2FrameType(header->type)); | |
| 70 // Frame flag bits that aren't used by any supported frame type. | |
| 71 header->flags = Http2FrameFlag(0xd2); | |
| 72 // A stream id with the reserved high-bit (R in the RFC) set. | |
| 73 // 2129510127 when the high-bit is cleared. | |
| 74 header->stream_id = 0xfeedbeef; | |
| 75 #endif | |
| 76 } | |
| 77 | |
| 78 class Http2DecoderAdapter : public SpdyFramerDecoderAdapter, | |
| 79 public Http2FrameDecoderListener { | |
| 80 typedef SpdyFramer::SpdyState SpdyState; | |
| 81 typedef SpdyFramer::SpdyFramerError SpdyFramerError; | |
| 82 | |
| 83 public: | |
| 84 explicit Http2DecoderAdapter(SpdyFramer* outer_framer) | |
| 85 : SpdyFramerDecoderAdapter(), outer_framer_(outer_framer) { | |
| 86 DVLOG(1) << "Http2DecoderAdapter ctor, outer_framer=" << outer_framer; | |
| 87 ResetInternal(); | |
| 88 } | |
| 89 ~Http2DecoderAdapter() override {} | |
| 90 | |
| 91 // =========================================================================== | |
| 92 // Implementations of the pure virtual methods from SpdyFramerDecoderAdapter; | |
| 93 // the other virtual methods of SpdyFramerDecoderAdapter have satsifactory | |
| 94 // default implementations. | |
| 95 | |
| 96 void set_extension_visitor(ExtensionVisitorInterface* visitor) override { | |
| 97 extension_ = visitor; | |
| 98 } | |
| 99 | |
| 100 // Passes the call on to the HPACK decoder. | |
| 101 void SetDecoderHeaderTableDebugVisitor( | |
| 102 std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) | |
| 103 override { | |
| 104 GetHpackDecoder()->SetHeaderTableDebugVisitor(std::move(visitor)); | |
| 105 } | |
| 106 | |
| 107 size_t ProcessInput(const char* data, size_t len) override { | |
| 108 size_t limit = outer_framer_->recv_frame_size_limit(); | |
| 109 frame_decoder_->set_maximum_payload_size(limit); | |
| 110 | |
| 111 size_t total_processed = 0; | |
| 112 while (len > 0 && spdy_state_ != SpdyFramer::SPDY_ERROR) { | |
| 113 // Process one at a time so that we update the adapter's internal | |
| 114 // state appropriately. | |
| 115 const size_t processed = ProcessInputFrame(data, len); | |
| 116 | |
| 117 // We had some data, and weren't in an error state, so should have | |
| 118 // processed/consumed at least one byte of it, even if we then ended up | |
| 119 // in an error state. | |
| 120 DCHECK(processed > 0) << "processed=" << processed | |
| 121 << " spdy_state_=" << spdy_state_ | |
| 122 << " spdy_framer_error_=" << spdy_framer_error_; | |
| 123 | |
| 124 data += processed; | |
| 125 len -= processed; | |
| 126 total_processed += processed; | |
| 127 if (process_single_input_frame() || processed == 0) { | |
| 128 break; | |
| 129 } | |
| 130 } | |
| 131 return total_processed; | |
| 132 } | |
| 133 | |
| 134 void Reset() override { ResetInternal(); } | |
| 135 | |
| 136 SpdyState state() const override { return spdy_state_; } | |
| 137 | |
| 138 SpdyFramerError spdy_framer_error() const override { | |
| 139 return spdy_framer_error_; | |
| 140 } | |
| 141 | |
| 142 bool probable_http_response() const override { | |
| 143 return latched_probable_http_response_; | |
| 144 } | |
| 145 | |
| 146 size_t EstimateMemoryUsage() const override { | |
| 147 // Skip |frame_decoder_|, |frame_header_| and |hpack_first_frame_header_| as | |
| 148 // they don't allocate. | |
| 149 return SpdyEstimateMemoryUsage(alt_svc_origin_) + | |
| 150 SpdyEstimateMemoryUsage(alt_svc_value_); | |
| 151 } | |
| 152 // =========================================================================== | |
| 153 // Implementations of the methods declared by Http2FrameDecoderListener. | |
| 154 | |
| 155 // Called once the common frame header has been decoded for any frame. | |
| 156 // This function is largely based on SpdyFramer::ValidateFrameHeader | |
| 157 // and some parts of SpdyFramer::ProcessCommonHeader. | |
| 158 bool OnFrameHeader(const Http2FrameHeader& header) override { | |
| 159 DVLOG(1) << "OnFrameHeader: " << header; | |
| 160 decoded_frame_header_ = true; | |
| 161 if (!latched_probable_http_response_) { | |
| 162 latched_probable_http_response_ = header.IsProbableHttpResponse(); | |
| 163 } | |
| 164 const uint8_t raw_frame_type = static_cast<uint8_t>(header.type); | |
| 165 visitor()->OnCommonHeader(header.stream_id, header.payload_length, | |
| 166 raw_frame_type, header.flags); | |
| 167 if (has_expected_frame_type_ && header.type != expected_frame_type_) { | |
| 168 // Report an unexpected frame error and close the connection if we | |
| 169 // expect a known frame type (probably CONTINUATION) and receive an | |
| 170 // unknown frame. | |
| 171 VLOG(1) << "The framer was expecting to receive a " | |
| 172 << expected_frame_type_ | |
| 173 << " frame, but instead received an unknown frame of type " | |
| 174 << header.type; | |
| 175 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME); | |
| 176 return false; | |
| 177 } | |
| 178 if (!IsSupportedHttp2FrameType(header.type)) { | |
| 179 if (extension_ != nullptr) { | |
| 180 // Unknown frames will be passed to the registered extension. | |
| 181 return true; | |
| 182 } | |
| 183 // In HTTP2 we ignore unknown frame types for extensibility, as long as | |
| 184 // the rest of the control frame header is valid. | |
| 185 // We rely on the visitor to check validity of stream_id. | |
| 186 bool valid_stream = | |
| 187 visitor()->OnUnknownFrame(header.stream_id, raw_frame_type); | |
| 188 if (!valid_stream) { | |
| 189 // Report an invalid frame error if the stream_id is not valid. | |
| 190 VLOG(1) << "Unknown control frame type " << header.type | |
| 191 << " received on invalid stream " << header.stream_id; | |
| 192 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME); | |
| 193 return false; | |
| 194 } else { | |
| 195 DVLOG(1) << "Ignoring unknown frame type " << header.type; | |
| 196 return true; | |
| 197 } | |
| 198 } | |
| 199 | |
| 200 SpdyFrameType frame_type = ToSpdyFrameType(header.type); | |
| 201 if (!IsValidHTTP2FrameStreamId(header.stream_id, frame_type)) { | |
| 202 VLOG(1) << "The framer received an invalid streamID of " | |
| 203 << header.stream_id << " for a frame of type " << header.type; | |
| 204 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID); | |
| 205 return false; | |
| 206 } | |
| 207 | |
| 208 if (has_expected_frame_type_ && header.type != expected_frame_type_) { | |
| 209 VLOG(1) << "Expected frame type " << expected_frame_type_ << ", not " | |
| 210 << header.type; | |
| 211 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME); | |
| 212 return false; | |
| 213 } | |
| 214 | |
| 215 if (!has_expected_frame_type_ && | |
| 216 header.type == Http2FrameType::CONTINUATION) { | |
| 217 VLOG(1) << "Got CONTINUATION frame when not expected."; | |
| 218 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME); | |
| 219 return false; | |
| 220 } | |
| 221 | |
| 222 if (header.type == Http2FrameType::DATA) { | |
| 223 // For some reason SpdyFramer still rejects invalid DATA frame flags. | |
| 224 uint8_t valid_flags = Http2FrameFlag::PADDED | Http2FrameFlag::END_STREAM; | |
| 225 if (header.HasAnyFlags(~valid_flags)) { | |
| 226 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_DATA_FRAME_FLAGS); | |
| 227 return false; | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 return true; | |
| 232 } | |
| 233 | |
| 234 void OnDataStart(const Http2FrameHeader& header) override { | |
| 235 DVLOG(1) << "OnDataStart: " << header; | |
| 236 | |
| 237 if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { | |
| 238 frame_header_ = header; | |
| 239 has_frame_header_ = true; | |
| 240 visitor()->OnDataFrameHeader(header.stream_id, header.payload_length, | |
| 241 header.IsEndStream()); | |
| 242 } | |
| 243 } | |
| 244 | |
| 245 void OnDataPayload(const char* data, size_t len) override { | |
| 246 DVLOG(1) << "OnDataPayload: len=" << len; | |
| 247 DCHECK(has_frame_header_); | |
| 248 DCHECK_EQ(frame_header_.type, Http2FrameType::DATA); | |
| 249 visitor()->OnStreamFrameData(frame_header().stream_id, data, len); | |
| 250 } | |
| 251 | |
| 252 void OnDataEnd() override { | |
| 253 DVLOG(1) << "OnDataEnd"; | |
| 254 DCHECK(has_frame_header_); | |
| 255 DCHECK_EQ(frame_header_.type, Http2FrameType::DATA); | |
| 256 if (frame_header().IsEndStream()) { | |
| 257 visitor()->OnStreamEnd(frame_header().stream_id); | |
| 258 } | |
| 259 opt_pad_length_.reset(); | |
| 260 } | |
| 261 | |
| 262 void OnHeadersStart(const Http2FrameHeader& header) override { | |
| 263 DVLOG(1) << "OnHeadersStart: " << header; | |
| 264 if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { | |
| 265 frame_header_ = header; | |
| 266 has_frame_header_ = true; | |
| 267 if (header.HasPriority()) { | |
| 268 // Once we've got the priority fields, then we can report the arrival | |
| 269 // of this HEADERS frame. | |
| 270 on_headers_called_ = false; | |
| 271 return; | |
| 272 } | |
| 273 on_headers_called_ = true; | |
| 274 ReportReceiveCompressedFrame(header); | |
| 275 visitor()->OnHeaders(header.stream_id, kNotHasPriorityFields, | |
| 276 0, // priority | |
| 277 0, // parent_stream_id | |
| 278 false, // exclusive | |
| 279 header.IsEndStream(), header.IsEndHeaders()); | |
| 280 CommonStartHpackBlock(); | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 void OnHeadersPriority(const Http2PriorityFields& priority) override { | |
| 285 DVLOG(1) << "OnHeadersPriority: " << priority; | |
| 286 DCHECK(has_frame_header_); | |
| 287 DCHECK_EQ(frame_type(), Http2FrameType::HEADERS) << frame_header_; | |
| 288 DCHECK(frame_header_.HasPriority()); | |
| 289 DCHECK(!on_headers_called_); | |
| 290 on_headers_called_ = true; | |
| 291 ReportReceiveCompressedFrame(frame_header_); | |
| 292 visitor()->OnHeaders(frame_header_.stream_id, kHasPriorityFields, | |
| 293 priority.weight, priority.stream_dependency, | |
| 294 priority.is_exclusive, frame_header_.IsEndStream(), | |
| 295 frame_header_.IsEndHeaders()); | |
| 296 CommonStartHpackBlock(); | |
| 297 } | |
| 298 | |
| 299 void OnHpackFragment(const char* data, size_t len) override { | |
| 300 DVLOG(1) << "OnHpackFragment: len=" << len; | |
| 301 on_hpack_fragment_called_ = true; | |
| 302 if (!GetHpackDecoder()->HandleControlFrameHeadersData(data, len)) { | |
| 303 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_DECOMPRESS_FAILURE); | |
| 304 return; | |
| 305 } | |
| 306 } | |
| 307 | |
| 308 void OnHeadersEnd() override { | |
| 309 DVLOG(1) << "OnHeadersEnd"; | |
| 310 CommonHpackFragmentEnd(); | |
| 311 opt_pad_length_.reset(); | |
| 312 } | |
| 313 | |
| 314 void OnPriorityFrame(const Http2FrameHeader& header, | |
| 315 const Http2PriorityFields& priority) override { | |
| 316 DVLOG(1) << "OnPriorityFrame: " << header << "; priority: " << priority; | |
| 317 if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { | |
| 318 visitor()->OnPriority(header.stream_id, priority.stream_dependency, | |
| 319 priority.weight, priority.is_exclusive); | |
| 320 } | |
| 321 } | |
| 322 | |
| 323 void OnContinuationStart(const Http2FrameHeader& header) override { | |
| 324 DVLOG(1) << "OnContinuationStart: " << header; | |
| 325 if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { | |
| 326 DCHECK(has_hpack_first_frame_header_); | |
| 327 if (header.stream_id != hpack_first_frame_header_.stream_id) { | |
| 328 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME); | |
| 329 return; | |
| 330 } | |
| 331 frame_header_ = header; | |
| 332 has_frame_header_ = true; | |
| 333 ReportReceiveCompressedFrame(header); | |
| 334 visitor()->OnContinuation(header.stream_id, header.IsEndHeaders()); | |
| 335 } | |
| 336 } | |
| 337 | |
| 338 void OnContinuationEnd() override { | |
| 339 DVLOG(1) << "OnContinuationEnd"; | |
| 340 CommonHpackFragmentEnd(); | |
| 341 } | |
| 342 | |
| 343 void OnPadLength(size_t trailing_length) override { | |
| 344 DVLOG(1) << "OnPadLength: " << trailing_length; | |
| 345 opt_pad_length_ = trailing_length; | |
| 346 if (frame_header_.type == Http2FrameType::DATA) { | |
| 347 visitor()->OnStreamPadding(stream_id(), 1); | |
| 348 } else if (frame_header_.type == Http2FrameType::HEADERS) { | |
| 349 CHECK_LT(trailing_length, 256u); | |
| 350 } | |
| 351 } | |
| 352 | |
| 353 void OnPadding(const char* padding, size_t skipped_length) override { | |
| 354 DVLOG(1) << "OnPadding: " << skipped_length; | |
| 355 if (frame_header_.type == Http2FrameType::DATA) { | |
| 356 visitor()->OnStreamPadding(stream_id(), skipped_length); | |
| 357 } else { | |
| 358 MaybeAnnounceEmptyFirstHpackFragment(); | |
| 359 } | |
| 360 } | |
| 361 | |
| 362 void OnRstStream(const Http2FrameHeader& header, | |
| 363 Http2ErrorCode http2_error_code) override { | |
| 364 DVLOG(1) << "OnRstStream: " << header << "; code=" << http2_error_code; | |
| 365 if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { | |
| 366 SpdyErrorCode error_code = | |
| 367 ParseErrorCode(static_cast<uint32_t>(http2_error_code)); | |
| 368 visitor()->OnRstStream(header.stream_id, error_code); | |
| 369 } | |
| 370 } | |
| 371 | |
| 372 void OnSettingsStart(const Http2FrameHeader& header) override { | |
| 373 DVLOG(1) << "OnSettingsStart: " << header; | |
| 374 if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { | |
| 375 frame_header_ = header; | |
| 376 has_frame_header_ = true; | |
| 377 visitor()->OnSettings(0); | |
| 378 } | |
| 379 } | |
| 380 | |
| 381 void OnSetting(const Http2SettingFields& setting_fields) override { | |
| 382 DVLOG(1) << "OnSetting: " << setting_fields; | |
| 383 const uint16_t parameter = static_cast<uint16_t>(setting_fields.parameter); | |
| 384 SpdySettingsIds setting_id; | |
| 385 if (!ParseSettingsId(parameter, &setting_id)) { | |
| 386 if (extension_ == nullptr) { | |
| 387 DVLOG(1) << "Ignoring unknown setting id: " << setting_fields; | |
| 388 } else { | |
| 389 extension_->OnSetting(parameter, setting_fields.value); | |
| 390 } | |
| 391 return; | |
| 392 } | |
| 393 visitor()->OnSetting(setting_id, setting_fields.value); | |
| 394 } | |
| 395 | |
| 396 void OnSettingsEnd() override { | |
| 397 DVLOG(1) << "OnSettingsEnd"; | |
| 398 visitor()->OnSettingsEnd(); | |
| 399 } | |
| 400 | |
| 401 void OnSettingsAck(const Http2FrameHeader& header) override { | |
| 402 DVLOG(1) << "OnSettingsAck: " << header; | |
| 403 if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { | |
| 404 visitor()->OnSettingsAck(); | |
| 405 } | |
| 406 } | |
| 407 | |
| 408 void OnPushPromiseStart(const Http2FrameHeader& header, | |
| 409 const Http2PushPromiseFields& promise, | |
| 410 size_t total_padding_length) override { | |
| 411 DVLOG(1) << "OnPushPromiseStart: " << header << "; promise: " << promise | |
| 412 << "; total_padding_length: " << total_padding_length; | |
| 413 if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { | |
| 414 if (promise.promised_stream_id == 0) { | |
| 415 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME); | |
| 416 return; | |
| 417 } | |
| 418 frame_header_ = header; | |
| 419 has_frame_header_ = true; | |
| 420 ReportReceiveCompressedFrame(header); | |
| 421 visitor()->OnPushPromise(header.stream_id, promise.promised_stream_id, | |
| 422 header.IsEndHeaders()); | |
| 423 CommonStartHpackBlock(); | |
| 424 } | |
| 425 } | |
| 426 | |
| 427 void OnPushPromiseEnd() override { | |
| 428 DVLOG(1) << "OnPushPromiseEnd"; | |
| 429 CommonHpackFragmentEnd(); | |
| 430 opt_pad_length_.reset(); | |
| 431 } | |
| 432 | |
| 433 void OnPing(const Http2FrameHeader& header, | |
| 434 const Http2PingFields& ping) override { | |
| 435 DVLOG(1) << "OnPing: " << header << "; ping: " << ping; | |
| 436 if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { | |
| 437 visitor()->OnPing(ToSpdyPingId(ping), false); | |
| 438 } | |
| 439 } | |
| 440 | |
| 441 void OnPingAck(const Http2FrameHeader& header, | |
| 442 const Http2PingFields& ping) override { | |
| 443 DVLOG(1) << "OnPingAck: " << header << "; ping: " << ping; | |
| 444 if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { | |
| 445 visitor()->OnPing(ToSpdyPingId(ping), true); | |
| 446 } | |
| 447 } | |
| 448 | |
| 449 void OnGoAwayStart(const Http2FrameHeader& header, | |
| 450 const Http2GoAwayFields& goaway) override { | |
| 451 DVLOG(1) << "OnGoAwayStart: " << header << "; goaway: " << goaway; | |
| 452 if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { | |
| 453 frame_header_ = header; | |
| 454 has_frame_header_ = true; | |
| 455 SpdyErrorCode error_code = | |
| 456 ParseErrorCode(static_cast<uint32_t>(goaway.error_code)); | |
| 457 visitor()->OnGoAway(goaway.last_stream_id, error_code); | |
| 458 } | |
| 459 } | |
| 460 | |
| 461 void OnGoAwayOpaqueData(const char* data, size_t len) override { | |
| 462 DVLOG(1) << "OnGoAwayOpaqueData: len=" << len; | |
| 463 visitor()->OnGoAwayFrameData(data, len); | |
| 464 } | |
| 465 | |
| 466 void OnGoAwayEnd() override { | |
| 467 DVLOG(1) << "OnGoAwayEnd"; | |
| 468 visitor()->OnGoAwayFrameData(nullptr, 0); | |
| 469 } | |
| 470 | |
| 471 void OnWindowUpdate(const Http2FrameHeader& header, | |
| 472 uint32_t increment) override { | |
| 473 DVLOG(1) << "OnWindowUpdate: " << header << "; increment=" << increment; | |
| 474 if (IsOkToStartFrame(header)) { | |
| 475 visitor()->OnWindowUpdate(header.stream_id, increment); | |
| 476 } | |
| 477 } | |
| 478 | |
| 479 // Per RFC7838, an ALTSVC frame on stream 0 with origin_length == 0, or one on | |
| 480 // a stream other than stream 0 with origin_length != 0 MUST be ignored. All | |
| 481 // frames are decoded by Http2DecoderAdapter, and it is left to the consumer | |
| 482 // (listener) to implement this behavior. | |
| 483 void OnAltSvcStart(const Http2FrameHeader& header, | |
| 484 size_t origin_length, | |
| 485 size_t value_length) override { | |
| 486 DVLOG(1) << "OnAltSvcStart: " << header | |
| 487 << "; origin_length: " << origin_length | |
| 488 << "; value_length: " << value_length; | |
| 489 if (!IsOkToStartFrame(header)) { | |
| 490 return; | |
| 491 } | |
| 492 frame_header_ = header; | |
| 493 has_frame_header_ = true; | |
| 494 alt_svc_origin_.clear(); | |
| 495 alt_svc_value_.clear(); | |
| 496 } | |
| 497 | |
| 498 void OnAltSvcOriginData(const char* data, size_t len) override { | |
| 499 DVLOG(1) << "OnAltSvcOriginData: len=" << len; | |
| 500 alt_svc_origin_.append(data, len); | |
| 501 } | |
| 502 | |
| 503 // Called when decoding the Alt-Svc-Field-Value of an ALTSVC; | |
| 504 // the field is uninterpreted. | |
| 505 void OnAltSvcValueData(const char* data, size_t len) override { | |
| 506 DVLOG(1) << "OnAltSvcValueData: len=" << len; | |
| 507 alt_svc_value_.append(data, len); | |
| 508 } | |
| 509 | |
| 510 void OnAltSvcEnd() override { | |
| 511 DVLOG(1) << "OnAltSvcEnd: origin.size(): " << alt_svc_origin_.size() | |
| 512 << "; value.size(): " << alt_svc_value_.size(); | |
| 513 SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; | |
| 514 if (!SpdyAltSvcWireFormat::ParseHeaderFieldValue(alt_svc_value_, | |
| 515 &altsvc_vector)) { | |
| 516 DLOG(ERROR) << "SpdyAltSvcWireFormat::ParseHeaderFieldValue failed."; | |
| 517 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME); | |
| 518 return; | |
| 519 } | |
| 520 visitor()->OnAltSvc(frame_header_.stream_id, alt_svc_origin_, | |
| 521 altsvc_vector); | |
| 522 // We assume that ALTSVC frames are rare, so get rid of the storage. | |
| 523 alt_svc_origin_.clear(); | |
| 524 alt_svc_origin_.shrink_to_fit(); | |
| 525 alt_svc_value_.clear(); | |
| 526 alt_svc_value_.shrink_to_fit(); | |
| 527 } | |
| 528 | |
| 529 // Except for BLOCKED frames, all other unknown frames are either dropped or | |
| 530 // passed to a registered extension. | |
| 531 void OnUnknownStart(const Http2FrameHeader& header) override { | |
| 532 DVLOG(1) << "OnUnknownStart: " << header; | |
| 533 if (IsOkToStartFrame(header)) { | |
| 534 if (extension_ != nullptr) { | |
| 535 const uint8_t type = static_cast<uint8_t>(header.type); | |
| 536 const uint8_t flags = static_cast<uint8_t>(header.flags); | |
| 537 handling_extension_payload_ = extension_->OnFrameHeader( | |
| 538 header.stream_id, header.payload_length, type, flags); | |
| 539 } | |
| 540 } | |
| 541 } | |
| 542 | |
| 543 void OnUnknownPayload(const char* data, size_t len) override { | |
| 544 if (handling_extension_payload_) { | |
| 545 extension_->OnFramePayload(data, len); | |
| 546 } else { | |
| 547 DVLOG(1) << "OnUnknownPayload: len=" << len; | |
| 548 } | |
| 549 } | |
| 550 | |
| 551 void OnUnknownEnd() override { | |
| 552 DVLOG(1) << "OnUnknownEnd"; | |
| 553 handling_extension_payload_ = false; | |
| 554 } | |
| 555 | |
| 556 void OnPaddingTooLong(const Http2FrameHeader& header, | |
| 557 size_t missing_length) override { | |
| 558 DVLOG(1) << "OnPaddingTooLong: " << header | |
| 559 << "; missing_length: " << missing_length; | |
| 560 if (header.type == Http2FrameType::DATA) { | |
| 561 if (header.payload_length == 0) { | |
| 562 DCHECK_EQ(1u, missing_length); | |
| 563 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_DATA_FRAME_FLAGS); | |
| 564 return; | |
| 565 } | |
| 566 visitor()->OnStreamPadding(header.stream_id, 1); | |
| 567 } | |
| 568 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_PADDING); | |
| 569 } | |
| 570 | |
| 571 void OnFrameSizeError(const Http2FrameHeader& header) override { | |
| 572 DVLOG(1) << "OnFrameSizeError: " << header; | |
| 573 size_t recv_limit = outer_framer_->recv_frame_size_limit(); | |
| 574 if (header.payload_length > recv_limit) { | |
| 575 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_OVERSIZED_PAYLOAD); | |
| 576 return; | |
| 577 } | |
| 578 if (header.type != Http2FrameType::DATA && | |
| 579 header.payload_length > recv_limit) { | |
| 580 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_CONTROL_PAYLOAD_TOO_LARGE); | |
| 581 return; | |
| 582 } | |
| 583 switch (header.type) { | |
| 584 case Http2FrameType::GOAWAY: | |
| 585 case Http2FrameType::ALTSVC: | |
| 586 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME); | |
| 587 break; | |
| 588 default: | |
| 589 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME_SIZE); | |
| 590 } | |
| 591 } | |
| 592 | |
| 593 private: | |
| 594 // Decodes the input up to the next frame boundary (i.e. at most one frame), | |
| 595 // stopping early if an error is detected. | |
| 596 size_t ProcessInputFrame(const char* data, size_t len) { | |
| 597 DCHECK_NE(spdy_state_, SpdyState::SPDY_ERROR); | |
| 598 DecodeBuffer db(data, len); | |
| 599 DecodeStatus status = frame_decoder_->DecodeFrame(&db); | |
| 600 if (spdy_state_ != SpdyFramer::SPDY_ERROR) { | |
| 601 DetermineSpdyState(status); | |
| 602 } else { | |
| 603 VLOG(1) << "ProcessInputFrame spdy_framer_error_=" | |
| 604 << SpdyFramer::SpdyFramerErrorToString(spdy_framer_error_); | |
| 605 if (spdy_framer_error_ == SpdyFramerError::SPDY_INVALID_PADDING && | |
| 606 has_frame_header_ && frame_type() != Http2FrameType::DATA) { | |
| 607 // spdy_framer_test checks that all of the available frame payload | |
| 608 // has been consumed, so do that. | |
| 609 size_t total = remaining_total_payload(); | |
| 610 if (total <= frame_header().payload_length) { | |
| 611 size_t avail = db.MinLengthRemaining(total); | |
| 612 VLOG(1) << "Skipping past " << avail << " bytes, of " << total | |
| 613 << " total remaining in the frame's payload."; | |
| 614 db.AdvanceCursor(avail); | |
| 615 } else { | |
| 616 SPDY_BUG << "Total remaining (" << total | |
| 617 << ") should not be greater than the payload length; " | |
| 618 << frame_header(); | |
| 619 } | |
| 620 } | |
| 621 } | |
| 622 return db.Offset(); | |
| 623 } | |
| 624 | |
| 625 // After decoding, determine the next SpdyState. Only called if the current | |
| 626 // state is NOT SpdyState::SPDY_ERROR (i.e. if none of the callback methods | |
| 627 // detected an error condition), because otherwise we assume that the callback | |
| 628 // method has set spdy_framer_error_ appropriately. | |
| 629 void DetermineSpdyState(DecodeStatus status) { | |
| 630 DCHECK_EQ(spdy_framer_error_, SpdyFramer::SPDY_NO_ERROR); | |
| 631 DCHECK(!HasError()) << spdy_framer_error_; | |
| 632 switch (status) { | |
| 633 case DecodeStatus::kDecodeDone: | |
| 634 DVLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeDone"; | |
| 635 ResetBetweenFrames(); | |
| 636 break; | |
| 637 case DecodeStatus::kDecodeInProgress: | |
| 638 DVLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeInProgress"; | |
| 639 if (decoded_frame_header_) { | |
| 640 if (IsDiscardingPayload()) { | |
| 641 set_spdy_state(SpdyState::SPDY_IGNORE_REMAINING_PAYLOAD); | |
| 642 } else if (has_frame_header_ && | |
| 643 frame_type() == Http2FrameType::DATA) { | |
| 644 if (IsReadingPaddingLength()) { | |
| 645 set_spdy_state(SpdyState::SPDY_READ_DATA_FRAME_PADDING_LENGTH); | |
| 646 } else if (IsSkippingPadding()) { | |
| 647 set_spdy_state(SpdyState::SPDY_CONSUME_PADDING); | |
| 648 } else { | |
| 649 set_spdy_state(SpdyState::SPDY_FORWARD_STREAM_FRAME); | |
| 650 } | |
| 651 } else { | |
| 652 set_spdy_state(SpdyState::SPDY_CONTROL_FRAME_PAYLOAD); | |
| 653 } | |
| 654 } else { | |
| 655 set_spdy_state(SpdyState::SPDY_READING_COMMON_HEADER); | |
| 656 } | |
| 657 break; | |
| 658 case DecodeStatus::kDecodeError: | |
| 659 VLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeError"; | |
| 660 if (IsDiscardingPayload()) { | |
| 661 if (remaining_total_payload() == 0) { | |
| 662 // Push the Http2FrameDecoder out of state kDiscardPayload now | |
| 663 // since doing so requires no input. | |
| 664 DecodeBuffer tmp("", 0); | |
| 665 DecodeStatus status = frame_decoder_->DecodeFrame(&tmp); | |
| 666 if (status != DecodeStatus::kDecodeDone) { | |
| 667 SPDY_BUG << "Expected to be done decoding the frame, not " | |
| 668 << status; | |
| 669 SetSpdyErrorAndNotify(SpdyFramer::SPDY_INTERNAL_FRAMER_ERROR); | |
| 670 } else if (spdy_framer_error_ != SpdyFramer::SPDY_NO_ERROR) { | |
| 671 SPDY_BUG << "Expected to have no error, not " | |
| 672 << SpdyFramer::SpdyFramerErrorToString( | |
| 673 spdy_framer_error_); | |
| 674 } else { | |
| 675 ResetBetweenFrames(); | |
| 676 } | |
| 677 } else { | |
| 678 set_spdy_state(SpdyState::SPDY_IGNORE_REMAINING_PAYLOAD); | |
| 679 } | |
| 680 } else { | |
| 681 SetSpdyErrorAndNotify(SpdyFramer::SPDY_INVALID_CONTROL_FRAME); | |
| 682 } | |
| 683 break; | |
| 684 } | |
| 685 } | |
| 686 | |
| 687 void ResetBetweenFrames() { | |
| 688 CorruptFrameHeader(&frame_header_); | |
| 689 decoded_frame_header_ = false; | |
| 690 has_frame_header_ = false; | |
| 691 set_spdy_state(SpdyState::SPDY_READY_FOR_FRAME); | |
| 692 } | |
| 693 | |
| 694 // ResetInternal is called from the constructor, and during tests, but not | |
| 695 // otherwise (i.e. not between every frame). | |
| 696 void ResetInternal() { | |
| 697 set_spdy_state(SpdyState::SPDY_READY_FOR_FRAME); | |
| 698 spdy_framer_error_ = SpdyFramerError::SPDY_NO_ERROR; | |
| 699 | |
| 700 decoded_frame_header_ = false; | |
| 701 has_frame_header_ = false; | |
| 702 on_headers_called_ = false; | |
| 703 on_hpack_fragment_called_ = false; | |
| 704 latched_probable_http_response_ = false; | |
| 705 has_expected_frame_type_ = false; | |
| 706 | |
| 707 CorruptFrameHeader(&frame_header_); | |
| 708 CorruptFrameHeader(&hpack_first_frame_header_); | |
| 709 | |
| 710 frame_decoder_.reset(new Http2FrameDecoder(this)); | |
| 711 } | |
| 712 | |
| 713 void set_spdy_state(SpdyState v) { | |
| 714 DVLOG(2) << "set_spdy_state(" << SpdyFramer::StateToString(v) << ")"; | |
| 715 spdy_state_ = v; | |
| 716 } | |
| 717 | |
| 718 void SetSpdyErrorAndNotify(SpdyFramerError error) { | |
| 719 if (HasError()) { | |
| 720 DCHECK_EQ(spdy_state_, SpdyState::SPDY_ERROR); | |
| 721 } else { | |
| 722 VLOG(2) << "SetSpdyErrorAndNotify(" | |
| 723 << SpdyFramer::SpdyFramerErrorToString(error) << ")"; | |
| 724 DCHECK_NE(error, SpdyFramerError::SPDY_NO_ERROR); | |
| 725 spdy_framer_error_ = error; | |
| 726 set_spdy_state(SpdyState::SPDY_ERROR); | |
| 727 frame_decoder_->set_listener(&no_op_listener_); | |
| 728 visitor()->OnError(outer_framer_); | |
| 729 } | |
| 730 } | |
| 731 | |
| 732 bool HasError() const { | |
| 733 if (spdy_state_ == SpdyState::SPDY_ERROR) { | |
| 734 DCHECK_NE(spdy_framer_error(), SpdyFramerError::SPDY_NO_ERROR); | |
| 735 return true; | |
| 736 } else { | |
| 737 DCHECK_EQ(spdy_framer_error(), SpdyFramerError::SPDY_NO_ERROR); | |
| 738 return false; | |
| 739 } | |
| 740 } | |
| 741 | |
| 742 const Http2FrameHeader& frame_header() const { | |
| 743 DCHECK(has_frame_header_); | |
| 744 return frame_header_; | |
| 745 } | |
| 746 | |
| 747 uint32_t stream_id() const { return frame_header().stream_id; } | |
| 748 | |
| 749 Http2FrameType frame_type() const { return frame_header().type; } | |
| 750 | |
| 751 size_t remaining_total_payload() const { | |
| 752 DCHECK(has_frame_header_); | |
| 753 size_t remaining = frame_decoder_->remaining_payload(); | |
| 754 if (IsPaddable(frame_type()) && frame_header_.IsPadded()) { | |
| 755 remaining += frame_decoder_->remaining_padding(); | |
| 756 } | |
| 757 return remaining; | |
| 758 } | |
| 759 | |
| 760 bool IsReadingPaddingLength() { | |
| 761 bool result = frame_header_.IsPadded() && !opt_pad_length_; | |
| 762 DVLOG(2) << "Http2DecoderAdapter::IsReadingPaddingLength: " << result; | |
| 763 return result; | |
| 764 } | |
| 765 bool IsSkippingPadding() { | |
| 766 bool result = frame_header_.IsPadded() && opt_pad_length_ && | |
| 767 frame_decoder_->remaining_payload() == 0 && | |
| 768 frame_decoder_->remaining_padding() > 0; | |
| 769 DVLOG(2) << "Http2DecoderAdapter::IsSkippingPadding: " << result; | |
| 770 return result; | |
| 771 } | |
| 772 bool IsDiscardingPayload() { | |
| 773 bool result = | |
| 774 decoded_frame_header_ && frame_decoder_->IsDiscardingPayload(); | |
| 775 DVLOG(2) << "Http2DecoderAdapter::IsDiscardingPayload: " << result; | |
| 776 return result; | |
| 777 } | |
| 778 // Called from OnXyz or OnXyzStart methods to decide whether it is OK to | |
| 779 // handle the callback. | |
| 780 bool IsOkToStartFrame(const Http2FrameHeader& header) { | |
| 781 DVLOG(3) << "IsOkToStartFrame"; | |
| 782 if (HasError()) { | |
| 783 VLOG(2) << "HasError()"; | |
| 784 return false; | |
| 785 } | |
| 786 DCHECK(!has_frame_header_); | |
| 787 if (has_expected_frame_type_ && header.type != expected_frame_type_) { | |
| 788 VLOG(1) << "Expected frame type " << expected_frame_type_ << ", not " | |
| 789 << header.type; | |
| 790 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME); | |
| 791 return false; | |
| 792 } | |
| 793 | |
| 794 return true; | |
| 795 } | |
| 796 | |
| 797 bool HasRequiredStreamId(uint32_t stream_id) { | |
| 798 DVLOG(3) << "HasRequiredStreamId: " << stream_id; | |
| 799 if (HasError()) { | |
| 800 VLOG(2) << "HasError()"; | |
| 801 return false; | |
| 802 } | |
| 803 if (stream_id != 0) { | |
| 804 return true; | |
| 805 } | |
| 806 VLOG(1) << "Stream Id is required, but zero provided"; | |
| 807 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID); | |
| 808 return false; | |
| 809 } | |
| 810 | |
| 811 bool HasRequiredStreamId(const Http2FrameHeader& header) { | |
| 812 return HasRequiredStreamId(header.stream_id); | |
| 813 } | |
| 814 | |
| 815 bool HasRequiredStreamIdZero(uint32_t stream_id) { | |
| 816 DVLOG(3) << "HasRequiredStreamIdZero: " << stream_id; | |
| 817 if (HasError()) { | |
| 818 VLOG(2) << "HasError()"; | |
| 819 return false; | |
| 820 } | |
| 821 if (stream_id == 0) { | |
| 822 return true; | |
| 823 } | |
| 824 VLOG(1) << "Stream Id was not zero, as required: " << stream_id; | |
| 825 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID); | |
| 826 return false; | |
| 827 } | |
| 828 | |
| 829 bool HasRequiredStreamIdZero(const Http2FrameHeader& header) { | |
| 830 return HasRequiredStreamIdZero(header.stream_id); | |
| 831 } | |
| 832 | |
| 833 void ReportReceiveCompressedFrame(const Http2FrameHeader& header) { | |
| 834 if (debug_visitor() != nullptr) { | |
| 835 size_t total = header.payload_length + Http2FrameHeader::EncodedSize(); | |
| 836 debug_visitor()->OnReceiveCompressedFrame( | |
| 837 header.stream_id, ToSpdyFrameType(header.type), total); | |
| 838 } | |
| 839 } | |
| 840 | |
| 841 HpackDecoderInterface* GetHpackDecoder() { | |
| 842 if (hpack_decoder_ == nullptr) { | |
| 843 hpack_decoder_ = outer_framer_->GetHpackDecoderForAdapter(); | |
| 844 } | |
| 845 return hpack_decoder_; | |
| 846 } | |
| 847 | |
| 848 void CommonStartHpackBlock() { | |
| 849 DVLOG(1) << "CommonStartHpackBlock"; | |
| 850 DCHECK(!has_hpack_first_frame_header_); | |
| 851 if (!frame_header_.IsEndHeaders()) { | |
| 852 hpack_first_frame_header_ = frame_header_; | |
| 853 has_hpack_first_frame_header_ = true; | |
| 854 } else { | |
| 855 CorruptFrameHeader(&hpack_first_frame_header_); | |
| 856 } | |
| 857 on_hpack_fragment_called_ = false; | |
| 858 SpdyHeadersHandlerInterface* handler = | |
| 859 visitor()->OnHeaderFrameStart(stream_id()); | |
| 860 if (handler == nullptr) { | |
| 861 SPDY_BUG << "visitor_->OnHeaderFrameStart returned nullptr"; | |
| 862 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INTERNAL_FRAMER_ERROR); | |
| 863 return; | |
| 864 } | |
| 865 GetHpackDecoder()->HandleControlFrameHeadersStart(handler); | |
| 866 } | |
| 867 | |
| 868 // SpdyFramer calls HandleControlFrameHeadersData even if there are zero | |
| 869 // fragment bytes in the first frame, so do the same. | |
| 870 void MaybeAnnounceEmptyFirstHpackFragment() { | |
| 871 if (!on_hpack_fragment_called_) { | |
| 872 OnHpackFragment(nullptr, 0); | |
| 873 DCHECK(on_hpack_fragment_called_); | |
| 874 } | |
| 875 } | |
| 876 | |
| 877 void CommonHpackFragmentEnd() { | |
| 878 DVLOG(1) << "CommonHpackFragmentEnd: stream_id=" << stream_id(); | |
| 879 if (HasError()) { | |
| 880 VLOG(1) << "HasError(), returning"; | |
| 881 return; | |
| 882 } | |
| 883 DCHECK(has_frame_header_); | |
| 884 MaybeAnnounceEmptyFirstHpackFragment(); | |
| 885 if (frame_header_.IsEndHeaders()) { | |
| 886 DCHECK_EQ(has_hpack_first_frame_header_, | |
| 887 frame_type() == Http2FrameType::CONTINUATION) | |
| 888 << frame_header(); | |
| 889 has_expected_frame_type_ = false; | |
| 890 if (GetHpackDecoder()->HandleControlFrameHeadersComplete(nullptr)) { | |
| 891 visitor()->OnHeaderFrameEnd(stream_id(), true); | |
| 892 } else { | |
| 893 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_DECOMPRESS_FAILURE); | |
| 894 return; | |
| 895 } | |
| 896 const Http2FrameHeader& first = | |
| 897 frame_type() == Http2FrameType::CONTINUATION | |
| 898 ? hpack_first_frame_header_ | |
| 899 : frame_header_; | |
| 900 if (first.type == Http2FrameType::HEADERS && first.IsEndStream()) { | |
| 901 visitor()->OnStreamEnd(first.stream_id); | |
| 902 } | |
| 903 hpack_decoder_ = nullptr; | |
| 904 has_hpack_first_frame_header_ = false; | |
| 905 CorruptFrameHeader(&hpack_first_frame_header_); | |
| 906 } else { | |
| 907 DCHECK(has_hpack_first_frame_header_); | |
| 908 has_expected_frame_type_ = true; | |
| 909 expected_frame_type_ = Http2FrameType::CONTINUATION; | |
| 910 } | |
| 911 } | |
| 912 | |
| 913 // The SpdyFramer that created this Http2FrameDecoderAdapter. | |
| 914 SpdyFramer* const outer_framer_; | |
| 915 | |
| 916 // If non-null, unknown frames and settings are passed to the extension. | |
| 917 ExtensionVisitorInterface* extension_ = nullptr; | |
| 918 | |
| 919 // The HPACK decoder that we're using for the HPACK block that is currently | |
| 920 // being decoded. Cleared at the end of the block. Owned by the SpdyFramer. | |
| 921 HpackDecoderInterface* hpack_decoder_ = nullptr; | |
| 922 | |
| 923 // The HTTP/2 frame decoder. Accessed via a unique_ptr to allow replacement | |
| 924 // (e.g. in tests) when Reset() is called. | |
| 925 std::unique_ptr<Http2FrameDecoder> frame_decoder_; | |
| 926 | |
| 927 // The most recently decoded frame header; invalid after we reached the end | |
| 928 // of that frame. | |
| 929 Http2FrameHeader frame_header_; | |
| 930 | |
| 931 // If decoding an HPACK block that is split across multiple frames, this holds | |
| 932 // the frame header of the HEADERS or PUSH_PROMISE that started the block. | |
| 933 Http2FrameHeader hpack_first_frame_header_; | |
| 934 | |
| 935 // Amount of trailing padding. Currently used just as an indicator of whether | |
| 936 // OnPadLength has been called. | |
| 937 base::Optional<size_t> opt_pad_length_; | |
| 938 | |
| 939 // Temporary buffers for the AltSvc fields. | |
| 940 SpdyString alt_svc_origin_; | |
| 941 SpdyString alt_svc_value_; | |
| 942 | |
| 943 // Listener used if we transition to an error state; the listener ignores all | |
| 944 // the callbacks. | |
| 945 Http2FrameDecoderNoOpListener no_op_listener_; | |
| 946 | |
| 947 // Next frame type expected. Currently only used for CONTINUATION frames, | |
| 948 // but could be used for detecting whether the first frame is a SETTINGS | |
| 949 // frame. | |
| 950 // TODO(jamessyng): Provide means to indicate that decoder should require | |
| 951 // SETTINGS frame as the first frame. | |
| 952 Http2FrameType expected_frame_type_; | |
| 953 | |
| 954 // Attempt to duplicate the SpdyState and SpdyFramerError values that | |
| 955 // SpdyFramer sets. Values determined by getting tests to pass. | |
| 956 SpdyState spdy_state_; | |
| 957 SpdyFramerError spdy_framer_error_; | |
| 958 | |
| 959 // Has OnFrameHeader been called? | |
| 960 bool decoded_frame_header_ = false; | |
| 961 | |
| 962 // Have we recorded an Http2FrameHeader for the current frame? | |
| 963 // We only do so if the decoder will make multiple callbacks for | |
| 964 // the frame; for example, for PING frames we don't make record | |
| 965 // the frame header, but for ALTSVC we do. | |
| 966 bool has_frame_header_ = false; | |
| 967 | |
| 968 // Have we recorded an Http2FrameHeader for the current HPACK block? | |
| 969 // True only for multi-frame HPACK blocks. | |
| 970 bool has_hpack_first_frame_header_ = false; | |
| 971 | |
| 972 // Has OnHeaders() already been called for current HEADERS block? Only | |
| 973 // meaningful between OnHeadersStart and OnHeadersPriority. | |
| 974 bool on_headers_called_; | |
| 975 | |
| 976 // Has OnHpackFragment() already been called for current HPACK block? | |
| 977 // SpdyFramer will pass an empty buffer to the HPACK decoder if a HEADERS | |
| 978 // or PUSH_PROMISE has no HPACK data in it (e.g. a HEADERS frame with only | |
| 979 // padding). Detect that condition and replicate the behavior using this | |
| 980 // field. | |
| 981 bool on_hpack_fragment_called_; | |
| 982 | |
| 983 // Have we seen a frame header that appears to be an HTTP/1 response? | |
| 984 bool latched_probable_http_response_ = false; | |
| 985 | |
| 986 // Is expected_frame_type_ set? | |
| 987 bool has_expected_frame_type_ = false; | |
| 988 | |
| 989 // Is the current frame payload destined for |extension_|? | |
| 990 bool handling_extension_payload_ = false; | |
| 991 }; | |
| 992 | |
| 993 } // namespace | |
| 994 | |
| 995 std::unique_ptr<SpdyFramerDecoderAdapter> CreateHttp2FrameDecoderAdapter( | |
| 996 SpdyFramer* outer_framer) { | |
| 997 return std::unique_ptr<SpdyFramerDecoderAdapter>( | |
| 998 new Http2DecoderAdapter(outer_framer)); | |
| 999 } | |
| 1000 | |
| 1001 } // namespace net | |
| OLD | NEW |