| 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/spdy_framer.h" | |
| 6 | |
| 7 #include "base/lazy_instance.h" | |
| 8 #include "base/memory/scoped_ptr.h" | |
| 9 #include "base/third_party/valgrind/memcheck.h" | |
| 10 #include "net/spdy/spdy_frame_builder.h" | |
| 11 #include "net/spdy/spdy_frame_reader.h" | |
| 12 #include "net/spdy/spdy_bitmasks.h" | |
| 13 #include "third_party/zlib/zlib.h" | |
| 14 | |
| 15 using base::StringPiece; | |
| 16 using std::string; | |
| 17 using std::vector; | |
| 18 | |
| 19 namespace net { | |
| 20 | |
| 21 namespace { | |
| 22 | |
| 23 // Compute the id of our dictionary so that we know we're using the | |
| 24 // right one when asked for it. | |
| 25 uLong CalculateDictionaryId(const char* dictionary, | |
| 26 const size_t dictionary_size) { | |
| 27 uLong initial_value = adler32(0L, Z_NULL, 0); | |
| 28 return adler32(initial_value, | |
| 29 reinterpret_cast<const Bytef*>(dictionary), | |
| 30 dictionary_size); | |
| 31 } | |
| 32 | |
| 33 // Check to see if the name and value of a cookie are both empty. | |
| 34 bool IsCookieEmpty(const base::StringPiece& cookie) { | |
| 35 if (cookie.size() == 0) { | |
| 36 return true; | |
| 37 } | |
| 38 size_t pos = cookie.find('='); | |
| 39 if (pos == base::StringPiece::npos) { | |
| 40 return false; | |
| 41 } | |
| 42 // Ignore leading whitespaces of cookie value. | |
| 43 size_t value_start = pos + 1; | |
| 44 for (; value_start < cookie.size(); value_start++) { | |
| 45 if (!(cookie[value_start] == ' ' || cookie[value_start] == '\t')) { | |
| 46 break; | |
| 47 } | |
| 48 } | |
| 49 return (pos == 0) && ((cookie.size() - value_start) == 0); | |
| 50 } | |
| 51 | |
| 52 struct DictionaryIds { | |
| 53 DictionaryIds() | |
| 54 : v2_dictionary_id(CalculateDictionaryId(kV2Dictionary, kV2DictionarySize)), | |
| 55 v3_dictionary_id(CalculateDictionaryId(kV3Dictionary, kV3DictionarySize)) | |
| 56 {} | |
| 57 const uLong v2_dictionary_id; | |
| 58 const uLong v3_dictionary_id; | |
| 59 }; | |
| 60 | |
| 61 // Adler ID for the SPDY header compressor dictionaries. Note that they are | |
| 62 // initialized lazily to avoid static initializers. | |
| 63 base::LazyInstance<DictionaryIds>::Leaky g_dictionary_ids; | |
| 64 | |
| 65 // Used to indicate no flags in a SPDY flags field. | |
| 66 const uint8 kNoFlags = 0; | |
| 67 | |
| 68 // Wire sizes of priority payloads. | |
| 69 const size_t kPriorityDependencyPayloadSize = 4; | |
| 70 const size_t kPriorityWeightPayloadSize = 1; | |
| 71 | |
| 72 // Wire size of pad length field. | |
| 73 const size_t kPadLengthFieldSize = 1; | |
| 74 | |
| 75 } // namespace | |
| 76 | |
| 77 const SpdyStreamId SpdyFramer::kInvalidStream = static_cast<SpdyStreamId>(-1); | |
| 78 const size_t SpdyFramer::kHeaderDataChunkMaxSize = 1024; | |
| 79 // We fragment sent control frames at smaller payload boundaries. | |
| 80 const size_t SpdyFramer::kMaxControlFrameSize = 1024; | |
| 81 // The size of the control frame buffer. Must be >= the minimum size of the | |
| 82 // largest control frame, which is SYN_STREAM. See GetSynStreamMinimumSize() for | |
| 83 // calculation details. | |
| 84 const size_t SpdyFramer::kControlFrameBufferSize = 19; | |
| 85 | |
| 86 #ifdef DEBUG_SPDY_STATE_CHANGES | |
| 87 #define CHANGE_STATE(newstate) \ | |
| 88 do { \ | |
| 89 DVLOG(1) << "Changing state from: " \ | |
| 90 << StateToString(state_) \ | |
| 91 << " to " << StateToString(newstate) << "\n"; \ | |
| 92 DCHECK(state_ != SPDY_ERROR); \ | |
| 93 DCHECK_EQ(previous_state_, state_); \ | |
| 94 previous_state_ = state_; \ | |
| 95 state_ = newstate; \ | |
| 96 } while (false) | |
| 97 #else | |
| 98 #define CHANGE_STATE(newstate) \ | |
| 99 do { \ | |
| 100 DCHECK(state_ != SPDY_ERROR); \ | |
| 101 DCHECK_EQ(previous_state_, state_); \ | |
| 102 previous_state_ = state_; \ | |
| 103 state_ = newstate; \ | |
| 104 } while (false) | |
| 105 #endif | |
| 106 | |
| 107 SettingsFlagsAndId SettingsFlagsAndId::FromWireFormat( | |
| 108 SpdyMajorVersion version, uint32 wire) { | |
| 109 if (version < SPDY3) { | |
| 110 ConvertFlagsAndIdForSpdy2(&wire); | |
| 111 } | |
| 112 return SettingsFlagsAndId(ntohl(wire) >> 24, ntohl(wire) & 0x00ffffff); | |
| 113 } | |
| 114 | |
| 115 SettingsFlagsAndId::SettingsFlagsAndId(uint8 flags, uint32 id) | |
| 116 : flags_(flags), id_(id & 0x00ffffff) { | |
| 117 LOG_IF(DFATAL, id > (1u << 24)) << "SPDY setting ID too large: " << id; | |
| 118 } | |
| 119 | |
| 120 uint32 SettingsFlagsAndId::GetWireFormat(SpdyMajorVersion version) | |
| 121 const { | |
| 122 uint32 wire = htonl(id_ & 0x00ffffff) | htonl(flags_ << 24); | |
| 123 if (version < SPDY3) { | |
| 124 ConvertFlagsAndIdForSpdy2(&wire); | |
| 125 } | |
| 126 return wire; | |
| 127 } | |
| 128 | |
| 129 // SPDY 2 had a bug in it with respect to byte ordering of id/flags field. | |
| 130 // This method is used to preserve buggy behavior and works on both | |
| 131 // little-endian and big-endian hosts. | |
| 132 // This method is also bidirectional (can be used to translate SPDY 2 to SPDY 3 | |
| 133 // as well as vice versa). | |
| 134 void SettingsFlagsAndId::ConvertFlagsAndIdForSpdy2(uint32* val) { | |
| 135 uint8* wire_array = reinterpret_cast<uint8*>(val); | |
| 136 std::swap(wire_array[0], wire_array[3]); | |
| 137 std::swap(wire_array[1], wire_array[2]); | |
| 138 } | |
| 139 | |
| 140 SpdyAltSvcScratch::SpdyAltSvcScratch() { Reset(); } | |
| 141 SpdyAltSvcScratch::~SpdyAltSvcScratch() {} | |
| 142 | |
| 143 bool SpdyFramerVisitorInterface::OnGoAwayFrameData(const char* goaway_data, | |
| 144 size_t len) { | |
| 145 return true; | |
| 146 } | |
| 147 | |
| 148 bool SpdyFramerVisitorInterface::OnRstStreamFrameData( | |
| 149 const char* rst_stream_data, | |
| 150 size_t len) { | |
| 151 return true; | |
| 152 } | |
| 153 | |
| 154 SpdyFramer::SpdyFramer(SpdyMajorVersion version) | |
| 155 : current_frame_buffer_(new char[kControlFrameBufferSize]), | |
| 156 enable_compression_(true), | |
| 157 visitor_(NULL), | |
| 158 debug_visitor_(NULL), | |
| 159 display_protocol_("SPDY"), | |
| 160 protocol_version_(version), | |
| 161 syn_frame_processed_(false), | |
| 162 probable_http_response_(false), | |
| 163 expect_continuation_(0), | |
| 164 end_stream_when_done_(false) { | |
| 165 DCHECK_GE(protocol_version_, SPDY_MIN_VERSION); | |
| 166 DCHECK_LE(protocol_version_, SPDY_MAX_VERSION); | |
| 167 DCHECK_LE(kMaxControlFrameSize, | |
| 168 SpdyConstants::GetFrameMaximumSize(protocol_version_) + | |
| 169 SpdyConstants::GetControlFrameHeaderSize(protocol_version_)); | |
| 170 Reset(); | |
| 171 } | |
| 172 | |
| 173 SpdyFramer::~SpdyFramer() { | |
| 174 if (header_compressor_.get()) { | |
| 175 deflateEnd(header_compressor_.get()); | |
| 176 } | |
| 177 if (header_decompressor_.get()) { | |
| 178 inflateEnd(header_decompressor_.get()); | |
| 179 } | |
| 180 } | |
| 181 | |
| 182 void SpdyFramer::Reset() { | |
| 183 state_ = SPDY_RESET; | |
| 184 previous_state_ = SPDY_RESET; | |
| 185 error_code_ = SPDY_NO_ERROR; | |
| 186 remaining_data_length_ = 0; | |
| 187 remaining_control_header_ = 0; | |
| 188 current_frame_buffer_length_ = 0; | |
| 189 current_frame_type_ = DATA; | |
| 190 current_frame_flags_ = 0; | |
| 191 current_frame_length_ = 0; | |
| 192 current_frame_stream_id_ = kInvalidStream; | |
| 193 settings_scratch_.Reset(); | |
| 194 altsvc_scratch_.Reset(); | |
| 195 remaining_padding_payload_length_ = 0; | |
| 196 } | |
| 197 | |
| 198 size_t SpdyFramer::GetDataFrameMinimumSize() const { | |
| 199 return SpdyConstants::GetDataFrameMinimumSize(protocol_version()); | |
| 200 } | |
| 201 | |
| 202 // Size, in bytes, of the control frame header. | |
| 203 size_t SpdyFramer::GetControlFrameHeaderSize() const { | |
| 204 return SpdyConstants::GetControlFrameHeaderSize(protocol_version()); | |
| 205 } | |
| 206 | |
| 207 size_t SpdyFramer::GetSynStreamMinimumSize() const { | |
| 208 // Size, in bytes, of a SYN_STREAM frame not including the variable-length | |
| 209 // name-value block. | |
| 210 if (protocol_version() <= SPDY3) { | |
| 211 // Calculated as: | |
| 212 // control frame header + 2 * 4 (stream IDs) + 1 (priority) | |
| 213 // + 1 (unused, was credential slot) | |
| 214 return GetControlFrameHeaderSize() + 10; | |
| 215 } else { | |
| 216 return GetControlFrameHeaderSize() + | |
| 217 kPriorityDependencyPayloadSize + | |
| 218 kPriorityWeightPayloadSize; | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 size_t SpdyFramer::GetSynReplyMinimumSize() const { | |
| 223 // Size, in bytes, of a SYN_REPLY frame not including the variable-length | |
| 224 // name-value block. | |
| 225 size_t size = GetControlFrameHeaderSize(); | |
| 226 if (protocol_version() <= SPDY3) { | |
| 227 // Calculated as: | |
| 228 // control frame header + 4 (stream IDs) | |
| 229 size += 4; | |
| 230 } | |
| 231 | |
| 232 // In SPDY 2, there were 2 unused bytes before payload. | |
| 233 if (protocol_version() < SPDY3) { | |
| 234 size += 2; | |
| 235 } | |
| 236 | |
| 237 return size; | |
| 238 } | |
| 239 | |
| 240 size_t SpdyFramer::GetRstStreamMinimumSize() const { | |
| 241 // Size, in bytes, of a RST_STREAM frame. | |
| 242 if (protocol_version() <= SPDY3) { | |
| 243 // Calculated as: | |
| 244 // control frame header + 4 (stream id) + 4 (status code) | |
| 245 return GetControlFrameHeaderSize() + 8; | |
| 246 } else { | |
| 247 // Calculated as: | |
| 248 // frame prefix + 4 (status code) | |
| 249 return GetControlFrameHeaderSize() + 4; | |
| 250 } | |
| 251 } | |
| 252 | |
| 253 size_t SpdyFramer::GetSettingsMinimumSize() const { | |
| 254 // Size, in bytes, of a SETTINGS frame not including the IDs and values | |
| 255 // from the variable-length value block. Calculated as: | |
| 256 // control frame header + 4 (number of ID/value pairs) | |
| 257 if (protocol_version() <= SPDY3) { | |
| 258 return GetControlFrameHeaderSize() + 4; | |
| 259 } else { | |
| 260 return GetControlFrameHeaderSize(); | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 size_t SpdyFramer::GetPingSize() const { | |
| 265 // Size, in bytes, of this PING frame. | |
| 266 if (protocol_version() <= SPDY3) { | |
| 267 // Calculated as: | |
| 268 // control frame header + 4 (id) | |
| 269 return GetControlFrameHeaderSize() + 4; | |
| 270 } else { | |
| 271 // Calculated as: | |
| 272 // control frame header + 8 (id) | |
| 273 return GetControlFrameHeaderSize() + 8; | |
| 274 } | |
| 275 } | |
| 276 | |
| 277 size_t SpdyFramer::GetGoAwayMinimumSize() const { | |
| 278 // Size, in bytes, of this GOAWAY frame. Calculated as: | |
| 279 // 1. Control frame header size | |
| 280 size_t size = GetControlFrameHeaderSize(); | |
| 281 | |
| 282 // 2. Last good stream id (4 bytes) | |
| 283 size += 4; | |
| 284 | |
| 285 // 3. SPDY 3+ GOAWAY frames also contain a status (4 bytes) | |
| 286 if (protocol_version() >= SPDY3) { | |
| 287 size += 4; | |
| 288 } | |
| 289 | |
| 290 return size; | |
| 291 } | |
| 292 | |
| 293 size_t SpdyFramer::GetHeadersMinimumSize() const { | |
| 294 // Size, in bytes, of a HEADERS frame not including the variable-length | |
| 295 // name-value block. | |
| 296 size_t size = GetControlFrameHeaderSize(); | |
| 297 if (protocol_version() <= SPDY3) { | |
| 298 // Calculated as: | |
| 299 // control frame header + 4 (stream IDs) | |
| 300 size += 4; | |
| 301 } | |
| 302 | |
| 303 // In SPDY 2, there were 2 unused bytes before payload. | |
| 304 if (protocol_version() <= SPDY2) { | |
| 305 size += 2; | |
| 306 } | |
| 307 | |
| 308 return size; | |
| 309 } | |
| 310 | |
| 311 size_t SpdyFramer::GetWindowUpdateSize() const { | |
| 312 // Size, in bytes, of a WINDOW_UPDATE frame. | |
| 313 if (protocol_version() <= SPDY3) { | |
| 314 // Calculated as: | |
| 315 // control frame header + 4 (stream id) + 4 (delta) | |
| 316 return GetControlFrameHeaderSize() + 8; | |
| 317 } else { | |
| 318 // Calculated as: | |
| 319 // frame prefix + 4 (delta) | |
| 320 return GetControlFrameHeaderSize() + 4; | |
| 321 } | |
| 322 } | |
| 323 | |
| 324 size_t SpdyFramer::GetBlockedSize() const { | |
| 325 DCHECK_LT(SPDY3, protocol_version()); | |
| 326 // Size, in bytes, of a BLOCKED frame. | |
| 327 // The BLOCKED frame has no payload beyond the control frame header. | |
| 328 return GetControlFrameHeaderSize(); | |
| 329 } | |
| 330 | |
| 331 size_t SpdyFramer::GetPushPromiseMinimumSize() const { | |
| 332 DCHECK_LT(SPDY3, protocol_version()); | |
| 333 // Size, in bytes, of a PUSH_PROMISE frame, sans the embedded header block. | |
| 334 // Calculated as frame prefix + 4 (promised stream id). | |
| 335 return GetControlFrameHeaderSize() + 4; | |
| 336 } | |
| 337 | |
| 338 size_t SpdyFramer::GetContinuationMinimumSize() const { | |
| 339 // Size, in bytes, of a CONTINUATION frame not including the variable-length | |
| 340 // headers fragments. | |
| 341 return GetControlFrameHeaderSize(); | |
| 342 } | |
| 343 | |
| 344 size_t SpdyFramer::GetAltSvcMinimumSize() const { | |
| 345 // Size, in bytes, of an ALTSVC frame not including the Protocol-ID, Host, and | |
| 346 // (optional) Origin fields, all of which can vary in length. | |
| 347 // Note that this gives a lower bound on the frame size rather than a true | |
| 348 // minimum; the actual frame should always be larger than this. | |
| 349 // Calculated as frame prefix + 4 (max-age) + 2 (port) + 1 (reserved byte) | |
| 350 // + 1 (pid_len) + 1 (host_len). | |
| 351 return GetControlFrameHeaderSize() + 9; | |
| 352 } | |
| 353 | |
| 354 size_t SpdyFramer::GetPrioritySize() const { | |
| 355 // Size, in bytes, of a PRIORITY frame. | |
| 356 return GetControlFrameHeaderSize() + | |
| 357 kPriorityDependencyPayloadSize + | |
| 358 kPriorityWeightPayloadSize; | |
| 359 } | |
| 360 | |
| 361 size_t SpdyFramer::GetFrameMinimumSize() const { | |
| 362 return std::min(GetDataFrameMinimumSize(), GetControlFrameHeaderSize()); | |
| 363 } | |
| 364 | |
| 365 size_t SpdyFramer::GetFrameMaximumSize() const { | |
| 366 return SpdyConstants::GetFrameMaximumSize(protocol_version()); | |
| 367 } | |
| 368 | |
| 369 size_t SpdyFramer::GetDataFrameMaximumPayload() const { | |
| 370 return GetFrameMaximumSize() - GetDataFrameMinimumSize(); | |
| 371 } | |
| 372 | |
| 373 size_t SpdyFramer::GetPrefixLength(SpdyFrameType type) const { | |
| 374 return SpdyConstants::GetPrefixLength(type, protocol_version()); | |
| 375 } | |
| 376 | |
| 377 const char* SpdyFramer::StateToString(int state) { | |
| 378 switch (state) { | |
| 379 case SPDY_ERROR: | |
| 380 return "ERROR"; | |
| 381 case SPDY_AUTO_RESET: | |
| 382 return "AUTO_RESET"; | |
| 383 case SPDY_RESET: | |
| 384 return "RESET"; | |
| 385 case SPDY_READING_COMMON_HEADER: | |
| 386 return "READING_COMMON_HEADER"; | |
| 387 case SPDY_CONTROL_FRAME_PAYLOAD: | |
| 388 return "CONTROL_FRAME_PAYLOAD"; | |
| 389 case SPDY_READ_DATA_FRAME_PADDING_LENGTH: | |
| 390 return "SPDY_READ_DATA_FRAME_PADDING_LENGTH"; | |
| 391 case SPDY_CONSUME_PADDING: | |
| 392 return "SPDY_CONSUME_PADDING"; | |
| 393 case SPDY_IGNORE_REMAINING_PAYLOAD: | |
| 394 return "IGNORE_REMAINING_PAYLOAD"; | |
| 395 case SPDY_FORWARD_STREAM_FRAME: | |
| 396 return "FORWARD_STREAM_FRAME"; | |
| 397 case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK: | |
| 398 return "SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK"; | |
| 399 case SPDY_CONTROL_FRAME_HEADER_BLOCK: | |
| 400 return "SPDY_CONTROL_FRAME_HEADER_BLOCK"; | |
| 401 case SPDY_GOAWAY_FRAME_PAYLOAD: | |
| 402 return "SPDY_GOAWAY_FRAME_PAYLOAD"; | |
| 403 case SPDY_RST_STREAM_FRAME_PAYLOAD: | |
| 404 return "SPDY_RST_STREAM_FRAME_PAYLOAD"; | |
| 405 case SPDY_SETTINGS_FRAME_PAYLOAD: | |
| 406 return "SPDY_SETTINGS_FRAME_PAYLOAD"; | |
| 407 case SPDY_ALTSVC_FRAME_PAYLOAD: | |
| 408 return "SPDY_ALTSVC_FRAME_PAYLOAD"; | |
| 409 } | |
| 410 return "UNKNOWN_STATE"; | |
| 411 } | |
| 412 | |
| 413 void SpdyFramer::set_error(SpdyError error) { | |
| 414 DCHECK(visitor_); | |
| 415 error_code_ = error; | |
| 416 // These values will usually get reset once we come to the end | |
| 417 // of a header block, but if we run into an error that | |
| 418 // might not happen, so reset them here. | |
| 419 expect_continuation_ = 0; | |
| 420 end_stream_when_done_ = false; | |
| 421 | |
| 422 CHANGE_STATE(SPDY_ERROR); | |
| 423 visitor_->OnError(this); | |
| 424 } | |
| 425 | |
| 426 const char* SpdyFramer::ErrorCodeToString(int error_code) { | |
| 427 switch (error_code) { | |
| 428 case SPDY_NO_ERROR: | |
| 429 return "NO_ERROR"; | |
| 430 case SPDY_INVALID_CONTROL_FRAME: | |
| 431 return "INVALID_CONTROL_FRAME"; | |
| 432 case SPDY_CONTROL_PAYLOAD_TOO_LARGE: | |
| 433 return "CONTROL_PAYLOAD_TOO_LARGE"; | |
| 434 case SPDY_ZLIB_INIT_FAILURE: | |
| 435 return "ZLIB_INIT_FAILURE"; | |
| 436 case SPDY_UNSUPPORTED_VERSION: | |
| 437 return "UNSUPPORTED_VERSION"; | |
| 438 case SPDY_DECOMPRESS_FAILURE: | |
| 439 return "DECOMPRESS_FAILURE"; | |
| 440 case SPDY_COMPRESS_FAILURE: | |
| 441 return "COMPRESS_FAILURE"; | |
| 442 case SPDY_INVALID_DATA_FRAME_FLAGS: | |
| 443 return "SPDY_INVALID_DATA_FRAME_FLAGS"; | |
| 444 case SPDY_INVALID_CONTROL_FRAME_FLAGS: | |
| 445 return "SPDY_INVALID_CONTROL_FRAME_FLAGS"; | |
| 446 case SPDY_UNEXPECTED_FRAME: | |
| 447 return "UNEXPECTED_FRAME"; | |
| 448 } | |
| 449 return "UNKNOWN_ERROR"; | |
| 450 } | |
| 451 | |
| 452 const char* SpdyFramer::StatusCodeToString(int status_code) { | |
| 453 switch (status_code) { | |
| 454 case RST_STREAM_INVALID: | |
| 455 return "INVALID"; | |
| 456 case RST_STREAM_PROTOCOL_ERROR: | |
| 457 return "PROTOCOL_ERROR"; | |
| 458 case RST_STREAM_INVALID_STREAM: | |
| 459 return "INVALID_STREAM"; | |
| 460 case RST_STREAM_REFUSED_STREAM: | |
| 461 return "REFUSED_STREAM"; | |
| 462 case RST_STREAM_UNSUPPORTED_VERSION: | |
| 463 return "UNSUPPORTED_VERSION"; | |
| 464 case RST_STREAM_CANCEL: | |
| 465 return "CANCEL"; | |
| 466 case RST_STREAM_INTERNAL_ERROR: | |
| 467 return "INTERNAL_ERROR"; | |
| 468 case RST_STREAM_FLOW_CONTROL_ERROR: | |
| 469 return "FLOW_CONTROL_ERROR"; | |
| 470 case RST_STREAM_STREAM_IN_USE: | |
| 471 return "STREAM_IN_USE"; | |
| 472 case RST_STREAM_STREAM_ALREADY_CLOSED: | |
| 473 return "STREAM_ALREADY_CLOSED"; | |
| 474 case RST_STREAM_INVALID_CREDENTIALS: | |
| 475 return "INVALID_CREDENTIALS"; | |
| 476 case RST_STREAM_FRAME_TOO_LARGE: | |
| 477 return "FRAME_TOO_LARGE"; | |
| 478 case RST_STREAM_CONNECT_ERROR: | |
| 479 return "CONNECT_ERROR"; | |
| 480 case RST_STREAM_ENHANCE_YOUR_CALM: | |
| 481 return "ENHANCE_YOUR_CALM"; | |
| 482 case RST_STREAM_INADEQUATE_SECURITY: | |
| 483 return "INADEQUATE_SECURITY"; | |
| 484 case RST_STREAM_HTTP_1_1_REQUIRED: | |
| 485 return "HTTP_1_1_REQUIRED"; | |
| 486 } | |
| 487 return "UNKNOWN_STATUS"; | |
| 488 } | |
| 489 | |
| 490 const char* SpdyFramer::FrameTypeToString(SpdyFrameType type) { | |
| 491 switch (type) { | |
| 492 case DATA: | |
| 493 return "DATA"; | |
| 494 case SYN_STREAM: | |
| 495 return "SYN_STREAM"; | |
| 496 case SYN_REPLY: | |
| 497 return "SYN_REPLY"; | |
| 498 case RST_STREAM: | |
| 499 return "RST_STREAM"; | |
| 500 case SETTINGS: | |
| 501 return "SETTINGS"; | |
| 502 case PING: | |
| 503 return "PING"; | |
| 504 case GOAWAY: | |
| 505 return "GOAWAY"; | |
| 506 case HEADERS: | |
| 507 return "HEADERS"; | |
| 508 case WINDOW_UPDATE: | |
| 509 return "WINDOW_UPDATE"; | |
| 510 case CREDENTIAL: | |
| 511 return "CREDENTIAL"; | |
| 512 case PUSH_PROMISE: | |
| 513 return "PUSH_PROMISE"; | |
| 514 case CONTINUATION: | |
| 515 return "CONTINUATION"; | |
| 516 case PRIORITY: | |
| 517 return "PRIORITY"; | |
| 518 case ALTSVC: | |
| 519 return "ALTSVC"; | |
| 520 case BLOCKED: | |
| 521 return "BLOCKED"; | |
| 522 } | |
| 523 return "UNKNOWN_CONTROL_TYPE"; | |
| 524 } | |
| 525 | |
| 526 size_t SpdyFramer::ProcessInput(const char* data, size_t len) { | |
| 527 DCHECK(visitor_); | |
| 528 DCHECK(data); | |
| 529 | |
| 530 size_t original_len = len; | |
| 531 do { | |
| 532 previous_state_ = state_; | |
| 533 switch (state_) { | |
| 534 case SPDY_ERROR: | |
| 535 goto bottom; | |
| 536 | |
| 537 case SPDY_AUTO_RESET: | |
| 538 case SPDY_RESET: | |
| 539 Reset(); | |
| 540 if (len > 0) { | |
| 541 CHANGE_STATE(SPDY_READING_COMMON_HEADER); | |
| 542 } | |
| 543 break; | |
| 544 | |
| 545 case SPDY_READING_COMMON_HEADER: { | |
| 546 size_t bytes_read = ProcessCommonHeader(data, len); | |
| 547 len -= bytes_read; | |
| 548 data += bytes_read; | |
| 549 break; | |
| 550 } | |
| 551 | |
| 552 case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK: { | |
| 553 // Control frames that contain header blocks | |
| 554 // (SYN_STREAM, SYN_REPLY, HEADERS, PUSH_PROMISE, CONTINUATION) | |
| 555 // take a different path through the state machine - they | |
| 556 // will go: | |
| 557 // 1. SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK | |
| 558 // 2. SPDY_CONTROL_FRAME_HEADER_BLOCK | |
| 559 // | |
| 560 // SETTINGS frames take a slightly modified route: | |
| 561 // 1. SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK | |
| 562 // 2. SPDY_SETTINGS_FRAME_PAYLOAD | |
| 563 // | |
| 564 // All other control frames will use the alternate route directly to | |
| 565 // SPDY_CONTROL_FRAME_PAYLOAD | |
| 566 int bytes_read = ProcessControlFrameBeforeHeaderBlock(data, len); | |
| 567 len -= bytes_read; | |
| 568 data += bytes_read; | |
| 569 break; | |
| 570 } | |
| 571 | |
| 572 case SPDY_SETTINGS_FRAME_PAYLOAD: { | |
| 573 int bytes_read = ProcessSettingsFramePayload(data, len); | |
| 574 len -= bytes_read; | |
| 575 data += bytes_read; | |
| 576 break; | |
| 577 } | |
| 578 | |
| 579 case SPDY_CONTROL_FRAME_HEADER_BLOCK: { | |
| 580 int bytes_read = ProcessControlFrameHeaderBlock( | |
| 581 data, len, protocol_version() > SPDY3); | |
| 582 len -= bytes_read; | |
| 583 data += bytes_read; | |
| 584 break; | |
| 585 } | |
| 586 | |
| 587 case SPDY_RST_STREAM_FRAME_PAYLOAD: { | |
| 588 size_t bytes_read = ProcessRstStreamFramePayload(data, len); | |
| 589 len -= bytes_read; | |
| 590 data += bytes_read; | |
| 591 break; | |
| 592 } | |
| 593 | |
| 594 case SPDY_GOAWAY_FRAME_PAYLOAD: { | |
| 595 size_t bytes_read = ProcessGoAwayFramePayload(data, len); | |
| 596 len -= bytes_read; | |
| 597 data += bytes_read; | |
| 598 break; | |
| 599 } | |
| 600 | |
| 601 case SPDY_ALTSVC_FRAME_PAYLOAD: { | |
| 602 size_t bytes_read = ProcessAltSvcFramePayload(data, len); | |
| 603 len -= bytes_read; | |
| 604 data += bytes_read; | |
| 605 break; | |
| 606 } | |
| 607 | |
| 608 case SPDY_CONTROL_FRAME_PAYLOAD: { | |
| 609 size_t bytes_read = ProcessControlFramePayload(data, len); | |
| 610 len -= bytes_read; | |
| 611 data += bytes_read; | |
| 612 break; | |
| 613 } | |
| 614 | |
| 615 case SPDY_READ_DATA_FRAME_PADDING_LENGTH: { | |
| 616 size_t bytes_read = ProcessDataFramePaddingLength(data, len); | |
| 617 len -= bytes_read; | |
| 618 data += bytes_read; | |
| 619 break; | |
| 620 } | |
| 621 | |
| 622 case SPDY_CONSUME_PADDING: { | |
| 623 size_t bytes_read = ProcessFramePadding(data, len); | |
| 624 len -= bytes_read; | |
| 625 data += bytes_read; | |
| 626 break; | |
| 627 } | |
| 628 | |
| 629 case SPDY_IGNORE_REMAINING_PAYLOAD: { | |
| 630 size_t bytes_read = ProcessIgnoredControlFramePayload(/*data,*/ len); | |
| 631 len -= bytes_read; | |
| 632 data += bytes_read; | |
| 633 break; | |
| 634 } | |
| 635 | |
| 636 case SPDY_FORWARD_STREAM_FRAME: { | |
| 637 size_t bytes_read = ProcessDataFramePayload(data, len); | |
| 638 len -= bytes_read; | |
| 639 data += bytes_read; | |
| 640 break; | |
| 641 } | |
| 642 | |
| 643 default: | |
| 644 LOG(DFATAL) << "Invalid value for " << display_protocol_ | |
| 645 << " framer state: " << state_; | |
| 646 // This ensures that we don't infinite-loop if state_ gets an | |
| 647 // invalid value somehow, such as due to a SpdyFramer getting deleted | |
| 648 // from a callback it calls. | |
| 649 goto bottom; | |
| 650 } | |
| 651 } while (state_ != previous_state_); | |
| 652 bottom: | |
| 653 DCHECK(len == 0 || state_ == SPDY_ERROR); | |
| 654 if (current_frame_buffer_length_ == 0 && | |
| 655 remaining_data_length_ == 0 && | |
| 656 remaining_control_header_ == 0) { | |
| 657 DCHECK(state_ == SPDY_RESET || state_ == SPDY_ERROR) | |
| 658 << "State: " << StateToString(state_); | |
| 659 } | |
| 660 | |
| 661 return original_len - len; | |
| 662 } | |
| 663 | |
| 664 size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) { | |
| 665 // This should only be called when we're in the SPDY_READING_COMMON_HEADER | |
| 666 // state. | |
| 667 DCHECK_EQ(state_, SPDY_READING_COMMON_HEADER); | |
| 668 | |
| 669 size_t original_len = len; | |
| 670 | |
| 671 // Update current frame buffer as needed. | |
| 672 if (current_frame_buffer_length_ < GetControlFrameHeaderSize()) { | |
| 673 size_t bytes_desired = | |
| 674 GetControlFrameHeaderSize() - current_frame_buffer_length_; | |
| 675 UpdateCurrentFrameBuffer(&data, &len, bytes_desired); | |
| 676 } | |
| 677 | |
| 678 if (current_frame_buffer_length_ < GetControlFrameHeaderSize()) { | |
| 679 // Not enough information to do anything meaningful. | |
| 680 return original_len - len; | |
| 681 } | |
| 682 | |
| 683 // Using a scoped_ptr here since we may need to create a new SpdyFrameReader | |
| 684 // when processing DATA frames below. | |
| 685 scoped_ptr<SpdyFrameReader> reader( | |
| 686 new SpdyFrameReader(current_frame_buffer_.get(), | |
| 687 current_frame_buffer_length_)); | |
| 688 | |
| 689 bool is_control_frame = false; | |
| 690 | |
| 691 int control_frame_type_field = | |
| 692 SpdyConstants::DataFrameType(protocol_version()); | |
| 693 // ProcessControlFrameHeader() will set current_frame_type_ to the | |
| 694 // correct value if this is a valid control frame. | |
| 695 current_frame_type_ = DATA; | |
| 696 if (protocol_version() <= SPDY3) { | |
| 697 uint16 version = 0; | |
| 698 bool successful_read = reader->ReadUInt16(&version); | |
| 699 DCHECK(successful_read); | |
| 700 is_control_frame = (version & kControlFlagMask) != 0; | |
| 701 version &= ~kControlFlagMask; // Only valid for control frames. | |
| 702 if (is_control_frame) { | |
| 703 // We check version before we check validity: version can never be | |
| 704 // 'invalid', it can only be unsupported. | |
| 705 if (version < SpdyConstants::SerializeMajorVersion(SPDY_MIN_VERSION) || | |
| 706 version > SpdyConstants::SerializeMajorVersion(SPDY_MAX_VERSION) || | |
| 707 SpdyConstants::ParseMajorVersion(version) != protocol_version()) { | |
| 708 // Version does not match the version the framer was initialized with. | |
| 709 DVLOG(1) << "Unsupported SPDY version " | |
| 710 << version | |
| 711 << " (expected " << protocol_version() << ")"; | |
| 712 set_error(SPDY_UNSUPPORTED_VERSION); | |
| 713 return 0; | |
| 714 } | |
| 715 // We check control_frame_type_field's validity in | |
| 716 // ProcessControlFrameHeader(). | |
| 717 uint16 control_frame_type_field_uint16; | |
| 718 successful_read = reader->ReadUInt16(&control_frame_type_field_uint16); | |
| 719 control_frame_type_field = control_frame_type_field_uint16; | |
| 720 } else { | |
| 721 reader->Rewind(); | |
| 722 successful_read = reader->ReadUInt31(¤t_frame_stream_id_); | |
| 723 } | |
| 724 DCHECK(successful_read); | |
| 725 | |
| 726 successful_read = reader->ReadUInt8(¤t_frame_flags_); | |
| 727 DCHECK(successful_read); | |
| 728 | |
| 729 uint32 length_field = 0; | |
| 730 successful_read = reader->ReadUInt24(&length_field); | |
| 731 DCHECK(successful_read); | |
| 732 remaining_data_length_ = length_field; | |
| 733 current_frame_length_ = remaining_data_length_ + reader->GetBytesConsumed(); | |
| 734 } else { | |
| 735 uint32 length_field = 0; | |
| 736 bool successful_read = reader->ReadUInt24(&length_field); | |
| 737 DCHECK(successful_read); | |
| 738 | |
| 739 uint8 control_frame_type_field_uint8; | |
| 740 successful_read = reader->ReadUInt8(&control_frame_type_field_uint8); | |
| 741 DCHECK(successful_read); | |
| 742 // We check control_frame_type_field's validity in | |
| 743 // ProcessControlFrameHeader(). | |
| 744 control_frame_type_field = control_frame_type_field_uint8; | |
| 745 is_control_frame = control_frame_type_field != | |
| 746 SpdyConstants::SerializeFrameType(protocol_version(), DATA); | |
| 747 | |
| 748 if (is_control_frame) { | |
| 749 current_frame_length_ = length_field + GetControlFrameHeaderSize(); | |
| 750 } else { | |
| 751 current_frame_length_ = length_field + GetDataFrameMinimumSize(); | |
| 752 } | |
| 753 | |
| 754 successful_read = reader->ReadUInt8(¤t_frame_flags_); | |
| 755 DCHECK(successful_read); | |
| 756 | |
| 757 successful_read = reader->ReadUInt31(¤t_frame_stream_id_); | |
| 758 DCHECK(successful_read); | |
| 759 | |
| 760 remaining_data_length_ = current_frame_length_ - reader->GetBytesConsumed(); | |
| 761 | |
| 762 // Before we accept a DATA frame, we need to make sure we're not in the | |
| 763 // middle of processing a header block. | |
| 764 const bool is_continuation_frame = (control_frame_type_field == | |
| 765 SpdyConstants::SerializeFrameType(protocol_version(), CONTINUATION)); | |
| 766 if ((expect_continuation_ != 0) != is_continuation_frame) { | |
| 767 if (expect_continuation_ != 0) { | |
| 768 DLOG(ERROR) << "The framer was expecting to receive a CONTINUATION " | |
| 769 << "frame, but instead received frame type " | |
| 770 << control_frame_type_field; | |
| 771 } else { | |
| 772 DLOG(ERROR) << "The framer received an unexpected CONTINUATION frame."; | |
| 773 } | |
| 774 set_error(SPDY_UNEXPECTED_FRAME); | |
| 775 return original_len - len; | |
| 776 } | |
| 777 } | |
| 778 DCHECK_EQ(is_control_frame ? GetControlFrameHeaderSize() | |
| 779 : GetDataFrameMinimumSize(), | |
| 780 reader->GetBytesConsumed()); | |
| 781 DCHECK_EQ(current_frame_length_, | |
| 782 remaining_data_length_ + reader->GetBytesConsumed()); | |
| 783 | |
| 784 // This is just a sanity check for help debugging early frame errors. | |
| 785 if (remaining_data_length_ > 1000000u) { | |
| 786 // The strncmp for 5 is safe because we only hit this point if we | |
| 787 // have kMinCommonHeader (8) bytes | |
| 788 if (!syn_frame_processed_ && | |
| 789 strncmp(current_frame_buffer_.get(), "HTTP/", 5) == 0) { | |
| 790 LOG(WARNING) << "Unexpected HTTP response to " << display_protocol_ | |
| 791 << " request"; | |
| 792 probable_http_response_ = true; | |
| 793 } else { | |
| 794 LOG(WARNING) << "Unexpectedly large frame. " << display_protocol_ | |
| 795 << " session is likely corrupt."; | |
| 796 } | |
| 797 } | |
| 798 | |
| 799 // if we're here, then we have the common header all received. | |
| 800 if (!is_control_frame) { | |
| 801 if (protocol_version() > SPDY3) { | |
| 802 // Catch bogus tests sending oversized DATA frames. | |
| 803 DCHECK_GE(GetFrameMaximumSize(), current_frame_length_) | |
| 804 << "DATA frame too large for SPDY >= 4."; | |
| 805 } | |
| 806 | |
| 807 uint8 valid_data_flags = 0; | |
| 808 if (protocol_version() > SPDY3) { | |
| 809 valid_data_flags = | |
| 810 DATA_FLAG_FIN | DATA_FLAG_END_SEGMENT | DATA_FLAG_PADDED; | |
| 811 } else { | |
| 812 valid_data_flags = DATA_FLAG_FIN; | |
| 813 } | |
| 814 | |
| 815 if (current_frame_flags_ & ~valid_data_flags) { | |
| 816 set_error(SPDY_INVALID_DATA_FRAME_FLAGS); | |
| 817 } else { | |
| 818 visitor_->OnDataFrameHeader(current_frame_stream_id_, | |
| 819 remaining_data_length_, | |
| 820 current_frame_flags_ & DATA_FLAG_FIN); | |
| 821 if (remaining_data_length_ > 0) { | |
| 822 CHANGE_STATE(SPDY_READ_DATA_FRAME_PADDING_LENGTH); | |
| 823 } else { | |
| 824 // Empty data frame. | |
| 825 if (current_frame_flags_ & DATA_FLAG_FIN) { | |
| 826 visitor_->OnStreamFrameData( | |
| 827 current_frame_stream_id_, NULL, 0, true); | |
| 828 } | |
| 829 CHANGE_STATE(SPDY_AUTO_RESET); | |
| 830 } | |
| 831 } | |
| 832 } else { | |
| 833 ProcessControlFrameHeader(control_frame_type_field); | |
| 834 } | |
| 835 | |
| 836 return original_len - len; | |
| 837 } | |
| 838 | |
| 839 void SpdyFramer::ProcessControlFrameHeader(int control_frame_type_field) { | |
| 840 DCHECK_EQ(SPDY_NO_ERROR, error_code_); | |
| 841 DCHECK_LE(GetControlFrameHeaderSize(), current_frame_buffer_length_); | |
| 842 | |
| 843 // TODO(mlavan): Either remove credential frames from the code entirely, | |
| 844 // or add them to parsing + serialization methods for SPDY3. | |
| 845 // Early detection of deprecated frames that we ignore. | |
| 846 if (protocol_version() <= SPDY3) { | |
| 847 if (control_frame_type_field == CREDENTIAL) { | |
| 848 current_frame_type_ = CREDENTIAL; | |
| 849 DCHECK_EQ(SPDY3, protocol_version()); | |
| 850 DVLOG(1) << "CREDENTIAL control frame found. Ignoring."; | |
| 851 CHANGE_STATE(SPDY_IGNORE_REMAINING_PAYLOAD); | |
| 852 return; | |
| 853 } | |
| 854 } | |
| 855 | |
| 856 if (!SpdyConstants::IsValidFrameType(protocol_version(), | |
| 857 control_frame_type_field)) { | |
| 858 if (protocol_version() <= SPDY3) { | |
| 859 DLOG(WARNING) << "Invalid control frame type " << control_frame_type_field | |
| 860 << " (protocol version: " << protocol_version() << ")"; | |
| 861 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 862 return; | |
| 863 } else { | |
| 864 // In HTTP2 we ignore unknown frame types for extensibility, as long as | |
| 865 // the rest of the control frame header is valid. | |
| 866 // We rely on the visitor to check validity of current_frame_stream_id_. | |
| 867 bool valid_stream = visitor_->OnUnknownFrame(current_frame_stream_id_, | |
| 868 control_frame_type_field); | |
| 869 if (valid_stream) { | |
| 870 DVLOG(1) << "Ignoring unknown frame type."; | |
| 871 CHANGE_STATE(SPDY_IGNORE_REMAINING_PAYLOAD); | |
| 872 } else { | |
| 873 // Report an invalid frame error and close the stream if the | |
| 874 // stream_id is not valid. | |
| 875 DLOG(WARNING) << "Unknown control frame type " | |
| 876 << control_frame_type_field | |
| 877 << " received on invalid stream " | |
| 878 << current_frame_stream_id_; | |
| 879 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 880 } | |
| 881 return; | |
| 882 } | |
| 883 } | |
| 884 | |
| 885 current_frame_type_ = SpdyConstants::ParseFrameType(protocol_version(), | |
| 886 control_frame_type_field); | |
| 887 | |
| 888 // Do some sanity checking on the control frame sizes and flags. | |
| 889 switch (current_frame_type_) { | |
| 890 case SYN_STREAM: | |
| 891 if (current_frame_length_ < GetSynStreamMinimumSize()) { | |
| 892 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 893 } else if (current_frame_flags_ & | |
| 894 ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) { | |
| 895 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 896 } | |
| 897 break; | |
| 898 case SYN_REPLY: | |
| 899 if (current_frame_length_ < GetSynReplyMinimumSize()) { | |
| 900 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 901 } else if (current_frame_flags_ & ~CONTROL_FLAG_FIN) { | |
| 902 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 903 } | |
| 904 break; | |
| 905 case RST_STREAM: | |
| 906 // For SPDY versions < 4, the header has a fixed length. | |
| 907 // For SPDY version 4 and up, the RST_STREAM frame may include optional | |
| 908 // opaque data, so we only have a lower limit on the frame size. | |
| 909 if ((current_frame_length_ != GetRstStreamMinimumSize() && | |
| 910 protocol_version() <= SPDY3) || | |
| 911 (current_frame_length_ < GetRstStreamMinimumSize() && | |
| 912 protocol_version() > SPDY3)) { | |
| 913 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 914 } else if (current_frame_flags_ != 0) { | |
| 915 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 916 } | |
| 917 break; | |
| 918 case SETTINGS: | |
| 919 { | |
| 920 // Make sure that we have an integral number of 8-byte key/value pairs, | |
| 921 // plus a 4-byte length field in SPDY3 and below. | |
| 922 size_t values_prefix_size = (protocol_version() <= SPDY3 ? 4 : 0); | |
| 923 // Size of each key/value pair in bytes. | |
| 924 size_t setting_size = SpdyConstants::GetSettingSize(protocol_version()); | |
| 925 if (current_frame_length_ < GetSettingsMinimumSize() || | |
| 926 (current_frame_length_ - GetControlFrameHeaderSize()) | |
| 927 % setting_size != values_prefix_size) { | |
| 928 DLOG(WARNING) << "Invalid length for SETTINGS frame: " | |
| 929 << current_frame_length_; | |
| 930 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 931 } else if (protocol_version() <= SPDY3 && | |
| 932 current_frame_flags_ & | |
| 933 ~SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS) { | |
| 934 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 935 } else if (protocol_version() > SPDY3 && | |
| 936 current_frame_flags_ & ~SETTINGS_FLAG_ACK) { | |
| 937 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 938 } else if (protocol_version() > SPDY3 && | |
| 939 current_frame_flags_ & SETTINGS_FLAG_ACK && | |
| 940 current_frame_length_ > GetSettingsMinimumSize()) { | |
| 941 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 942 } | |
| 943 break; | |
| 944 } | |
| 945 case PING: | |
| 946 if (current_frame_length_ != GetPingSize()) { | |
| 947 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 948 } else if ((protocol_version() <= SPDY3 && current_frame_flags_ != 0) || | |
| 949 (current_frame_flags_ & ~PING_FLAG_ACK)) { | |
| 950 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 951 } | |
| 952 break; | |
| 953 case GOAWAY: | |
| 954 { | |
| 955 // For SPDY version < 4, there are only mandatory fields and the header | |
| 956 // has a fixed length. For SPDY version >= 4, optional opaque data may | |
| 957 // be appended to the GOAWAY frame, thus there is only a minimal length | |
| 958 // restriction. | |
| 959 if ((current_frame_length_ != GetGoAwayMinimumSize() && | |
| 960 protocol_version() <= SPDY3) || | |
| 961 (current_frame_length_ < GetGoAwayMinimumSize() && | |
| 962 protocol_version() > SPDY3)) { | |
| 963 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 964 } else if (current_frame_flags_ != 0) { | |
| 965 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 966 } | |
| 967 break; | |
| 968 } | |
| 969 case HEADERS: | |
| 970 { | |
| 971 size_t min_size = GetHeadersMinimumSize(); | |
| 972 if (protocol_version() > SPDY3 && | |
| 973 (current_frame_flags_ & HEADERS_FLAG_PRIORITY)) { | |
| 974 min_size += 4; | |
| 975 } | |
| 976 if (current_frame_length_ < min_size) { | |
| 977 // TODO(mlavan): check here for HEADERS with no payload? | |
| 978 // (not allowed in SPDY4) | |
| 979 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 980 } else if (protocol_version() <= SPDY3 && | |
| 981 current_frame_flags_ & ~CONTROL_FLAG_FIN) { | |
| 982 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 983 } else if (protocol_version() > SPDY3 && | |
| 984 current_frame_flags_ & | |
| 985 ~(CONTROL_FLAG_FIN | HEADERS_FLAG_PRIORITY | | |
| 986 HEADERS_FLAG_END_HEADERS | HEADERS_FLAG_END_SEGMENT | | |
| 987 HEADERS_FLAG_PADDED)) { | |
| 988 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 989 } | |
| 990 } | |
| 991 break; | |
| 992 case WINDOW_UPDATE: | |
| 993 if (current_frame_length_ != GetWindowUpdateSize()) { | |
| 994 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 995 } else if (current_frame_flags_ != 0) { | |
| 996 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 997 } | |
| 998 break; | |
| 999 case BLOCKED: | |
| 1000 if (current_frame_length_ != GetBlockedSize() || | |
| 1001 protocol_version() <= SPDY3) { | |
| 1002 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 1003 } else if (current_frame_flags_ != 0) { | |
| 1004 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 1005 } | |
| 1006 break; | |
| 1007 case PUSH_PROMISE: | |
| 1008 if (current_frame_length_ < GetPushPromiseMinimumSize()) { | |
| 1009 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 1010 } else if (protocol_version() <= SPDY3 && current_frame_flags_ != 0) { | |
| 1011 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 1012 } else if (protocol_version() > SPDY3 && | |
| 1013 current_frame_flags_ & | |
| 1014 ~(PUSH_PROMISE_FLAG_END_PUSH_PROMISE | | |
| 1015 HEADERS_FLAG_PADDED)) { | |
| 1016 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 1017 } | |
| 1018 break; | |
| 1019 case CONTINUATION: | |
| 1020 if (current_frame_length_ < GetContinuationMinimumSize() || | |
| 1021 protocol_version() <= SPDY3) { | |
| 1022 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 1023 } else if (current_frame_flags_ & ~HEADERS_FLAG_END_HEADERS) { | |
| 1024 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 1025 } | |
| 1026 break; | |
| 1027 case ALTSVC: | |
| 1028 if (current_frame_length_ <= GetAltSvcMinimumSize()) { | |
| 1029 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 1030 } else if (current_frame_flags_ != 0) { | |
| 1031 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 1032 } | |
| 1033 break; | |
| 1034 case PRIORITY: | |
| 1035 if (current_frame_length_ != GetPrioritySize() || | |
| 1036 protocol_version() <= SPDY3) { | |
| 1037 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 1038 } else if (current_frame_flags_ != 0) { | |
| 1039 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | |
| 1040 } | |
| 1041 break; | |
| 1042 default: | |
| 1043 LOG(WARNING) << "Valid " << display_protocol_ | |
| 1044 << " control frame with unhandled type: " | |
| 1045 << current_frame_type_; | |
| 1046 // This branch should be unreachable because of the frame type bounds | |
| 1047 // check above. However, we DLOG(FATAL) here in an effort to painfully | |
| 1048 // club the head of the developer who failed to keep this file in sync | |
| 1049 // with spdy_protocol.h. | |
| 1050 DLOG(FATAL); | |
| 1051 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 1052 break; | |
| 1053 } | |
| 1054 | |
| 1055 if (state_ == SPDY_ERROR) { | |
| 1056 return; | |
| 1057 } | |
| 1058 | |
| 1059 if (current_frame_length_ > | |
| 1060 SpdyConstants::GetFrameMaximumSize(protocol_version()) + | |
| 1061 SpdyConstants::GetControlFrameHeaderSize(protocol_version())) { | |
| 1062 DLOG(WARNING) << "Received control frame of type " << current_frame_type_ | |
| 1063 << " with way too big of a payload: " | |
| 1064 << current_frame_length_; | |
| 1065 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE); | |
| 1066 return; | |
| 1067 } | |
| 1068 | |
| 1069 if (current_frame_type_ == GOAWAY) { | |
| 1070 CHANGE_STATE(SPDY_GOAWAY_FRAME_PAYLOAD); | |
| 1071 return; | |
| 1072 } | |
| 1073 | |
| 1074 if (current_frame_type_ == RST_STREAM) { | |
| 1075 CHANGE_STATE(SPDY_RST_STREAM_FRAME_PAYLOAD); | |
| 1076 return; | |
| 1077 } | |
| 1078 | |
| 1079 if (current_frame_type_ == ALTSVC) { | |
| 1080 CHANGE_STATE(SPDY_ALTSVC_FRAME_PAYLOAD); | |
| 1081 return; | |
| 1082 } | |
| 1083 // Determine the frame size without variable-length data. | |
| 1084 int32 frame_size_without_variable_data; | |
| 1085 switch (current_frame_type_) { | |
| 1086 case SYN_STREAM: | |
| 1087 syn_frame_processed_ = true; | |
| 1088 frame_size_without_variable_data = GetSynStreamMinimumSize(); | |
| 1089 break; | |
| 1090 case SYN_REPLY: | |
| 1091 syn_frame_processed_ = true; | |
| 1092 frame_size_without_variable_data = GetSynReplyMinimumSize(); | |
| 1093 break; | |
| 1094 case SETTINGS: | |
| 1095 frame_size_without_variable_data = GetSettingsMinimumSize(); | |
| 1096 break; | |
| 1097 case HEADERS: | |
| 1098 frame_size_without_variable_data = GetHeadersMinimumSize(); | |
| 1099 if (protocol_version() > SPDY3) { | |
| 1100 if (current_frame_flags_ & HEADERS_FLAG_PADDED) { | |
| 1101 frame_size_without_variable_data += kPadLengthFieldSize; | |
| 1102 } | |
| 1103 if (current_frame_flags_ & HEADERS_FLAG_PRIORITY) { | |
| 1104 frame_size_without_variable_data += | |
| 1105 kPriorityDependencyPayloadSize + | |
| 1106 kPriorityWeightPayloadSize; | |
| 1107 } | |
| 1108 } | |
| 1109 break; | |
| 1110 case PUSH_PROMISE: | |
| 1111 frame_size_without_variable_data = GetPushPromiseMinimumSize(); | |
| 1112 if (protocol_version() > SPDY3 && | |
| 1113 current_frame_flags_ & PUSH_PROMISE_FLAG_PADDED) { | |
| 1114 frame_size_without_variable_data += kPadLengthFieldSize; | |
| 1115 } | |
| 1116 break; | |
| 1117 case CONTINUATION: | |
| 1118 frame_size_without_variable_data = GetContinuationMinimumSize(); | |
| 1119 break; | |
| 1120 default: | |
| 1121 frame_size_without_variable_data = -1; | |
| 1122 break; | |
| 1123 } | |
| 1124 | |
| 1125 if ((frame_size_without_variable_data == -1) && | |
| 1126 (current_frame_length_ > kControlFrameBufferSize)) { | |
| 1127 // We should already be in an error state. Double-check. | |
| 1128 DCHECK_EQ(SPDY_ERROR, state_); | |
| 1129 if (state_ != SPDY_ERROR) { | |
| 1130 LOG(DFATAL) << display_protocol_ | |
| 1131 << " control frame buffer too small for fixed-length frame."; | |
| 1132 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE); | |
| 1133 } | |
| 1134 return; | |
| 1135 } | |
| 1136 | |
| 1137 if (frame_size_without_variable_data > 0) { | |
| 1138 // We have a control frame with a header block. We need to parse the | |
| 1139 // remainder of the control frame's header before we can parse the header | |
| 1140 // block. The start of the header block varies with the control type. | |
| 1141 DCHECK_GE(frame_size_without_variable_data, | |
| 1142 static_cast<int32>(current_frame_buffer_length_)); | |
| 1143 remaining_control_header_ = frame_size_without_variable_data - | |
| 1144 current_frame_buffer_length_; | |
| 1145 | |
| 1146 CHANGE_STATE(SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK); | |
| 1147 return; | |
| 1148 } | |
| 1149 | |
| 1150 CHANGE_STATE(SPDY_CONTROL_FRAME_PAYLOAD); | |
| 1151 } | |
| 1152 | |
| 1153 size_t SpdyFramer::UpdateCurrentFrameBuffer(const char** data, size_t* len, | |
| 1154 size_t max_bytes) { | |
| 1155 size_t bytes_to_read = std::min(*len, max_bytes); | |
| 1156 if (bytes_to_read > 0) { | |
| 1157 DCHECK_GE(kControlFrameBufferSize, | |
| 1158 current_frame_buffer_length_ + bytes_to_read); | |
| 1159 memcpy(current_frame_buffer_.get() + current_frame_buffer_length_, | |
| 1160 *data, | |
| 1161 bytes_to_read); | |
| 1162 current_frame_buffer_length_ += bytes_to_read; | |
| 1163 *data += bytes_to_read; | |
| 1164 *len -= bytes_to_read; | |
| 1165 } | |
| 1166 return bytes_to_read; | |
| 1167 } | |
| 1168 | |
| 1169 size_t SpdyFramer::GetSerializedLength( | |
| 1170 const SpdyMajorVersion spdy_version, | |
| 1171 const SpdyHeaderBlock* headers) { | |
| 1172 const size_t num_name_value_pairs_size | |
| 1173 = (spdy_version < SPDY3) ? sizeof(uint16) : sizeof(uint32); | |
| 1174 const size_t length_of_name_size = num_name_value_pairs_size; | |
| 1175 const size_t length_of_value_size = num_name_value_pairs_size; | |
| 1176 | |
| 1177 size_t total_length = num_name_value_pairs_size; | |
| 1178 for (SpdyHeaderBlock::const_iterator it = headers->begin(); | |
| 1179 it != headers->end(); | |
| 1180 ++it) { | |
| 1181 // We add space for the length of the name and the length of the value as | |
| 1182 // well as the length of the name and the length of the value. | |
| 1183 total_length += length_of_name_size + it->first.size() + | |
| 1184 length_of_value_size + it->second.size(); | |
| 1185 } | |
| 1186 return total_length; | |
| 1187 } | |
| 1188 | |
| 1189 void SpdyFramer::WriteHeaderBlock(SpdyFrameBuilder* frame, | |
| 1190 const SpdyMajorVersion spdy_version, | |
| 1191 const SpdyHeaderBlock* headers) { | |
| 1192 if (spdy_version < SPDY3) { | |
| 1193 frame->WriteUInt16(static_cast<uint16>(headers->size())); | |
| 1194 } else { | |
| 1195 frame->WriteUInt32(headers->size()); | |
| 1196 } | |
| 1197 SpdyHeaderBlock::const_iterator it; | |
| 1198 for (it = headers->begin(); it != headers->end(); ++it) { | |
| 1199 if (spdy_version < SPDY3) { | |
| 1200 frame->WriteString(it->first); | |
| 1201 frame->WriteString(it->second); | |
| 1202 } else { | |
| 1203 frame->WriteStringPiece32(it->first); | |
| 1204 frame->WriteStringPiece32(it->second); | |
| 1205 } | |
| 1206 } | |
| 1207 } | |
| 1208 | |
| 1209 // TODO(phajdan.jr): Clean up after we no longer need | |
| 1210 // to workaround http://crbug.com/139744. | |
| 1211 #if !defined(USE_SYSTEM_ZLIB) | |
| 1212 | |
| 1213 // These constants are used by zlib to differentiate between normal data and | |
| 1214 // cookie data. Cookie data is handled specially by zlib when compressing. | |
| 1215 enum ZDataClass { | |
| 1216 // kZStandardData is compressed normally, save that it will never match | |
| 1217 // against any other class of data in the window. | |
| 1218 kZStandardData = Z_CLASS_STANDARD, | |
| 1219 // kZCookieData is compressed in its own Huffman blocks and only matches in | |
| 1220 // its entirety and only against other kZCookieData blocks. Any matches must | |
| 1221 // be preceeded by a kZStandardData byte, or a semicolon to prevent matching | |
| 1222 // a suffix. It's assumed that kZCookieData ends in a semicolon to prevent | |
| 1223 // prefix matches. | |
| 1224 kZCookieData = Z_CLASS_COOKIE, | |
| 1225 // kZHuffmanOnlyData is only Huffman compressed - no matches are performed | |
| 1226 // against the window. | |
| 1227 kZHuffmanOnlyData = Z_CLASS_HUFFMAN_ONLY, | |
| 1228 }; | |
| 1229 | |
| 1230 // WriteZ writes |data| to the deflate context |out|. WriteZ will flush as | |
| 1231 // needed when switching between classes of data. | |
| 1232 static void WriteZ(const base::StringPiece& data, | |
| 1233 ZDataClass clas, | |
| 1234 z_stream* out) { | |
| 1235 int rv; | |
| 1236 | |
| 1237 // If we are switching from standard to non-standard data then we need to end | |
| 1238 // the current Huffman context to avoid it leaking between them. | |
| 1239 if (out->clas == kZStandardData && | |
| 1240 clas != kZStandardData) { | |
| 1241 out->avail_in = 0; | |
| 1242 rv = deflate(out, Z_PARTIAL_FLUSH); | |
| 1243 DCHECK_EQ(Z_OK, rv); | |
| 1244 DCHECK_EQ(0u, out->avail_in); | |
| 1245 DCHECK_LT(0u, out->avail_out); | |
| 1246 } | |
| 1247 | |
| 1248 out->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data.data())); | |
| 1249 out->avail_in = data.size(); | |
| 1250 out->clas = clas; | |
| 1251 if (clas == kZStandardData) { | |
| 1252 rv = deflate(out, Z_NO_FLUSH); | |
| 1253 } else { | |
| 1254 rv = deflate(out, Z_PARTIAL_FLUSH); | |
| 1255 } | |
| 1256 if (!data.empty()) { | |
| 1257 // If we didn't provide any data then zlib will return Z_BUF_ERROR. | |
| 1258 DCHECK_EQ(Z_OK, rv); | |
| 1259 } | |
| 1260 DCHECK_EQ(0u, out->avail_in); | |
| 1261 DCHECK_LT(0u, out->avail_out); | |
| 1262 } | |
| 1263 | |
| 1264 // WriteLengthZ writes |n| as a |length|-byte, big-endian number to |out|. | |
| 1265 static void WriteLengthZ(size_t n, | |
| 1266 unsigned length, | |
| 1267 ZDataClass clas, | |
| 1268 z_stream* out) { | |
| 1269 char buf[4]; | |
| 1270 DCHECK_LE(length, sizeof(buf)); | |
| 1271 for (unsigned i = 1; i <= length; i++) { | |
| 1272 buf[length - i] = static_cast<char>(n); | |
| 1273 n >>= 8; | |
| 1274 } | |
| 1275 WriteZ(base::StringPiece(buf, length), clas, out); | |
| 1276 } | |
| 1277 | |
| 1278 // WriteHeaderBlockToZ serialises |headers| to the deflate context |z| in a | |
| 1279 // manner that resists the length of the compressed data from compromising | |
| 1280 // cookie data. | |
| 1281 void SpdyFramer::WriteHeaderBlockToZ(const SpdyHeaderBlock* headers, | |
| 1282 z_stream* z) const { | |
| 1283 unsigned length_length = 4; | |
| 1284 if (protocol_version() < 3) | |
| 1285 length_length = 2; | |
| 1286 | |
| 1287 WriteLengthZ(headers->size(), length_length, kZStandardData, z); | |
| 1288 | |
| 1289 std::map<std::string, std::string>::const_iterator it; | |
| 1290 for (it = headers->begin(); it != headers->end(); ++it) { | |
| 1291 WriteLengthZ(it->first.size(), length_length, kZStandardData, z); | |
| 1292 WriteZ(it->first, kZStandardData, z); | |
| 1293 | |
| 1294 if (it->first == "cookie") { | |
| 1295 // We require the cookie values (save for the last) to end with a | |
| 1296 // semicolon and (save for the first) to start with a space. This is | |
| 1297 // typically the format that we are given them in but we reserialize them | |
| 1298 // to be sure. | |
| 1299 | |
| 1300 std::vector<base::StringPiece> cookie_values; | |
| 1301 size_t cookie_length = 0; | |
| 1302 base::StringPiece cookie_data(it->second); | |
| 1303 | |
| 1304 for (;;) { | |
| 1305 while (!cookie_data.empty() && | |
| 1306 (cookie_data[0] == ' ' || cookie_data[0] == '\t')) { | |
| 1307 cookie_data.remove_prefix(1); | |
| 1308 } | |
| 1309 if (cookie_data.empty()) | |
| 1310 break; | |
| 1311 | |
| 1312 size_t i; | |
| 1313 for (i = 0; i < cookie_data.size(); i++) { | |
| 1314 if (cookie_data[i] == ';') | |
| 1315 break; | |
| 1316 } | |
| 1317 if (i < cookie_data.size()) { | |
| 1318 if (!IsCookieEmpty(cookie_data.substr(0, i))) { | |
| 1319 cookie_values.push_back(cookie_data.substr(0, i)); | |
| 1320 cookie_length += i + 2 /* semicolon and space */; | |
| 1321 } | |
| 1322 cookie_data.remove_prefix(i + 1); | |
| 1323 } else { | |
| 1324 if (!IsCookieEmpty(cookie_data)) { | |
| 1325 cookie_values.push_back(cookie_data); | |
| 1326 cookie_length += cookie_data.size(); | |
| 1327 } else if (cookie_length > 2) { | |
| 1328 cookie_length -= 2 /* compensate for previously added length */; | |
| 1329 } | |
| 1330 cookie_data.remove_prefix(i); | |
| 1331 } | |
| 1332 } | |
| 1333 | |
| 1334 WriteLengthZ(cookie_length, length_length, kZStandardData, z); | |
| 1335 for (size_t i = 0; i < cookie_values.size(); i++) { | |
| 1336 std::string cookie; | |
| 1337 // Since zlib will only back-reference complete cookies, a cookie that | |
| 1338 // is currently last (and so doesn't have a trailing semicolon) won't | |
| 1339 // match if it's later in a non-final position. The same is true of | |
| 1340 // the first cookie. | |
| 1341 if (i == 0 && cookie_values.size() == 1) { | |
| 1342 cookie = cookie_values[i].as_string(); | |
| 1343 } else if (i == 0) { | |
| 1344 cookie = cookie_values[i].as_string() + ";"; | |
| 1345 } else if (i < cookie_values.size() - 1) { | |
| 1346 cookie = " " + cookie_values[i].as_string() + ";"; | |
| 1347 } else { | |
| 1348 cookie = " " + cookie_values[i].as_string(); | |
| 1349 } | |
| 1350 WriteZ(cookie, kZCookieData, z); | |
| 1351 } | |
| 1352 } else if (it->first == "accept" || | |
| 1353 it->first == "accept-charset" || | |
| 1354 it->first == "accept-encoding" || | |
| 1355 it->first == "accept-language" || | |
| 1356 it->first == "host" || | |
| 1357 it->first == "version" || | |
| 1358 it->first == "method" || | |
| 1359 it->first == "scheme" || | |
| 1360 it->first == ":host" || | |
| 1361 it->first == ":version" || | |
| 1362 it->first == ":method" || | |
| 1363 it->first == ":scheme" || | |
| 1364 it->first == "user-agent") { | |
| 1365 WriteLengthZ(it->second.size(), length_length, kZStandardData, z); | |
| 1366 WriteZ(it->second, kZStandardData, z); | |
| 1367 } else { | |
| 1368 // Non-whitelisted headers are Huffman compressed in their own block, but | |
| 1369 // don't match against the window. | |
| 1370 WriteLengthZ(it->second.size(), length_length, kZStandardData, z); | |
| 1371 WriteZ(it->second, kZHuffmanOnlyData, z); | |
| 1372 } | |
| 1373 } | |
| 1374 | |
| 1375 z->avail_in = 0; | |
| 1376 int rv = deflate(z, Z_SYNC_FLUSH); | |
| 1377 DCHECK_EQ(Z_OK, rv); | |
| 1378 z->clas = kZStandardData; | |
| 1379 } | |
| 1380 | |
| 1381 #endif // !defined(USE_SYSTEM_ZLIB) | |
| 1382 | |
| 1383 size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data, | |
| 1384 size_t len) { | |
| 1385 DCHECK_EQ(SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK, state_); | |
| 1386 const size_t original_len = len; | |
| 1387 | |
| 1388 if (remaining_control_header_ > 0) { | |
| 1389 size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len, | |
| 1390 remaining_control_header_); | |
| 1391 remaining_control_header_ -= bytes_read; | |
| 1392 remaining_data_length_ -= bytes_read; | |
| 1393 } | |
| 1394 | |
| 1395 if (remaining_control_header_ == 0) { | |
| 1396 SpdyFrameReader reader(current_frame_buffer_.get(), | |
| 1397 current_frame_buffer_length_); | |
| 1398 reader.Seek(GetControlFrameHeaderSize()); // Seek past frame header. | |
| 1399 | |
| 1400 switch (current_frame_type_) { | |
| 1401 case SYN_STREAM: | |
| 1402 { | |
| 1403 DCHECK_GE(SPDY3, protocol_version()); | |
| 1404 bool successful_read = true; | |
| 1405 successful_read = reader.ReadUInt31(¤t_frame_stream_id_); | |
| 1406 DCHECK(successful_read); | |
| 1407 if (current_frame_stream_id_ == 0) { | |
| 1408 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 1409 break; | |
| 1410 } | |
| 1411 | |
| 1412 SpdyStreamId associated_to_stream_id = kInvalidStream; | |
| 1413 successful_read = reader.ReadUInt31(&associated_to_stream_id); | |
| 1414 DCHECK(successful_read); | |
| 1415 | |
| 1416 SpdyPriority priority = 0; | |
| 1417 successful_read = reader.ReadUInt8(&priority); | |
| 1418 DCHECK(successful_read); | |
| 1419 if (protocol_version() <= SPDY2) { | |
| 1420 priority = priority >> 6; | |
| 1421 } else { | |
| 1422 priority = priority >> 5; | |
| 1423 } | |
| 1424 | |
| 1425 // Seek past unused byte; used to be credential slot in SPDY 3. | |
| 1426 reader.Seek(1); | |
| 1427 | |
| 1428 DCHECK(reader.IsDoneReading()); | |
| 1429 if (debug_visitor_) { | |
| 1430 debug_visitor_->OnReceiveCompressedFrame( | |
| 1431 current_frame_stream_id_, | |
| 1432 current_frame_type_, | |
| 1433 current_frame_length_); | |
| 1434 } | |
| 1435 visitor_->OnSynStream( | |
| 1436 current_frame_stream_id_, | |
| 1437 associated_to_stream_id, | |
| 1438 priority, | |
| 1439 (current_frame_flags_ & CONTROL_FLAG_FIN) != 0, | |
| 1440 (current_frame_flags_ & CONTROL_FLAG_UNIDIRECTIONAL) != 0); | |
| 1441 } | |
| 1442 CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK); | |
| 1443 break; | |
| 1444 case SETTINGS: | |
| 1445 if (protocol_version() > SPDY3 && | |
| 1446 current_frame_flags_ & SETTINGS_FLAG_ACK) { | |
| 1447 visitor_->OnSettingsAck(); | |
| 1448 CHANGE_STATE(SPDY_AUTO_RESET); | |
| 1449 } else { | |
| 1450 visitor_->OnSettings(current_frame_flags_ & | |
| 1451 SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS); | |
| 1452 CHANGE_STATE(SPDY_SETTINGS_FRAME_PAYLOAD); | |
| 1453 } | |
| 1454 break; | |
| 1455 case SYN_REPLY: | |
| 1456 case HEADERS: | |
| 1457 // SYN_REPLY and HEADERS are the same, save for the visitor call. | |
| 1458 { | |
| 1459 if (protocol_version() > SPDY3) { | |
| 1460 DCHECK_EQ(HEADERS, current_frame_type_); | |
| 1461 } | |
| 1462 bool successful_read = true; | |
| 1463 if (protocol_version() <= SPDY3) { | |
| 1464 successful_read = reader.ReadUInt31(¤t_frame_stream_id_); | |
| 1465 DCHECK(successful_read); | |
| 1466 } | |
| 1467 if (current_frame_stream_id_ == 0) { | |
| 1468 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 1469 break; | |
| 1470 } | |
| 1471 if (protocol_version() <= SPDY2) { | |
| 1472 // SPDY 2 had two unused bytes here. Seek past them. | |
| 1473 reader.Seek(2); | |
| 1474 } | |
| 1475 if (protocol_version() > SPDY3 && | |
| 1476 !(current_frame_flags_ & HEADERS_FLAG_END_HEADERS) && | |
| 1477 current_frame_type_ == HEADERS) { | |
| 1478 expect_continuation_ = current_frame_stream_id_; | |
| 1479 end_stream_when_done_ = current_frame_flags_ & CONTROL_FLAG_FIN; | |
| 1480 } | |
| 1481 if (protocol_version() > SPDY3 && | |
| 1482 current_frame_flags_ & HEADERS_FLAG_PADDED) { | |
| 1483 uint8 pad_payload_len = 0; | |
| 1484 DCHECK_EQ(remaining_padding_payload_length_, 0u); | |
| 1485 successful_read = reader.ReadUInt8(&pad_payload_len); | |
| 1486 DCHECK(successful_read); | |
| 1487 remaining_padding_payload_length_ = pad_payload_len; | |
| 1488 } | |
| 1489 const bool has_priority = | |
| 1490 (current_frame_flags_ & HEADERS_FLAG_PRIORITY) != 0; | |
| 1491 SpdyPriority priority = 0; | |
| 1492 if (protocol_version() > SPDY3 && has_priority) { | |
| 1493 // TODO(jgraettinger): Process dependency rather than ignoring it. | |
| 1494 reader.Seek(kPriorityDependencyPayloadSize); | |
| 1495 uint8 weight = 0; | |
| 1496 successful_read = reader.ReadUInt8(&weight); | |
| 1497 if (successful_read) { | |
| 1498 priority = MapWeightToPriority(weight); | |
| 1499 } | |
| 1500 } | |
| 1501 DCHECK(reader.IsDoneReading()); | |
| 1502 if (debug_visitor_) { | |
| 1503 debug_visitor_->OnReceiveCompressedFrame( | |
| 1504 current_frame_stream_id_, | |
| 1505 current_frame_type_, | |
| 1506 current_frame_length_); | |
| 1507 } | |
| 1508 if (current_frame_type_ == SYN_REPLY) { | |
| 1509 visitor_->OnSynReply( | |
| 1510 current_frame_stream_id_, | |
| 1511 (current_frame_flags_ & CONTROL_FLAG_FIN) != 0); | |
| 1512 } else { | |
| 1513 visitor_->OnHeaders( | |
| 1514 current_frame_stream_id_, | |
| 1515 (current_frame_flags_ & HEADERS_FLAG_PRIORITY) != 0, priority, | |
| 1516 (current_frame_flags_ & CONTROL_FLAG_FIN) != 0, | |
| 1517 expect_continuation_ == 0); | |
| 1518 } | |
| 1519 } | |
| 1520 CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK); | |
| 1521 break; | |
| 1522 case PUSH_PROMISE: | |
| 1523 { | |
| 1524 DCHECK_LT(SPDY3, protocol_version()); | |
| 1525 if (current_frame_stream_id_ == 0) { | |
| 1526 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 1527 break; | |
| 1528 } | |
| 1529 bool successful_read = true; | |
| 1530 if (protocol_version() > SPDY3 && | |
| 1531 current_frame_flags_ & PUSH_PROMISE_FLAG_PADDED) { | |
| 1532 DCHECK_EQ(remaining_padding_payload_length_, 0u); | |
| 1533 uint8 pad_payload_len = 0; | |
| 1534 successful_read = reader.ReadUInt8(&pad_payload_len); | |
| 1535 DCHECK(successful_read); | |
| 1536 remaining_padding_payload_length_ = pad_payload_len; | |
| 1537 } | |
| 1538 } | |
| 1539 { | |
| 1540 SpdyStreamId promised_stream_id = kInvalidStream; | |
| 1541 bool successful_read = reader.ReadUInt31(&promised_stream_id); | |
| 1542 DCHECK(successful_read); | |
| 1543 DCHECK(reader.IsDoneReading()); | |
| 1544 if (promised_stream_id == 0) { | |
| 1545 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 1546 break; | |
| 1547 } | |
| 1548 if (!(current_frame_flags_ & PUSH_PROMISE_FLAG_END_PUSH_PROMISE)) { | |
| 1549 expect_continuation_ = current_frame_stream_id_; | |
| 1550 } | |
| 1551 if (debug_visitor_) { | |
| 1552 debug_visitor_->OnReceiveCompressedFrame( | |
| 1553 current_frame_stream_id_, | |
| 1554 current_frame_type_, | |
| 1555 current_frame_length_); | |
| 1556 } | |
| 1557 visitor_->OnPushPromise(current_frame_stream_id_, | |
| 1558 promised_stream_id, | |
| 1559 (current_frame_flags_ & | |
| 1560 PUSH_PROMISE_FLAG_END_PUSH_PROMISE) != 0); | |
| 1561 } | |
| 1562 CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK); | |
| 1563 break; | |
| 1564 case CONTINUATION: | |
| 1565 { | |
| 1566 // Check to make sure the stream id of the current frame is | |
| 1567 // the same as that of the preceding frame. | |
| 1568 // If we're at this point we should already know that | |
| 1569 // expect_continuation_ != 0, so this doubles as a check | |
| 1570 // that current_frame_stream_id != 0. | |
| 1571 if (current_frame_stream_id_ != expect_continuation_) { | |
| 1572 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 1573 break; | |
| 1574 } | |
| 1575 if (current_frame_flags_ & HEADERS_FLAG_END_HEADERS) { | |
| 1576 expect_continuation_ = 0; | |
| 1577 } | |
| 1578 if (debug_visitor_) { | |
| 1579 debug_visitor_->OnReceiveCompressedFrame( | |
| 1580 current_frame_stream_id_, | |
| 1581 current_frame_type_, | |
| 1582 current_frame_length_); | |
| 1583 } | |
| 1584 visitor_->OnContinuation(current_frame_stream_id_, | |
| 1585 (current_frame_flags_ & | |
| 1586 HEADERS_FLAG_END_HEADERS) != 0); | |
| 1587 } | |
| 1588 CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK); | |
| 1589 break; | |
| 1590 default: | |
| 1591 DCHECK(false); | |
| 1592 } | |
| 1593 } | |
| 1594 return original_len - len; | |
| 1595 } | |
| 1596 | |
| 1597 // Does not buffer the control payload. Instead, either passes directly to the | |
| 1598 // visitor or decompresses and then passes directly to the visitor, via | |
| 1599 // IncrementallyDeliverControlFrameHeaderData() or | |
| 1600 // IncrementallyDecompressControlFrameHeaderData() respectively. | |
| 1601 size_t SpdyFramer::ProcessControlFrameHeaderBlock(const char* data, | |
| 1602 size_t data_len, | |
| 1603 bool is_hpack_header_block) { | |
| 1604 DCHECK_EQ(SPDY_CONTROL_FRAME_HEADER_BLOCK, state_); | |
| 1605 | |
| 1606 bool processed_successfully = true; | |
| 1607 if (current_frame_type_ != SYN_STREAM && | |
| 1608 current_frame_type_ != SYN_REPLY && | |
| 1609 current_frame_type_ != HEADERS && | |
| 1610 current_frame_type_ != PUSH_PROMISE && | |
| 1611 current_frame_type_ != CONTINUATION) { | |
| 1612 LOG(DFATAL) << "Unhandled frame type in ProcessControlFrameHeaderBlock."; | |
| 1613 } | |
| 1614 size_t process_bytes = std::min( | |
| 1615 data_len, remaining_data_length_ - remaining_padding_payload_length_); | |
| 1616 if (is_hpack_header_block) { | |
| 1617 if (!GetHpackDecoder()->HandleControlFrameHeadersData( | |
| 1618 current_frame_stream_id_, data, process_bytes)) { | |
| 1619 // TODO(jgraettinger): Finer-grained HPACK error codes. | |
| 1620 set_error(SPDY_DECOMPRESS_FAILURE); | |
| 1621 processed_successfully = false; | |
| 1622 } | |
| 1623 } else if (process_bytes > 0) { | |
| 1624 if (enable_compression_ && protocol_version() <= SPDY3) { | |
| 1625 processed_successfully = IncrementallyDecompressControlFrameHeaderData( | |
| 1626 current_frame_stream_id_, data, process_bytes); | |
| 1627 } else { | |
| 1628 processed_successfully = IncrementallyDeliverControlFrameHeaderData( | |
| 1629 current_frame_stream_id_, data, process_bytes); | |
| 1630 } | |
| 1631 } | |
| 1632 remaining_data_length_ -= process_bytes; | |
| 1633 | |
| 1634 // Handle the case that there is no futher data in this frame. | |
| 1635 if (remaining_data_length_ == remaining_padding_payload_length_ && | |
| 1636 processed_successfully) { | |
| 1637 if (expect_continuation_ == 0) { | |
| 1638 if (is_hpack_header_block) { | |
| 1639 if (!GetHpackDecoder()->HandleControlFrameHeadersComplete( | |
| 1640 current_frame_stream_id_)) { | |
| 1641 set_error(SPDY_DECOMPRESS_FAILURE); | |
| 1642 processed_successfully = false; | |
| 1643 } else { | |
| 1644 // TODO(jgraettinger): To be removed with migration to | |
| 1645 // SpdyHeadersHandlerInterface. Serializes the HPACK block as a SPDY3 | |
| 1646 // block, delivered via reentrant call to | |
| 1647 // ProcessControlFrameHeaderBlock(). | |
| 1648 DeliverHpackBlockAsSpdy3Block(); | |
| 1649 return process_bytes; | |
| 1650 } | |
| 1651 } else { | |
| 1652 // The complete header block has been delivered. We send a zero-length | |
| 1653 // OnControlFrameHeaderData() to indicate this. | |
| 1654 visitor_->OnControlFrameHeaderData(current_frame_stream_id_, NULL, 0); | |
| 1655 } | |
| 1656 } | |
| 1657 if (processed_successfully) { | |
| 1658 CHANGE_STATE(SPDY_CONSUME_PADDING); | |
| 1659 } | |
| 1660 } | |
| 1661 | |
| 1662 // Handle error. | |
| 1663 if (!processed_successfully) { | |
| 1664 return data_len; | |
| 1665 } | |
| 1666 | |
| 1667 // Return amount processed. | |
| 1668 return process_bytes; | |
| 1669 } | |
| 1670 | |
| 1671 size_t SpdyFramer::ProcessSettingsFramePayload(const char* data, | |
| 1672 size_t data_len) { | |
| 1673 DCHECK_EQ(SPDY_SETTINGS_FRAME_PAYLOAD, state_); | |
| 1674 DCHECK_EQ(SETTINGS, current_frame_type_); | |
| 1675 size_t unprocessed_bytes = std::min(data_len, remaining_data_length_); | |
| 1676 size_t processed_bytes = 0; | |
| 1677 | |
| 1678 size_t setting_size = SpdyConstants::GetSettingSize(protocol_version()); | |
| 1679 | |
| 1680 // Loop over our incoming data. | |
| 1681 while (unprocessed_bytes > 0) { | |
| 1682 // Process up to one setting at a time. | |
| 1683 size_t processing = std::min( | |
| 1684 unprocessed_bytes, | |
| 1685 static_cast<size_t>(setting_size - settings_scratch_.setting_buf_len)); | |
| 1686 | |
| 1687 // Check if we have a complete setting in our input. | |
| 1688 if (processing == setting_size) { | |
| 1689 // Parse the setting directly out of the input without buffering. | |
| 1690 if (!ProcessSetting(data + processed_bytes)) { | |
| 1691 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 1692 return processed_bytes; | |
| 1693 } | |
| 1694 } else { | |
| 1695 // Continue updating settings_scratch_.setting_buf. | |
| 1696 memcpy(settings_scratch_.setting_buf + settings_scratch_.setting_buf_len, | |
| 1697 data + processed_bytes, | |
| 1698 processing); | |
| 1699 settings_scratch_.setting_buf_len += processing; | |
| 1700 | |
| 1701 // Check if we have a complete setting buffered. | |
| 1702 if (settings_scratch_.setting_buf_len == setting_size) { | |
| 1703 if (!ProcessSetting(settings_scratch_.setting_buf)) { | |
| 1704 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 1705 return processed_bytes; | |
| 1706 } | |
| 1707 // Reset settings_scratch_.setting_buf for our next setting. | |
| 1708 settings_scratch_.setting_buf_len = 0; | |
| 1709 } | |
| 1710 } | |
| 1711 | |
| 1712 // Iterate. | |
| 1713 unprocessed_bytes -= processing; | |
| 1714 processed_bytes += processing; | |
| 1715 } | |
| 1716 | |
| 1717 // Check if we're done handling this SETTINGS frame. | |
| 1718 remaining_data_length_ -= processed_bytes; | |
| 1719 if (remaining_data_length_ == 0) { | |
| 1720 visitor_->OnSettingsEnd(); | |
| 1721 CHANGE_STATE(SPDY_AUTO_RESET); | |
| 1722 } | |
| 1723 | |
| 1724 return processed_bytes; | |
| 1725 } | |
| 1726 | |
| 1727 void SpdyFramer::DeliverHpackBlockAsSpdy3Block() { | |
| 1728 DCHECK_LT(SPDY3, protocol_version()); | |
| 1729 DCHECK_EQ(remaining_padding_payload_length_, remaining_data_length_); | |
| 1730 | |
| 1731 const SpdyNameValueBlock& block = GetHpackDecoder()->decoded_block(); | |
| 1732 if (block.empty()) { | |
| 1733 // Special-case this to make tests happy. | |
| 1734 ProcessControlFrameHeaderBlock(NULL, 0, false); | |
| 1735 return; | |
| 1736 } | |
| 1737 SpdyFrameBuilder builder( | |
| 1738 GetSerializedLength(protocol_version(), &block), | |
| 1739 SPDY3); | |
| 1740 | |
| 1741 SerializeNameValueBlockWithoutCompression(&builder, block); | |
| 1742 scoped_ptr<SpdyFrame> frame(builder.take()); | |
| 1743 | |
| 1744 // Preserve padding length, and reset it after the re-entrant call. | |
| 1745 size_t remaining_padding = remaining_padding_payload_length_; | |
| 1746 | |
| 1747 remaining_padding_payload_length_ = 0; | |
| 1748 remaining_data_length_ = frame->size(); | |
| 1749 | |
| 1750 ProcessControlFrameHeaderBlock(frame->data(), frame->size(), false); | |
| 1751 | |
| 1752 remaining_padding_payload_length_ = remaining_padding; | |
| 1753 remaining_data_length_ = remaining_padding; | |
| 1754 } | |
| 1755 | |
| 1756 bool SpdyFramer::ProcessSetting(const char* data) { | |
| 1757 int id_field; | |
| 1758 SpdySettingsIds id; | |
| 1759 uint8 flags = 0; | |
| 1760 uint32 value; | |
| 1761 | |
| 1762 // Extract fields. | |
| 1763 // Maintain behavior of old SPDY 2 bug with byte ordering of flags/id. | |
| 1764 if (protocol_version() <= SPDY3) { | |
| 1765 const uint32 id_and_flags_wire = *(reinterpret_cast<const uint32*>(data)); | |
| 1766 SettingsFlagsAndId id_and_flags = | |
| 1767 SettingsFlagsAndId::FromWireFormat(protocol_version(), id_and_flags_wire); | |
| 1768 id_field = id_and_flags.id(); | |
| 1769 flags = id_and_flags.flags(); | |
| 1770 value = ntohl(*(reinterpret_cast<const uint32*>(data + 4))); | |
| 1771 } else { | |
| 1772 id_field = ntohs(*(reinterpret_cast<const uint16*>(data))); | |
| 1773 value = ntohl(*(reinterpret_cast<const uint32*>(data + 2))); | |
| 1774 } | |
| 1775 | |
| 1776 // Validate id. | |
| 1777 if (!SpdyConstants::IsValidSettingId(protocol_version(), id_field)) { | |
| 1778 DLOG(WARNING) << "Unknown SETTINGS ID: " << id_field; | |
| 1779 if (protocol_version() <= SPDY3) { | |
| 1780 return false; | |
| 1781 } else { | |
| 1782 // In HTTP2 we ignore unknown settings for extensibility. | |
| 1783 return true; | |
| 1784 } | |
| 1785 } | |
| 1786 id = SpdyConstants::ParseSettingId(protocol_version(), id_field); | |
| 1787 | |
| 1788 if (protocol_version() <= SPDY3) { | |
| 1789 // Detect duplicates. | |
| 1790 if (id <= settings_scratch_.last_setting_id) { | |
| 1791 DLOG(WARNING) << "Duplicate entry or invalid ordering for id " << id | |
| 1792 << " in " << display_protocol_ << " SETTINGS frame " | |
| 1793 << "(last setting id was " | |
| 1794 << settings_scratch_.last_setting_id << ")."; | |
| 1795 return false; | |
| 1796 } | |
| 1797 settings_scratch_.last_setting_id = id; | |
| 1798 | |
| 1799 // Validate flags. | |
| 1800 uint8 kFlagsMask = SETTINGS_FLAG_PLEASE_PERSIST | SETTINGS_FLAG_PERSISTED; | |
| 1801 if ((flags & ~(kFlagsMask)) != 0) { | |
| 1802 DLOG(WARNING) << "Unknown SETTINGS flags provided for id " << id << ": " | |
| 1803 << flags; | |
| 1804 return false; | |
| 1805 } | |
| 1806 } | |
| 1807 | |
| 1808 // Validation succeeded. Pass on to visitor. | |
| 1809 visitor_->OnSetting(id, flags, value); | |
| 1810 return true; | |
| 1811 } | |
| 1812 | |
| 1813 size_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) { | |
| 1814 size_t original_len = len; | |
| 1815 size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len, | |
| 1816 remaining_data_length_); | |
| 1817 remaining_data_length_ -= bytes_read; | |
| 1818 if (remaining_data_length_ == 0) { | |
| 1819 SpdyFrameReader reader(current_frame_buffer_.get(), | |
| 1820 current_frame_buffer_length_); | |
| 1821 reader.Seek(GetControlFrameHeaderSize()); // Skip frame header. | |
| 1822 | |
| 1823 // Use frame-specific handlers. | |
| 1824 switch (current_frame_type_) { | |
| 1825 case PING: { | |
| 1826 SpdyPingId id = 0; | |
| 1827 bool is_ack = protocol_version() > SPDY3 && | |
| 1828 (current_frame_flags_ & PING_FLAG_ACK); | |
| 1829 bool successful_read = true; | |
| 1830 if (protocol_version() <= SPDY3) { | |
| 1831 uint32 id32 = 0; | |
| 1832 successful_read = reader.ReadUInt32(&id32); | |
| 1833 id = id32; | |
| 1834 } else { | |
| 1835 successful_read = reader.ReadUInt64(&id); | |
| 1836 } | |
| 1837 DCHECK(successful_read); | |
| 1838 DCHECK(reader.IsDoneReading()); | |
| 1839 visitor_->OnPing(id, is_ack); | |
| 1840 } | |
| 1841 break; | |
| 1842 case WINDOW_UPDATE: { | |
| 1843 uint32 delta_window_size = 0; | |
| 1844 bool successful_read = true; | |
| 1845 if (protocol_version() <= SPDY3) { | |
| 1846 successful_read = reader.ReadUInt31(¤t_frame_stream_id_); | |
| 1847 DCHECK(successful_read); | |
| 1848 } | |
| 1849 successful_read = reader.ReadUInt32(&delta_window_size); | |
| 1850 DCHECK(successful_read); | |
| 1851 DCHECK(reader.IsDoneReading()); | |
| 1852 visitor_->OnWindowUpdate(current_frame_stream_id_, | |
| 1853 delta_window_size); | |
| 1854 } | |
| 1855 break; | |
| 1856 case BLOCKED: { | |
| 1857 DCHECK_LT(SPDY3, protocol_version()); | |
| 1858 DCHECK(reader.IsDoneReading()); | |
| 1859 visitor_->OnBlocked(current_frame_stream_id_); | |
| 1860 } | |
| 1861 break; | |
| 1862 case PRIORITY: { | |
| 1863 DCHECK_LT(SPDY3, protocol_version()); | |
| 1864 uint32 parent_stream_id; | |
| 1865 uint8 weight; | |
| 1866 bool exclusive; | |
| 1867 bool successful_read = true; | |
| 1868 successful_read = reader.ReadUInt32(&parent_stream_id); | |
| 1869 DCHECK(successful_read); | |
| 1870 // Exclusivity is indicated by a single bit flag. | |
| 1871 exclusive = (parent_stream_id >> 31) != 0; | |
| 1872 // Zero out the highest-order bit to get the parent stream id. | |
| 1873 parent_stream_id &= 0x7fffffff; | |
| 1874 successful_read = reader.ReadUInt8(&weight); | |
| 1875 DCHECK(successful_read); | |
| 1876 DCHECK(reader.IsDoneReading()); | |
| 1877 visitor_->OnPriority( | |
| 1878 current_frame_stream_id_, parent_stream_id, weight, exclusive); | |
| 1879 } | |
| 1880 break; | |
| 1881 default: | |
| 1882 // Unreachable. | |
| 1883 LOG(FATAL) << "Unhandled control frame " << current_frame_type_; | |
| 1884 } | |
| 1885 | |
| 1886 CHANGE_STATE(SPDY_IGNORE_REMAINING_PAYLOAD); | |
| 1887 } | |
| 1888 return original_len - len; | |
| 1889 } | |
| 1890 | |
| 1891 size_t SpdyFramer::ProcessGoAwayFramePayload(const char* data, size_t len) { | |
| 1892 if (len == 0) { | |
| 1893 return 0; | |
| 1894 } | |
| 1895 // Clamp to the actual remaining payload. | |
| 1896 if (len > remaining_data_length_) { | |
| 1897 len = remaining_data_length_; | |
| 1898 } | |
| 1899 size_t original_len = len; | |
| 1900 | |
| 1901 // Check if we had already read enough bytes to parse the GOAWAY header. | |
| 1902 const size_t header_size = GetGoAwayMinimumSize(); | |
| 1903 size_t unread_header_bytes = header_size - current_frame_buffer_length_; | |
| 1904 bool already_parsed_header = (unread_header_bytes == 0); | |
| 1905 if (!already_parsed_header) { | |
| 1906 // Buffer the new GOAWAY header bytes we got. | |
| 1907 UpdateCurrentFrameBuffer(&data, &len, unread_header_bytes); | |
| 1908 | |
| 1909 // Do we have enough to parse the constant size GOAWAY header? | |
| 1910 if (current_frame_buffer_length_ == header_size) { | |
| 1911 // Parse out the last good stream id. | |
| 1912 SpdyFrameReader reader(current_frame_buffer_.get(), | |
| 1913 current_frame_buffer_length_); | |
| 1914 reader.Seek(GetControlFrameHeaderSize()); // Seek past frame header. | |
| 1915 bool successful_read = reader.ReadUInt31(¤t_frame_stream_id_); | |
| 1916 DCHECK(successful_read); | |
| 1917 | |
| 1918 // In SPDYv3 and up, frames also specify a status code - parse it out. | |
| 1919 SpdyGoAwayStatus status = GOAWAY_OK; | |
| 1920 if (protocol_version() >= SPDY3) { | |
| 1921 uint32 status_raw = GOAWAY_OK; | |
| 1922 successful_read = reader.ReadUInt32(&status_raw); | |
| 1923 DCHECK(successful_read); | |
| 1924 if (SpdyConstants::IsValidGoAwayStatus(protocol_version(), | |
| 1925 status_raw)) { | |
| 1926 status = SpdyConstants::ParseGoAwayStatus(protocol_version(), | |
| 1927 status_raw); | |
| 1928 } else { | |
| 1929 if (protocol_version() > SPDY3) { | |
| 1930 // Treat unrecognized status codes as INTERNAL_ERROR as | |
| 1931 // recommended by the HTTP/2 spec. | |
| 1932 status = GOAWAY_INTERNAL_ERROR; | |
| 1933 } | |
| 1934 } | |
| 1935 } | |
| 1936 // Finished parsing the GOAWAY header, call frame handler. | |
| 1937 visitor_->OnGoAway(current_frame_stream_id_, status); | |
| 1938 } | |
| 1939 } | |
| 1940 | |
| 1941 // Handle remaining data as opaque. | |
| 1942 bool processed_successfully = true; | |
| 1943 if (len > 0) { | |
| 1944 processed_successfully = visitor_->OnGoAwayFrameData(data, len); | |
| 1945 } | |
| 1946 remaining_data_length_ -= original_len; | |
| 1947 if (!processed_successfully) { | |
| 1948 set_error(SPDY_GOAWAY_FRAME_CORRUPT); | |
| 1949 } else if (remaining_data_length_ == 0) { | |
| 1950 // Signal that there is not more opaque data. | |
| 1951 visitor_->OnGoAwayFrameData(NULL, 0); | |
| 1952 CHANGE_STATE(SPDY_AUTO_RESET); | |
| 1953 } | |
| 1954 return original_len; | |
| 1955 } | |
| 1956 | |
| 1957 size_t SpdyFramer::ProcessRstStreamFramePayload(const char* data, size_t len) { | |
| 1958 if (len == 0) { | |
| 1959 return 0; | |
| 1960 } | |
| 1961 // Clamp to the actual remaining payload. | |
| 1962 if (len > remaining_data_length_) { | |
| 1963 len = remaining_data_length_; | |
| 1964 } | |
| 1965 size_t original_len = len; | |
| 1966 | |
| 1967 // Check if we had already read enough bytes to parse the fixed-length portion | |
| 1968 // of the RST_STREAM frame. | |
| 1969 const size_t header_size = GetRstStreamMinimumSize(); | |
| 1970 size_t unread_header_bytes = header_size - current_frame_buffer_length_; | |
| 1971 bool already_parsed_header = (unread_header_bytes == 0); | |
| 1972 if (!already_parsed_header) { | |
| 1973 // Buffer the new RST_STREAM header bytes we got. | |
| 1974 UpdateCurrentFrameBuffer(&data, &len, unread_header_bytes); | |
| 1975 | |
| 1976 // Do we have enough to parse the constant size RST_STREAM header? | |
| 1977 if (current_frame_buffer_length_ == header_size) { | |
| 1978 // Parse out the last good stream id. | |
| 1979 SpdyFrameReader reader(current_frame_buffer_.get(), | |
| 1980 current_frame_buffer_length_); | |
| 1981 reader.Seek(GetControlFrameHeaderSize()); // Seek past frame header. | |
| 1982 if (protocol_version() <= SPDY3) { | |
| 1983 bool successful_read = reader.ReadUInt31(¤t_frame_stream_id_); | |
| 1984 DCHECK(successful_read); | |
| 1985 } | |
| 1986 | |
| 1987 SpdyRstStreamStatus status = RST_STREAM_INVALID; | |
| 1988 uint32 status_raw = status; | |
| 1989 bool successful_read = reader.ReadUInt32(&status_raw); | |
| 1990 DCHECK(successful_read); | |
| 1991 if (SpdyConstants::IsValidRstStreamStatus(protocol_version(), | |
| 1992 status_raw)) { | |
| 1993 status = | |
| 1994 SpdyConstants::ParseRstStreamStatus(protocol_version(), status_raw); | |
| 1995 } else { | |
| 1996 if (protocol_version() > SPDY3) { | |
| 1997 // Treat unrecognized status codes as INTERNAL_ERROR as | |
| 1998 // recommended by the HTTP/2 spec. | |
| 1999 status = RST_STREAM_INTERNAL_ERROR; | |
| 2000 } | |
| 2001 } | |
| 2002 // Finished parsing the RST_STREAM header, call frame handler. | |
| 2003 visitor_->OnRstStream(current_frame_stream_id_, status); | |
| 2004 } | |
| 2005 } | |
| 2006 | |
| 2007 // Handle remaining data as opaque. | |
| 2008 bool processed_successfully = true; | |
| 2009 if (len > 0) { | |
| 2010 processed_successfully = visitor_->OnRstStreamFrameData(data, len); | |
| 2011 } | |
| 2012 remaining_data_length_ -= original_len; | |
| 2013 if (!processed_successfully) { | |
| 2014 set_error(SPDY_RST_STREAM_FRAME_CORRUPT); | |
| 2015 } else if (remaining_data_length_ == 0) { | |
| 2016 // Signal that there is not more opaque data. | |
| 2017 visitor_->OnRstStreamFrameData(NULL, 0); | |
| 2018 CHANGE_STATE(SPDY_AUTO_RESET); | |
| 2019 } | |
| 2020 return original_len; | |
| 2021 } | |
| 2022 | |
| 2023 size_t SpdyFramer::ProcessAltSvcFramePayload(const char* data, size_t len) { | |
| 2024 if (len == 0) { | |
| 2025 return 0; | |
| 2026 } | |
| 2027 | |
| 2028 // Clamp to the actual remaining payload. | |
| 2029 len = std::min(len, remaining_data_length_); | |
| 2030 | |
| 2031 size_t processed_bytes = 0; | |
| 2032 size_t processing = 0; | |
| 2033 size_t bytes_remaining; | |
| 2034 char* buffer; | |
| 2035 size_t* buffer_len; | |
| 2036 | |
| 2037 while (len > 0) { | |
| 2038 if (altsvc_scratch_.pid_len == 0) { | |
| 2039 // The size of the frame up to the PID_LEN field. | |
| 2040 size_t fixed_len_portion = GetAltSvcMinimumSize() - 1; | |
| 2041 bytes_remaining = fixed_len_portion - current_frame_buffer_length_; | |
| 2042 processing = std::min(len, bytes_remaining); | |
| 2043 // Buffer the new ALTSVC bytes we got. | |
| 2044 UpdateCurrentFrameBuffer(&data, &len, processing); | |
| 2045 | |
| 2046 // Do we have enough to parse the length of the protocol id? | |
| 2047 if (current_frame_buffer_length_ == fixed_len_portion) { | |
| 2048 // Parse out the max age, port, and pid_len. | |
| 2049 SpdyFrameReader reader(current_frame_buffer_.get(), | |
| 2050 current_frame_buffer_length_); | |
| 2051 reader.Seek(GetControlFrameHeaderSize()); // Seek past frame header. | |
| 2052 bool successful_read = reader.ReadUInt32(&altsvc_scratch_.max_age); | |
| 2053 reader.ReadUInt16(&altsvc_scratch_.port); | |
| 2054 reader.Seek(1); // Reserved byte. | |
| 2055 successful_read = successful_read && | |
| 2056 reader.ReadUInt8(&altsvc_scratch_.pid_len); | |
| 2057 DCHECK(successful_read); | |
| 2058 // Sanity check length value. | |
| 2059 if (GetAltSvcMinimumSize() + altsvc_scratch_.pid_len >= | |
| 2060 current_frame_length_) { | |
| 2061 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 2062 return 0; | |
| 2063 } | |
| 2064 altsvc_scratch_.protocol_id.reset( | |
| 2065 new char[size_t(altsvc_scratch_.pid_len)]); | |
| 2066 } | |
| 2067 processed_bytes += processing; | |
| 2068 continue; | |
| 2069 } else if (altsvc_scratch_.pid_buf_len < altsvc_scratch_.pid_len) { | |
| 2070 // Buffer protocol id field as in comes in. | |
| 2071 buffer = altsvc_scratch_.protocol_id.get(); | |
| 2072 buffer_len = &altsvc_scratch_.pid_buf_len; | |
| 2073 bytes_remaining = altsvc_scratch_.pid_len - altsvc_scratch_.pid_buf_len; | |
| 2074 } else if (altsvc_scratch_.host_len == 0) { | |
| 2075 // Parse out the host length. | |
| 2076 processing = 1; | |
| 2077 altsvc_scratch_.host_len = *reinterpret_cast<const uint8*>(data); | |
| 2078 // Sanity check length value. | |
| 2079 if (GetAltSvcMinimumSize() + altsvc_scratch_.pid_len + | |
| 2080 altsvc_scratch_.host_len > current_frame_length_) { | |
| 2081 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 2082 return 0; | |
| 2083 } | |
| 2084 altsvc_scratch_.host.reset(new char[altsvc_scratch_.host_len]); | |
| 2085 // Once we have host length, we can also determine the origin length | |
| 2086 // by process of elimination. | |
| 2087 altsvc_scratch_.origin_len = current_frame_length_ - | |
| 2088 GetAltSvcMinimumSize() - | |
| 2089 altsvc_scratch_.pid_len - | |
| 2090 altsvc_scratch_.host_len; | |
| 2091 if (altsvc_scratch_.origin_len > 0) { | |
| 2092 altsvc_scratch_.origin.reset(new char[altsvc_scratch_.origin_len]); | |
| 2093 } | |
| 2094 data += processing; | |
| 2095 processed_bytes += processing; | |
| 2096 len -= processing; | |
| 2097 continue; | |
| 2098 } else if (altsvc_scratch_.host_buf_len < altsvc_scratch_.host_len) { | |
| 2099 // Buffer host field as it comes in. | |
| 2100 // TODO(mlavan): check formatting for host and origin | |
| 2101 buffer = altsvc_scratch_.host.get(); | |
| 2102 buffer_len = &altsvc_scratch_.host_buf_len; | |
| 2103 bytes_remaining = altsvc_scratch_.host_len - altsvc_scratch_.host_buf_len; | |
| 2104 } else { | |
| 2105 // Buffer (optional) origin field as it comes in. | |
| 2106 if (altsvc_scratch_.origin_len <= 0) { | |
| 2107 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 2108 return 0; | |
| 2109 } | |
| 2110 buffer = altsvc_scratch_.origin.get(); | |
| 2111 buffer_len = &altsvc_scratch_.origin_buf_len; | |
| 2112 bytes_remaining = remaining_data_length_ - | |
| 2113 processed_bytes - | |
| 2114 altsvc_scratch_.origin_buf_len; | |
| 2115 if (len > bytes_remaining) { | |
| 2116 // This is our last field; there shouldn't be any more bytes. | |
| 2117 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 2118 return 0; | |
| 2119 } | |
| 2120 } | |
| 2121 | |
| 2122 // Copy data bytes into the appropriate field. | |
| 2123 processing = std::min(len, bytes_remaining); | |
| 2124 memcpy(buffer + *buffer_len, | |
| 2125 data, | |
| 2126 processing); | |
| 2127 *buffer_len += processing; | |
| 2128 data += processing; | |
| 2129 processed_bytes += processing; | |
| 2130 len -= processing; | |
| 2131 } | |
| 2132 | |
| 2133 remaining_data_length_ -= processed_bytes; | |
| 2134 if (remaining_data_length_ == 0) { | |
| 2135 visitor_->OnAltSvc(current_frame_stream_id_, | |
| 2136 altsvc_scratch_.max_age, | |
| 2137 altsvc_scratch_.port, | |
| 2138 StringPiece(altsvc_scratch_.protocol_id.get(), | |
| 2139 altsvc_scratch_.pid_len), | |
| 2140 StringPiece(altsvc_scratch_.host.get(), | |
| 2141 altsvc_scratch_.host_len), | |
| 2142 StringPiece(altsvc_scratch_.origin.get(), | |
| 2143 altsvc_scratch_.origin_len)); | |
| 2144 CHANGE_STATE(SPDY_AUTO_RESET); | |
| 2145 } | |
| 2146 | |
| 2147 return processed_bytes; | |
| 2148 } | |
| 2149 | |
| 2150 size_t SpdyFramer::ProcessDataFramePaddingLength(const char* data, size_t len) { | |
| 2151 DCHECK_EQ(SPDY_READ_DATA_FRAME_PADDING_LENGTH, state_); | |
| 2152 DCHECK_EQ(0u, remaining_padding_payload_length_); | |
| 2153 DCHECK_EQ(DATA, current_frame_type_); | |
| 2154 | |
| 2155 size_t original_len = len; | |
| 2156 if (current_frame_flags_ & DATA_FLAG_PADDED) { | |
| 2157 if (len != 0) { | |
| 2158 if (remaining_data_length_ < kPadLengthFieldSize) { | |
| 2159 set_error(SPDY_INVALID_DATA_FRAME_FLAGS); | |
| 2160 return 0; | |
| 2161 } | |
| 2162 | |
| 2163 remaining_padding_payload_length_ = *reinterpret_cast<const uint8*>(data); | |
| 2164 ++data; | |
| 2165 --len; | |
| 2166 --remaining_data_length_; | |
| 2167 } else { | |
| 2168 // We don't have the data available for parsing the pad length field. Keep | |
| 2169 // waiting. | |
| 2170 return 0; | |
| 2171 } | |
| 2172 } | |
| 2173 | |
| 2174 if (remaining_padding_payload_length_ > remaining_data_length_) { | |
| 2175 set_error(SPDY_INVALID_DATA_FRAME_FLAGS); | |
| 2176 return 0; | |
| 2177 } | |
| 2178 CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME); | |
| 2179 return original_len - len; | |
| 2180 } | |
| 2181 | |
| 2182 size_t SpdyFramer::ProcessFramePadding(const char* data, size_t len) { | |
| 2183 DCHECK_EQ(SPDY_CONSUME_PADDING, state_); | |
| 2184 | |
| 2185 size_t original_len = len; | |
| 2186 if (remaining_padding_payload_length_ > 0) { | |
| 2187 DCHECK_EQ(remaining_padding_payload_length_, remaining_data_length_); | |
| 2188 size_t amount_to_discard = std::min(remaining_padding_payload_length_, len); | |
| 2189 if (current_frame_type_ == DATA && amount_to_discard > 0) { | |
| 2190 // The visitor needs to know about padding so it can send window updates. | |
| 2191 // Communicate the padding to the visitor through a NULL data pointer, | |
| 2192 // with a nonzero size. | |
| 2193 visitor_->OnStreamFrameData( | |
| 2194 current_frame_stream_id_, NULL, amount_to_discard, false); | |
| 2195 } | |
| 2196 data += amount_to_discard; | |
| 2197 len -= amount_to_discard; | |
| 2198 remaining_padding_payload_length_ -= amount_to_discard; | |
| 2199 remaining_data_length_ -= amount_to_discard; | |
| 2200 } | |
| 2201 | |
| 2202 if (remaining_data_length_ == 0) { | |
| 2203 // If the FIN flag is set, or this ends a header block which set FIN, | |
| 2204 // inform the visitor of EOF via a 0-length data frame. | |
| 2205 if (expect_continuation_ == 0 && | |
| 2206 ((current_frame_flags_ & CONTROL_FLAG_FIN) != 0 || | |
| 2207 end_stream_when_done_)) { | |
| 2208 end_stream_when_done_ = false; | |
| 2209 visitor_->OnStreamFrameData(current_frame_stream_id_, NULL, 0, true); | |
| 2210 } | |
| 2211 CHANGE_STATE(SPDY_AUTO_RESET); | |
| 2212 } | |
| 2213 return original_len - len; | |
| 2214 } | |
| 2215 | |
| 2216 size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) { | |
| 2217 size_t original_len = len; | |
| 2218 if (remaining_data_length_ - remaining_padding_payload_length_ > 0) { | |
| 2219 size_t amount_to_forward = std::min( | |
| 2220 remaining_data_length_ - remaining_padding_payload_length_, len); | |
| 2221 if (amount_to_forward && state_ != SPDY_IGNORE_REMAINING_PAYLOAD) { | |
| 2222 // Only inform the visitor if there is data. | |
| 2223 if (amount_to_forward) { | |
| 2224 visitor_->OnStreamFrameData( | |
| 2225 current_frame_stream_id_, data, amount_to_forward, false); | |
| 2226 } | |
| 2227 } | |
| 2228 data += amount_to_forward; | |
| 2229 len -= amount_to_forward; | |
| 2230 remaining_data_length_ -= amount_to_forward; | |
| 2231 } | |
| 2232 | |
| 2233 if (remaining_data_length_ == remaining_padding_payload_length_) { | |
| 2234 CHANGE_STATE(SPDY_CONSUME_PADDING); | |
| 2235 } | |
| 2236 return original_len - len; | |
| 2237 } | |
| 2238 | |
| 2239 size_t SpdyFramer::ProcessIgnoredControlFramePayload(/*const char* data,*/ | |
| 2240 size_t len) { | |
| 2241 size_t original_len = len; | |
| 2242 if (remaining_data_length_ > 0) { | |
| 2243 size_t amount_to_ignore = std::min(remaining_data_length_, len); | |
| 2244 len -= amount_to_ignore; | |
| 2245 remaining_data_length_ -= amount_to_ignore; | |
| 2246 } | |
| 2247 | |
| 2248 if (remaining_data_length_ == 0) { | |
| 2249 CHANGE_STATE(SPDY_AUTO_RESET); | |
| 2250 } | |
| 2251 return original_len - len; | |
| 2252 } | |
| 2253 | |
| 2254 size_t SpdyFramer::ParseHeaderBlockInBuffer(const char* header_data, | |
| 2255 size_t header_length, | |
| 2256 SpdyHeaderBlock* block) const { | |
| 2257 SpdyFrameReader reader(header_data, header_length); | |
| 2258 | |
| 2259 // Read number of headers. | |
| 2260 uint32 num_headers; | |
| 2261 if (protocol_version() <= SPDY2) { | |
| 2262 uint16 temp; | |
| 2263 if (!reader.ReadUInt16(&temp)) { | |
| 2264 DVLOG(1) << "Unable to read number of headers."; | |
| 2265 return 0; | |
| 2266 } | |
| 2267 num_headers = temp; | |
| 2268 } else { | |
| 2269 if (!reader.ReadUInt32(&num_headers)) { | |
| 2270 DVLOG(1) << "Unable to read number of headers."; | |
| 2271 return 0; | |
| 2272 } | |
| 2273 } | |
| 2274 | |
| 2275 // Read each header. | |
| 2276 for (uint32 index = 0; index < num_headers; ++index) { | |
| 2277 base::StringPiece temp; | |
| 2278 | |
| 2279 // Read header name. | |
| 2280 if ((protocol_version() <= SPDY2) ? !reader.ReadStringPiece16(&temp) | |
| 2281 : !reader.ReadStringPiece32(&temp)) { | |
| 2282 DVLOG(1) << "Unable to read header name (" << index + 1 << " of " | |
| 2283 << num_headers << ")."; | |
| 2284 return 0; | |
| 2285 } | |
| 2286 std::string name = temp.as_string(); | |
| 2287 | |
| 2288 // Read header value. | |
| 2289 if ((protocol_version() <= SPDY2) ? !reader.ReadStringPiece16(&temp) | |
| 2290 : !reader.ReadStringPiece32(&temp)) { | |
| 2291 DVLOG(1) << "Unable to read header value (" << index + 1 << " of " | |
| 2292 << num_headers << ")."; | |
| 2293 return 0; | |
| 2294 } | |
| 2295 std::string value = temp.as_string(); | |
| 2296 | |
| 2297 // Ensure no duplicates. | |
| 2298 if (block->find(name) != block->end()) { | |
| 2299 DVLOG(1) << "Duplicate header '" << name << "' (" << index + 1 << " of " | |
| 2300 << num_headers << ")."; | |
| 2301 return 0; | |
| 2302 } | |
| 2303 | |
| 2304 // Store header. | |
| 2305 (*block)[name] = value; | |
| 2306 } | |
| 2307 return reader.GetBytesConsumed(); | |
| 2308 } | |
| 2309 | |
| 2310 SpdySerializedFrame* SpdyFramer::SerializeData( | |
| 2311 const SpdyDataIR& data_ir) const { | |
| 2312 uint8 flags = DATA_FLAG_NONE; | |
| 2313 if (data_ir.fin()) { | |
| 2314 flags = DATA_FLAG_FIN; | |
| 2315 } | |
| 2316 | |
| 2317 if (protocol_version() > SPDY3) { | |
| 2318 int num_padding_fields = 0; | |
| 2319 if (data_ir.padded()) { | |
| 2320 flags |= DATA_FLAG_PADDED; | |
| 2321 ++num_padding_fields; | |
| 2322 } | |
| 2323 | |
| 2324 const size_t size_with_padding = num_padding_fields + | |
| 2325 data_ir.data().length() + data_ir.padding_payload_len() + | |
| 2326 GetDataFrameMinimumSize(); | |
| 2327 SpdyFrameBuilder builder(size_with_padding, protocol_version()); | |
| 2328 builder.WriteDataFrameHeader(*this, data_ir.stream_id(), flags); | |
| 2329 if (data_ir.padded()) { | |
| 2330 builder.WriteUInt8(data_ir.padding_payload_len() & 0xff); | |
| 2331 } | |
| 2332 builder.WriteBytes(data_ir.data().data(), data_ir.data().length()); | |
| 2333 if (data_ir.padding_payload_len() > 0) { | |
| 2334 string padding(data_ir.padding_payload_len(), 0); | |
| 2335 builder.WriteBytes(padding.data(), padding.length()); | |
| 2336 } | |
| 2337 DCHECK_EQ(size_with_padding, builder.length()); | |
| 2338 return builder.take(); | |
| 2339 } else { | |
| 2340 const size_t size = GetDataFrameMinimumSize() + data_ir.data().length(); | |
| 2341 SpdyFrameBuilder builder(size, protocol_version()); | |
| 2342 builder.WriteDataFrameHeader(*this, data_ir.stream_id(), flags); | |
| 2343 builder.WriteBytes(data_ir.data().data(), data_ir.data().length()); | |
| 2344 DCHECK_EQ(size, builder.length()); | |
| 2345 return builder.take(); | |
| 2346 } | |
| 2347 } | |
| 2348 | |
| 2349 SpdySerializedFrame* SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthField( | |
| 2350 const SpdyDataIR& data_ir) const { | |
| 2351 uint8 flags = DATA_FLAG_NONE; | |
| 2352 if (data_ir.fin()) { | |
| 2353 flags = DATA_FLAG_FIN; | |
| 2354 } | |
| 2355 | |
| 2356 size_t frame_size = GetDataFrameMinimumSize(); | |
| 2357 size_t num_padding_fields = 0; | |
| 2358 if (protocol_version() > SPDY3) { | |
| 2359 if (data_ir.padded()) { | |
| 2360 flags |= DATA_FLAG_PADDED; | |
| 2361 ++num_padding_fields; | |
| 2362 } | |
| 2363 frame_size += num_padding_fields; | |
| 2364 } | |
| 2365 | |
| 2366 SpdyFrameBuilder builder(frame_size, protocol_version()); | |
| 2367 builder.WriteDataFrameHeader(*this, data_ir.stream_id(), flags); | |
| 2368 if (protocol_version() > SPDY3) { | |
| 2369 if (data_ir.padded()) { | |
| 2370 builder.WriteUInt8(data_ir.padding_payload_len() & 0xff); | |
| 2371 } | |
| 2372 builder.OverwriteLength(*this, num_padding_fields + | |
| 2373 data_ir.data().length() + data_ir.padding_payload_len()); | |
| 2374 } else { | |
| 2375 builder.OverwriteLength(*this, data_ir.data().length()); | |
| 2376 } | |
| 2377 DCHECK_EQ(frame_size, builder.length()); | |
| 2378 return builder.take(); | |
| 2379 } | |
| 2380 | |
| 2381 SpdySerializedFrame* SpdyFramer::SerializeSynStream( | |
| 2382 const SpdySynStreamIR& syn_stream) { | |
| 2383 DCHECK_GE(SPDY3, protocol_version()); | |
| 2384 uint8 flags = 0; | |
| 2385 if (syn_stream.fin()) { | |
| 2386 flags |= CONTROL_FLAG_FIN; | |
| 2387 } | |
| 2388 if (syn_stream.unidirectional()) { | |
| 2389 // TODO(hkhalil): invalid for HTTP2. | |
| 2390 flags |= CONTROL_FLAG_UNIDIRECTIONAL; | |
| 2391 } | |
| 2392 | |
| 2393 // Sanitize priority. | |
| 2394 uint8 priority = syn_stream.priority(); | |
| 2395 if (priority > GetLowestPriority()) { | |
| 2396 DLOG(DFATAL) << "Priority out-of-bounds."; | |
| 2397 priority = GetLowestPriority(); | |
| 2398 } | |
| 2399 | |
| 2400 // The size of this frame, including variable-length name-value block. | |
| 2401 size_t size = GetSynStreamMinimumSize() + | |
| 2402 GetSerializedLength(syn_stream.name_value_block()); | |
| 2403 | |
| 2404 SpdyFrameBuilder builder(size, protocol_version()); | |
| 2405 builder.WriteControlFrameHeader(*this, SYN_STREAM, flags); | |
| 2406 builder.WriteUInt32(syn_stream.stream_id()); | |
| 2407 builder.WriteUInt32(syn_stream.associated_to_stream_id()); | |
| 2408 builder.WriteUInt8(priority << ((protocol_version() <= SPDY2) ? 6 : 5)); | |
| 2409 builder.WriteUInt8(0); // Unused byte where credential slot used to be. | |
| 2410 DCHECK_EQ(GetSynStreamMinimumSize(), builder.length()); | |
| 2411 SerializeNameValueBlock(&builder, syn_stream); | |
| 2412 | |
| 2413 if (debug_visitor_) { | |
| 2414 const size_t payload_len = | |
| 2415 GetSerializedLength(protocol_version(), | |
| 2416 &(syn_stream.name_value_block())); | |
| 2417 debug_visitor_->OnSendCompressedFrame(syn_stream.stream_id(), | |
| 2418 SYN_STREAM, | |
| 2419 payload_len, | |
| 2420 builder.length()); | |
| 2421 } | |
| 2422 | |
| 2423 return builder.take(); | |
| 2424 } | |
| 2425 | |
| 2426 SpdySerializedFrame* SpdyFramer::SerializeSynReply( | |
| 2427 const SpdySynReplyIR& syn_reply) { | |
| 2428 DCHECK_GE(SPDY3, protocol_version()); | |
| 2429 uint8 flags = 0; | |
| 2430 if (syn_reply.fin()) { | |
| 2431 flags |= CONTROL_FLAG_FIN; | |
| 2432 } | |
| 2433 | |
| 2434 // The size of this frame, including variable-length name-value block. | |
| 2435 const size_t size = GetSynReplyMinimumSize() + | |
| 2436 GetSerializedLength(syn_reply.name_value_block()); | |
| 2437 | |
| 2438 SpdyFrameBuilder builder(size, protocol_version()); | |
| 2439 if (protocol_version() <= SPDY3) { | |
| 2440 builder.WriteControlFrameHeader(*this, SYN_REPLY, flags); | |
| 2441 builder.WriteUInt32(syn_reply.stream_id()); | |
| 2442 } else { | |
| 2443 builder.BeginNewFrame(*this, | |
| 2444 HEADERS, | |
| 2445 flags, | |
| 2446 syn_reply.stream_id()); | |
| 2447 } | |
| 2448 if (protocol_version() < SPDY3) { | |
| 2449 builder.WriteUInt16(0); // Unused. | |
| 2450 } | |
| 2451 DCHECK_EQ(GetSynReplyMinimumSize(), builder.length()); | |
| 2452 SerializeNameValueBlock(&builder, syn_reply); | |
| 2453 | |
| 2454 if (debug_visitor_) { | |
| 2455 const size_t payload_len = GetSerializedLength( | |
| 2456 protocol_version(), &(syn_reply.name_value_block())); | |
| 2457 debug_visitor_->OnSendCompressedFrame(syn_reply.stream_id(), | |
| 2458 SYN_REPLY, | |
| 2459 payload_len, | |
| 2460 builder.length()); | |
| 2461 } | |
| 2462 | |
| 2463 return builder.take(); | |
| 2464 } | |
| 2465 | |
| 2466 SpdySerializedFrame* SpdyFramer::SerializeRstStream( | |
| 2467 const SpdyRstStreamIR& rst_stream) const { | |
| 2468 // TODO(jgraettinger): For now, Chromium will support parsing RST_STREAM | |
| 2469 // payloads, but will not emit them. SPDY4 is used for draft HTTP/2, | |
| 2470 // which doesn't currently include RST_STREAM payloads. GFE flags have been | |
| 2471 // commented but left in place to simplify future patching. | |
| 2472 // Compute the output buffer size, taking opaque data into account. | |
| 2473 size_t expected_length = GetRstStreamMinimumSize(); | |
| 2474 if (protocol_version() > SPDY3) { | |
| 2475 expected_length += rst_stream.description().size(); | |
| 2476 } | |
| 2477 SpdyFrameBuilder builder(expected_length, protocol_version()); | |
| 2478 | |
| 2479 // Serialize the RST_STREAM frame. | |
| 2480 if (protocol_version() <= SPDY3) { | |
| 2481 builder.WriteControlFrameHeader(*this, RST_STREAM, 0); | |
| 2482 builder.WriteUInt32(rst_stream.stream_id()); | |
| 2483 } else { | |
| 2484 builder.BeginNewFrame(*this, RST_STREAM, 0, rst_stream.stream_id()); | |
| 2485 } | |
| 2486 | |
| 2487 builder.WriteUInt32(SpdyConstants::SerializeRstStreamStatus( | |
| 2488 protocol_version(), rst_stream.status())); | |
| 2489 | |
| 2490 // In SPDY4 and up, RST_STREAM frames may also specify opaque data. | |
| 2491 if (protocol_version() > SPDY3 && rst_stream.description().size() > 0) { | |
| 2492 builder.WriteBytes(rst_stream.description().data(), | |
| 2493 rst_stream.description().size()); | |
| 2494 } | |
| 2495 | |
| 2496 DCHECK_EQ(expected_length, builder.length()); | |
| 2497 return builder.take(); | |
| 2498 } | |
| 2499 | |
| 2500 SpdySerializedFrame* SpdyFramer::SerializeSettings( | |
| 2501 const SpdySettingsIR& settings) const { | |
| 2502 uint8 flags = 0; | |
| 2503 | |
| 2504 if (protocol_version() <= SPDY3) { | |
| 2505 if (settings.clear_settings()) { | |
| 2506 flags |= SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS; | |
| 2507 } | |
| 2508 } else { | |
| 2509 if (settings.is_ack()) { | |
| 2510 flags |= SETTINGS_FLAG_ACK; | |
| 2511 } | |
| 2512 } | |
| 2513 const SpdySettingsIR::ValueMap* values = &(settings.values()); | |
| 2514 | |
| 2515 size_t setting_size = SpdyConstants::GetSettingSize(protocol_version()); | |
| 2516 // Size, in bytes, of this SETTINGS frame. | |
| 2517 const size_t size = GetSettingsMinimumSize() + | |
| 2518 (values->size() * setting_size); | |
| 2519 SpdyFrameBuilder builder(size, protocol_version()); | |
| 2520 if (protocol_version() <= SPDY3) { | |
| 2521 builder.WriteControlFrameHeader(*this, SETTINGS, flags); | |
| 2522 } else { | |
| 2523 builder.BeginNewFrame(*this, SETTINGS, flags, 0); | |
| 2524 } | |
| 2525 | |
| 2526 // If this is an ACK, payload should be empty. | |
| 2527 if (protocol_version() > SPDY3 && settings.is_ack()) { | |
| 2528 return builder.take(); | |
| 2529 } | |
| 2530 | |
| 2531 if (protocol_version() <= SPDY3) { | |
| 2532 builder.WriteUInt32(values->size()); | |
| 2533 } | |
| 2534 DCHECK_EQ(GetSettingsMinimumSize(), builder.length()); | |
| 2535 for (SpdySettingsIR::ValueMap::const_iterator it = values->begin(); | |
| 2536 it != values->end(); | |
| 2537 ++it) { | |
| 2538 int setting_id = | |
| 2539 SpdyConstants::SerializeSettingId(protocol_version(), it->first); | |
| 2540 DCHECK_GE(setting_id, 0); | |
| 2541 if (protocol_version() <= SPDY3) { | |
| 2542 uint8 setting_flags = 0; | |
| 2543 if (it->second.persist_value) { | |
| 2544 setting_flags |= SETTINGS_FLAG_PLEASE_PERSIST; | |
| 2545 } | |
| 2546 if (it->second.persisted) { | |
| 2547 setting_flags |= SETTINGS_FLAG_PERSISTED; | |
| 2548 } | |
| 2549 SettingsFlagsAndId flags_and_id(setting_flags, setting_id); | |
| 2550 uint32 id_and_flags_wire = flags_and_id.GetWireFormat(protocol_version()); | |
| 2551 builder.WriteBytes(&id_and_flags_wire, 4); | |
| 2552 } else { | |
| 2553 builder.WriteUInt16(static_cast<uint16>(setting_id)); | |
| 2554 } | |
| 2555 builder.WriteUInt32(it->second.value); | |
| 2556 } | |
| 2557 DCHECK_EQ(size, builder.length()); | |
| 2558 return builder.take(); | |
| 2559 } | |
| 2560 | |
| 2561 SpdySerializedFrame* SpdyFramer::SerializePing(const SpdyPingIR& ping) const { | |
| 2562 SpdyFrameBuilder builder(GetPingSize(), protocol_version()); | |
| 2563 if (protocol_version() <= SPDY3) { | |
| 2564 builder.WriteControlFrameHeader(*this, PING, kNoFlags); | |
| 2565 builder.WriteUInt32(static_cast<uint32>(ping.id())); | |
| 2566 } else { | |
| 2567 uint8 flags = 0; | |
| 2568 if (ping.is_ack()) { | |
| 2569 flags |= PING_FLAG_ACK; | |
| 2570 } | |
| 2571 builder.BeginNewFrame(*this, PING, flags, 0); | |
| 2572 builder.WriteUInt64(ping.id()); | |
| 2573 } | |
| 2574 DCHECK_EQ(GetPingSize(), builder.length()); | |
| 2575 return builder.take(); | |
| 2576 } | |
| 2577 | |
| 2578 SpdySerializedFrame* SpdyFramer::SerializeGoAway( | |
| 2579 const SpdyGoAwayIR& goaway) const { | |
| 2580 | |
| 2581 // Compute the output buffer size, take opaque data into account. | |
| 2582 size_t expected_length = GetGoAwayMinimumSize(); | |
| 2583 if (protocol_version() > SPDY3) { | |
| 2584 expected_length += goaway.description().size(); | |
| 2585 } | |
| 2586 SpdyFrameBuilder builder(expected_length, protocol_version()); | |
| 2587 | |
| 2588 // Serialize the GOAWAY frame. | |
| 2589 if (protocol_version() <= SPDY3) { | |
| 2590 builder.WriteControlFrameHeader(*this, GOAWAY, kNoFlags); | |
| 2591 } else { | |
| 2592 builder.BeginNewFrame(*this, GOAWAY, 0, 0); | |
| 2593 } | |
| 2594 | |
| 2595 // GOAWAY frames specify the last good stream id for all SPDY versions. | |
| 2596 builder.WriteUInt32(goaway.last_good_stream_id()); | |
| 2597 | |
| 2598 // In SPDY3 and up, GOAWAY frames also specify the error status code. | |
| 2599 if (protocol_version() >= SPDY3) { | |
| 2600 // TODO(jgraettinger): Merge back to server-side. | |
| 2601 builder.WriteUInt32(SpdyConstants::SerializeGoAwayStatus(protocol_version(), | |
| 2602 goaway.status())); | |
| 2603 } | |
| 2604 | |
| 2605 // In SPDY4 and up, GOAWAY frames may also specify opaque data. | |
| 2606 if ((protocol_version() > SPDY3) && (goaway.description().size() > 0)) { | |
| 2607 builder.WriteBytes(goaway.description().data(), | |
| 2608 goaway.description().size()); | |
| 2609 } | |
| 2610 | |
| 2611 DCHECK_EQ(expected_length, builder.length()); | |
| 2612 return builder.take(); | |
| 2613 } | |
| 2614 | |
| 2615 SpdySerializedFrame* SpdyFramer::SerializeHeaders( | |
| 2616 const SpdyHeadersIR& headers) { | |
| 2617 uint8 flags = 0; | |
| 2618 if (headers.fin()) { | |
| 2619 flags |= CONTROL_FLAG_FIN; | |
| 2620 } | |
| 2621 if (protocol_version() > SPDY3) { | |
| 2622 // This will get overwritten if we overflow into a CONTINUATION frame. | |
| 2623 flags |= HEADERS_FLAG_END_HEADERS; | |
| 2624 if (headers.has_priority()) { | |
| 2625 flags |= HEADERS_FLAG_PRIORITY; | |
| 2626 } | |
| 2627 if (headers.padded()) { | |
| 2628 flags |= HEADERS_FLAG_PADDED; | |
| 2629 } | |
| 2630 } | |
| 2631 | |
| 2632 // The size of this frame, including padding (if there is any) | |
| 2633 // and variable-length name-value block. | |
| 2634 size_t size = GetHeadersMinimumSize(); | |
| 2635 | |
| 2636 if (protocol_version() > SPDY3 && headers.padded()) { | |
| 2637 size += kPadLengthFieldSize; | |
| 2638 size += headers.padding_payload_len(); | |
| 2639 } | |
| 2640 | |
| 2641 SpdyPriority priority = static_cast<SpdyPriority>(headers.priority()); | |
| 2642 if (headers.has_priority()) { | |
| 2643 if (headers.priority() > GetLowestPriority()) { | |
| 2644 DLOG(DFATAL) << "Priority out-of-bounds."; | |
| 2645 priority = GetLowestPriority(); | |
| 2646 } | |
| 2647 size += 5; | |
| 2648 } | |
| 2649 | |
| 2650 string hpack_encoding; | |
| 2651 if (protocol_version() > SPDY3) { | |
| 2652 if (enable_compression_) { | |
| 2653 GetHpackEncoder()->EncodeHeaderSet( | |
| 2654 headers.name_value_block(), &hpack_encoding); | |
| 2655 } else { | |
| 2656 GetHpackEncoder()->EncodeHeaderSetWithoutCompression( | |
| 2657 headers.name_value_block(), &hpack_encoding); | |
| 2658 } | |
| 2659 size += hpack_encoding.size(); | |
| 2660 if (size > kMaxControlFrameSize) { | |
| 2661 size += GetNumberRequiredContinuationFrames(size) * | |
| 2662 GetContinuationMinimumSize(); | |
| 2663 flags &= ~HEADERS_FLAG_END_HEADERS; | |
| 2664 } | |
| 2665 } else { | |
| 2666 size += GetSerializedLength(headers.name_value_block()); | |
| 2667 } | |
| 2668 | |
| 2669 SpdyFrameBuilder builder(size, protocol_version()); | |
| 2670 if (protocol_version() <= SPDY3) { | |
| 2671 builder.WriteControlFrameHeader(*this, HEADERS, flags); | |
| 2672 builder.WriteUInt32(headers.stream_id()); | |
| 2673 } else { | |
| 2674 builder.BeginNewFrame(*this, | |
| 2675 HEADERS, | |
| 2676 flags, | |
| 2677 headers.stream_id()); | |
| 2678 } | |
| 2679 if (protocol_version() <= SPDY2) { | |
| 2680 builder.WriteUInt16(0); // Unused. | |
| 2681 } | |
| 2682 DCHECK_EQ(GetHeadersMinimumSize(), builder.length()); | |
| 2683 | |
| 2684 if (protocol_version() > SPDY3) { | |
| 2685 int padding_payload_len = 0; | |
| 2686 if (headers.padded()) { | |
| 2687 builder.WriteUInt8(headers.padding_payload_len()); | |
| 2688 padding_payload_len = headers.padding_payload_len(); | |
| 2689 } | |
| 2690 if (headers.has_priority()) { | |
| 2691 // TODO(jgraettinger): Plumb priorities and stream dependencies. | |
| 2692 builder.WriteUInt32(0); // Non-exclusive bit and root stream ID. | |
| 2693 builder.WriteUInt8(MapPriorityToWeight(priority)); | |
| 2694 } | |
| 2695 WritePayloadWithContinuation(&builder, | |
| 2696 hpack_encoding, | |
| 2697 headers.stream_id(), | |
| 2698 HEADERS, | |
| 2699 padding_payload_len); | |
| 2700 } else { | |
| 2701 SerializeNameValueBlock(&builder, headers); | |
| 2702 } | |
| 2703 | |
| 2704 if (debug_visitor_) { | |
| 2705 // SPDY4 uses HPACK for header compression. However, continue to | |
| 2706 // use GetSerializedLength() for an apples-to-apples comparision of | |
| 2707 // compression performance between HPACK and SPDY w/ deflate. | |
| 2708 const size_t payload_len = | |
| 2709 GetSerializedLength(protocol_version(), | |
| 2710 &(headers.name_value_block())); | |
| 2711 debug_visitor_->OnSendCompressedFrame(headers.stream_id(), | |
| 2712 HEADERS, | |
| 2713 payload_len, | |
| 2714 builder.length()); | |
| 2715 } | |
| 2716 | |
| 2717 return builder.take(); | |
| 2718 } | |
| 2719 | |
| 2720 SpdySerializedFrame* SpdyFramer::SerializeWindowUpdate( | |
| 2721 const SpdyWindowUpdateIR& window_update) const { | |
| 2722 SpdyFrameBuilder builder(GetWindowUpdateSize(), protocol_version()); | |
| 2723 if (protocol_version() <= SPDY3) { | |
| 2724 builder.WriteControlFrameHeader(*this, WINDOW_UPDATE, kNoFlags); | |
| 2725 builder.WriteUInt32(window_update.stream_id()); | |
| 2726 } else { | |
| 2727 builder.BeginNewFrame(*this, | |
| 2728 WINDOW_UPDATE, | |
| 2729 kNoFlags, | |
| 2730 window_update.stream_id()); | |
| 2731 } | |
| 2732 builder.WriteUInt32(window_update.delta()); | |
| 2733 DCHECK_EQ(GetWindowUpdateSize(), builder.length()); | |
| 2734 return builder.take(); | |
| 2735 } | |
| 2736 | |
| 2737 SpdyFrame* SpdyFramer::SerializeBlocked(const SpdyBlockedIR& blocked) const { | |
| 2738 DCHECK_LT(SPDY3, protocol_version()); | |
| 2739 SpdyFrameBuilder builder(GetBlockedSize(), protocol_version()); | |
| 2740 builder.BeginNewFrame(*this, BLOCKED, kNoFlags, blocked.stream_id()); | |
| 2741 return builder.take(); | |
| 2742 } | |
| 2743 | |
| 2744 SpdyFrame* SpdyFramer::SerializePushPromise( | |
| 2745 const SpdyPushPromiseIR& push_promise) { | |
| 2746 DCHECK_LT(SPDY3, protocol_version()); | |
| 2747 uint8 flags = 0; | |
| 2748 // This will get overwritten if we overflow into a CONTINUATION frame. | |
| 2749 flags |= PUSH_PROMISE_FLAG_END_PUSH_PROMISE; | |
| 2750 // The size of this frame, including variable-length name-value block. | |
| 2751 size_t size = GetPushPromiseMinimumSize(); | |
| 2752 | |
| 2753 if (push_promise.padded()) { | |
| 2754 flags |= PUSH_PROMISE_FLAG_PADDED; | |
| 2755 size += kPadLengthFieldSize; | |
| 2756 size += push_promise.padding_payload_len(); | |
| 2757 } | |
| 2758 | |
| 2759 string hpack_encoding; | |
| 2760 if (enable_compression_) { | |
| 2761 GetHpackEncoder()->EncodeHeaderSet( | |
| 2762 push_promise.name_value_block(), &hpack_encoding); | |
| 2763 } else { | |
| 2764 GetHpackEncoder()->EncodeHeaderSetWithoutCompression( | |
| 2765 push_promise.name_value_block(), &hpack_encoding); | |
| 2766 } | |
| 2767 size += hpack_encoding.size(); | |
| 2768 if (size > kMaxControlFrameSize) { | |
| 2769 size += GetNumberRequiredContinuationFrames(size) * | |
| 2770 GetContinuationMinimumSize(); | |
| 2771 flags &= ~PUSH_PROMISE_FLAG_END_PUSH_PROMISE; | |
| 2772 } | |
| 2773 | |
| 2774 SpdyFrameBuilder builder(size, protocol_version()); | |
| 2775 builder.BeginNewFrame(*this, | |
| 2776 PUSH_PROMISE, | |
| 2777 flags, | |
| 2778 push_promise.stream_id()); | |
| 2779 int padding_payload_len = 0; | |
| 2780 if (push_promise.padded()) { | |
| 2781 builder.WriteUInt8(push_promise.padding_payload_len()); | |
| 2782 builder.WriteUInt32(push_promise.promised_stream_id()); | |
| 2783 DCHECK_EQ(GetPushPromiseMinimumSize() + kPadLengthFieldSize, | |
| 2784 builder.length()); | |
| 2785 | |
| 2786 padding_payload_len = push_promise.padding_payload_len(); | |
| 2787 } else { | |
| 2788 builder.WriteUInt32(push_promise.promised_stream_id()); | |
| 2789 DCHECK_EQ(GetPushPromiseMinimumSize(), builder.length()); | |
| 2790 } | |
| 2791 | |
| 2792 WritePayloadWithContinuation(&builder, | |
| 2793 hpack_encoding, | |
| 2794 push_promise.stream_id(), | |
| 2795 PUSH_PROMISE, | |
| 2796 padding_payload_len); | |
| 2797 | |
| 2798 if (debug_visitor_) { | |
| 2799 // SPDY4 uses HPACK for header compression. However, continue to | |
| 2800 // use GetSerializedLength() for an apples-to-apples comparision of | |
| 2801 // compression performance between HPACK and SPDY w/ deflate. | |
| 2802 const size_t payload_len = | |
| 2803 GetSerializedLength(protocol_version(), | |
| 2804 &(push_promise.name_value_block())); | |
| 2805 debug_visitor_->OnSendCompressedFrame(push_promise.stream_id(), | |
| 2806 PUSH_PROMISE, | |
| 2807 payload_len, | |
| 2808 builder.length()); | |
| 2809 } | |
| 2810 | |
| 2811 return builder.take(); | |
| 2812 } | |
| 2813 | |
| 2814 // TODO(jgraettinger): This implementation is incorrect. The continuation | |
| 2815 // frame continues a previously-begun HPACK encoding; it doesn't begin a | |
| 2816 // new one. Figure out whether it makes sense to keep SerializeContinuation(). | |
| 2817 SpdyFrame* SpdyFramer::SerializeContinuation( | |
| 2818 const SpdyContinuationIR& continuation) { | |
| 2819 CHECK_LT(SPDY3, protocol_version()); | |
| 2820 uint8 flags = 0; | |
| 2821 if (continuation.end_headers()) { | |
| 2822 flags |= HEADERS_FLAG_END_HEADERS; | |
| 2823 } | |
| 2824 | |
| 2825 // The size of this frame, including variable-length name-value block. | |
| 2826 size_t size = GetContinuationMinimumSize(); | |
| 2827 string hpack_encoding; | |
| 2828 if (enable_compression_) { | |
| 2829 GetHpackEncoder()->EncodeHeaderSet( | |
| 2830 continuation.name_value_block(), &hpack_encoding); | |
| 2831 } else { | |
| 2832 GetHpackEncoder()->EncodeHeaderSetWithoutCompression( | |
| 2833 continuation.name_value_block(), &hpack_encoding); | |
| 2834 } | |
| 2835 size += hpack_encoding.size(); | |
| 2836 | |
| 2837 SpdyFrameBuilder builder(size, protocol_version()); | |
| 2838 builder.BeginNewFrame(*this, CONTINUATION, flags, | |
| 2839 continuation.stream_id()); | |
| 2840 DCHECK_EQ(GetContinuationMinimumSize(), builder.length()); | |
| 2841 | |
| 2842 builder.WriteBytes(&hpack_encoding[0], hpack_encoding.size()); | |
| 2843 return builder.take(); | |
| 2844 } | |
| 2845 | |
| 2846 SpdyFrame* SpdyFramer::SerializeAltSvc(const SpdyAltSvcIR& altsvc) { | |
| 2847 DCHECK_LT(SPDY3, protocol_version()); | |
| 2848 size_t size = GetAltSvcMinimumSize(); | |
| 2849 size += altsvc.protocol_id().length(); | |
| 2850 size += altsvc.host().length(); | |
| 2851 size += altsvc.origin().length(); | |
| 2852 | |
| 2853 SpdyFrameBuilder builder(size, protocol_version()); | |
| 2854 builder.BeginNewFrame(*this, ALTSVC, kNoFlags, altsvc.stream_id()); | |
| 2855 | |
| 2856 // TODO(bnc): http://crbug.com/438263 | |
| 2857 // Update the binary format here to the new text-based payload format. | |
| 2858 builder.WriteUInt32(altsvc.max_age()); | |
| 2859 builder.WriteUInt16(altsvc.port()); | |
| 2860 builder.WriteUInt8(0); // Reserved. | |
| 2861 builder.WriteUInt8(static_cast<uint8>(altsvc.protocol_id().length())); | |
| 2862 builder.WriteBytes(altsvc.protocol_id().data(), | |
| 2863 altsvc.protocol_id().length()); | |
| 2864 builder.WriteUInt8(static_cast<uint8>(altsvc.host().length())); | |
| 2865 builder.WriteBytes(altsvc.host().data(), altsvc.host().length()); | |
| 2866 builder.WriteBytes(altsvc.origin().data(), altsvc.origin().length()); | |
| 2867 DCHECK_LT(GetAltSvcMinimumSize(), builder.length()); | |
| 2868 return builder.take(); | |
| 2869 } | |
| 2870 | |
| 2871 SpdyFrame* SpdyFramer::SerializePriority(const SpdyPriorityIR& priority) const { | |
| 2872 DCHECK_LT(SPDY3, protocol_version()); | |
| 2873 size_t size = GetPrioritySize(); | |
| 2874 | |
| 2875 SpdyFrameBuilder builder(size, protocol_version()); | |
| 2876 builder.BeginNewFrame(*this, PRIORITY, kNoFlags, priority.stream_id()); | |
| 2877 | |
| 2878 // Make sure the highest-order bit in the parent stream id is zeroed out. | |
| 2879 uint32 parent_stream_id = priority.parent_stream_id() & 0x7fffffff; | |
| 2880 uint32 exclusive = priority.exclusive() ? 0x80000000 : 0; | |
| 2881 // Set the one-bit exclusivity flag. | |
| 2882 uint32 flag_and_parent_id = parent_stream_id | exclusive; | |
| 2883 builder.WriteUInt32(flag_and_parent_id); | |
| 2884 builder.WriteUInt8(priority.weight()); | |
| 2885 DCHECK_EQ(GetPrioritySize(), builder.length()); | |
| 2886 return builder.take(); | |
| 2887 } | |
| 2888 | |
| 2889 namespace { | |
| 2890 | |
| 2891 class FrameSerializationVisitor : public SpdyFrameVisitor { | |
| 2892 public: | |
| 2893 explicit FrameSerializationVisitor(SpdyFramer* framer) : framer_(framer) {} | |
| 2894 ~FrameSerializationVisitor() override {} | |
| 2895 | |
| 2896 SpdySerializedFrame* ReleaseSerializedFrame() { return frame_.release(); } | |
| 2897 | |
| 2898 void VisitData(const SpdyDataIR& data) override { | |
| 2899 frame_.reset(framer_->SerializeData(data)); | |
| 2900 } | |
| 2901 void VisitSynStream(const SpdySynStreamIR& syn_stream) override { | |
| 2902 frame_.reset(framer_->SerializeSynStream(syn_stream)); | |
| 2903 } | |
| 2904 void VisitSynReply(const SpdySynReplyIR& syn_reply) override { | |
| 2905 frame_.reset(framer_->SerializeSynReply(syn_reply)); | |
| 2906 } | |
| 2907 void VisitRstStream(const SpdyRstStreamIR& rst_stream) override { | |
| 2908 frame_.reset(framer_->SerializeRstStream(rst_stream)); | |
| 2909 } | |
| 2910 void VisitSettings(const SpdySettingsIR& settings) override { | |
| 2911 frame_.reset(framer_->SerializeSettings(settings)); | |
| 2912 } | |
| 2913 void VisitPing(const SpdyPingIR& ping) override { | |
| 2914 frame_.reset(framer_->SerializePing(ping)); | |
| 2915 } | |
| 2916 void VisitGoAway(const SpdyGoAwayIR& goaway) override { | |
| 2917 frame_.reset(framer_->SerializeGoAway(goaway)); | |
| 2918 } | |
| 2919 void VisitHeaders(const SpdyHeadersIR& headers) override { | |
| 2920 frame_.reset(framer_->SerializeHeaders(headers)); | |
| 2921 } | |
| 2922 void VisitWindowUpdate(const SpdyWindowUpdateIR& window_update) override { | |
| 2923 frame_.reset(framer_->SerializeWindowUpdate(window_update)); | |
| 2924 } | |
| 2925 void VisitBlocked(const SpdyBlockedIR& blocked) override { | |
| 2926 frame_.reset(framer_->SerializeBlocked(blocked)); | |
| 2927 } | |
| 2928 void VisitPushPromise(const SpdyPushPromiseIR& push_promise) override { | |
| 2929 frame_.reset(framer_->SerializePushPromise(push_promise)); | |
| 2930 } | |
| 2931 void VisitContinuation(const SpdyContinuationIR& continuation) override { | |
| 2932 frame_.reset(framer_->SerializeContinuation(continuation)); | |
| 2933 } | |
| 2934 void VisitAltSvc(const SpdyAltSvcIR& altsvc) override { | |
| 2935 frame_.reset(framer_->SerializeAltSvc(altsvc)); | |
| 2936 } | |
| 2937 void VisitPriority(const SpdyPriorityIR& priority) override { | |
| 2938 frame_.reset(framer_->SerializePriority(priority)); | |
| 2939 } | |
| 2940 | |
| 2941 private: | |
| 2942 SpdyFramer* framer_; | |
| 2943 scoped_ptr<SpdySerializedFrame> frame_; | |
| 2944 }; | |
| 2945 | |
| 2946 } // namespace | |
| 2947 | |
| 2948 SpdySerializedFrame* SpdyFramer::SerializeFrame(const SpdyFrameIR& frame) { | |
| 2949 FrameSerializationVisitor visitor(this); | |
| 2950 frame.Visit(&visitor); | |
| 2951 return visitor.ReleaseSerializedFrame(); | |
| 2952 } | |
| 2953 | |
| 2954 size_t SpdyFramer::GetSerializedLength(const SpdyHeaderBlock& headers) { | |
| 2955 CHECK_GE(SPDY3, protocol_version()); | |
| 2956 const size_t uncompressed_length = | |
| 2957 GetSerializedLength(protocol_version(), &headers); | |
| 2958 if (!enable_compression_) { | |
| 2959 return uncompressed_length; | |
| 2960 } | |
| 2961 z_stream* compressor = GetHeaderCompressor(); | |
| 2962 // Since we'll be performing lots of flushes when compressing the data, | |
| 2963 // zlib's lower bounds may be insufficient. | |
| 2964 return 2 * deflateBound(compressor, uncompressed_length); | |
| 2965 } | |
| 2966 | |
| 2967 size_t SpdyFramer::GetNumberRequiredContinuationFrames(size_t size) { | |
| 2968 DCHECK_GT(protocol_version(), SPDY3); | |
| 2969 DCHECK_GT(size, kMaxControlFrameSize); | |
| 2970 size_t overflow = size - kMaxControlFrameSize; | |
| 2971 return overflow / (kMaxControlFrameSize - GetContinuationMinimumSize()) + 1; | |
| 2972 } | |
| 2973 | |
| 2974 void SpdyFramer::WritePayloadWithContinuation(SpdyFrameBuilder* builder, | |
| 2975 const string& hpack_encoding, | |
| 2976 SpdyStreamId stream_id, | |
| 2977 SpdyFrameType type, | |
| 2978 int padding_payload_len) { | |
| 2979 uint8 end_flag = 0; | |
| 2980 uint8 flags = 0; | |
| 2981 if (type == HEADERS) { | |
| 2982 end_flag = HEADERS_FLAG_END_HEADERS; | |
| 2983 } else if (type == PUSH_PROMISE) { | |
| 2984 end_flag = PUSH_PROMISE_FLAG_END_PUSH_PROMISE; | |
| 2985 } else { | |
| 2986 DLOG(FATAL) << "CONTINUATION frames cannot be used with frame type " | |
| 2987 << FrameTypeToString(type); | |
| 2988 } | |
| 2989 | |
| 2990 // Write all the padding payload and as much of the data payload as possible | |
| 2991 // into the initial frame. | |
| 2992 size_t bytes_remaining = 0; | |
| 2993 bytes_remaining = | |
| 2994 hpack_encoding.size() - | |
| 2995 std::min(hpack_encoding.size(), | |
| 2996 kMaxControlFrameSize - builder->length() - padding_payload_len); | |
| 2997 builder->WriteBytes(&hpack_encoding[0], | |
| 2998 hpack_encoding.size() - bytes_remaining); | |
| 2999 if (padding_payload_len > 0) { | |
| 3000 string padding = string(padding_payload_len, 0); | |
| 3001 builder->WriteBytes(padding.data(), padding.length()); | |
| 3002 } | |
| 3003 if (bytes_remaining > 0) { | |
| 3004 builder->OverwriteLength( | |
| 3005 *this, kMaxControlFrameSize - GetControlFrameHeaderSize()); | |
| 3006 } | |
| 3007 | |
| 3008 // Tack on CONTINUATION frames for the overflow. | |
| 3009 while (bytes_remaining > 0) { | |
| 3010 size_t bytes_to_write = std::min( | |
| 3011 bytes_remaining, kMaxControlFrameSize - GetContinuationMinimumSize()); | |
| 3012 // Write CONTINUATION frame prefix. | |
| 3013 if (bytes_remaining == bytes_to_write) { | |
| 3014 flags |= end_flag; | |
| 3015 } | |
| 3016 builder->BeginNewFrame(*this, CONTINUATION, flags, stream_id); | |
| 3017 // Write payload fragment. | |
| 3018 builder->WriteBytes( | |
| 3019 &hpack_encoding[hpack_encoding.size() - bytes_remaining], | |
| 3020 bytes_to_write); | |
| 3021 bytes_remaining -= bytes_to_write; | |
| 3022 } | |
| 3023 } | |
| 3024 | |
| 3025 // The following compression setting are based on Brian Olson's analysis. See | |
| 3026 // https://groups.google.com/group/spdy-dev/browse_thread/thread/dfaf498542fac79
2 | |
| 3027 // for more details. | |
| 3028 #if defined(USE_SYSTEM_ZLIB) | |
| 3029 // System zlib is not expected to have workaround for http://crbug.com/139744, | |
| 3030 // so disable compression in that case. | |
| 3031 // TODO(phajdan.jr): Remove the special case when it's no longer necessary. | |
| 3032 static const int kCompressorLevel = 0; | |
| 3033 #else // !defined(USE_SYSTEM_ZLIB) | |
| 3034 static const int kCompressorLevel = 9; | |
| 3035 #endif // !defined(USE_SYSTEM_ZLIB) | |
| 3036 static const int kCompressorWindowSizeInBits = 11; | |
| 3037 static const int kCompressorMemLevel = 1; | |
| 3038 | |
| 3039 z_stream* SpdyFramer::GetHeaderCompressor() { | |
| 3040 if (header_compressor_.get()) | |
| 3041 return header_compressor_.get(); // Already initialized. | |
| 3042 | |
| 3043 header_compressor_.reset(new z_stream); | |
| 3044 memset(header_compressor_.get(), 0, sizeof(z_stream)); | |
| 3045 | |
| 3046 int success = deflateInit2(header_compressor_.get(), | |
| 3047 kCompressorLevel, | |
| 3048 Z_DEFLATED, | |
| 3049 kCompressorWindowSizeInBits, | |
| 3050 kCompressorMemLevel, | |
| 3051 Z_DEFAULT_STRATEGY); | |
| 3052 if (success == Z_OK) { | |
| 3053 const char* dictionary = (protocol_version() <= SPDY2) ? | |
| 3054 kV2Dictionary : kV3Dictionary; | |
| 3055 const int dictionary_size = (protocol_version() <= SPDY2) ? | |
| 3056 kV2DictionarySize : kV3DictionarySize; | |
| 3057 success = deflateSetDictionary(header_compressor_.get(), | |
| 3058 reinterpret_cast<const Bytef*>(dictionary), | |
| 3059 dictionary_size); | |
| 3060 } | |
| 3061 if (success != Z_OK) { | |
| 3062 LOG(WARNING) << "deflateSetDictionary failure: " << success; | |
| 3063 header_compressor_.reset(NULL); | |
| 3064 return NULL; | |
| 3065 } | |
| 3066 return header_compressor_.get(); | |
| 3067 } | |
| 3068 | |
| 3069 z_stream* SpdyFramer::GetHeaderDecompressor() { | |
| 3070 if (header_decompressor_.get()) | |
| 3071 return header_decompressor_.get(); // Already initialized. | |
| 3072 | |
| 3073 header_decompressor_.reset(new z_stream); | |
| 3074 memset(header_decompressor_.get(), 0, sizeof(z_stream)); | |
| 3075 | |
| 3076 int success = inflateInit(header_decompressor_.get()); | |
| 3077 if (success != Z_OK) { | |
| 3078 LOG(WARNING) << "inflateInit failure: " << success; | |
| 3079 header_decompressor_.reset(NULL); | |
| 3080 return NULL; | |
| 3081 } | |
| 3082 return header_decompressor_.get(); | |
| 3083 } | |
| 3084 | |
| 3085 HpackEncoder* SpdyFramer::GetHpackEncoder() { | |
| 3086 DCHECK_LT(SPDY3, protocol_version()); | |
| 3087 if (hpack_encoder_.get() == nullptr) { | |
| 3088 hpack_encoder_.reset(new HpackEncoder(ObtainHpackHuffmanTable())); | |
| 3089 } | |
| 3090 return hpack_encoder_.get(); | |
| 3091 } | |
| 3092 | |
| 3093 HpackDecoder* SpdyFramer::GetHpackDecoder() { | |
| 3094 DCHECK_LT(SPDY3, protocol_version()); | |
| 3095 if (hpack_decoder_.get() == nullptr) { | |
| 3096 hpack_decoder_.reset(new HpackDecoder(ObtainHpackHuffmanTable())); | |
| 3097 } | |
| 3098 return hpack_decoder_.get(); | |
| 3099 } | |
| 3100 | |
| 3101 uint8 SpdyFramer::MapPriorityToWeight(SpdyPriority priority) { | |
| 3102 const float kSteps = 255.9f / 7.f; | |
| 3103 return static_cast<uint8>(kSteps * (7.f - priority)); | |
| 3104 } | |
| 3105 | |
| 3106 SpdyPriority SpdyFramer::MapWeightToPriority(uint8 weight) { | |
| 3107 const float kSteps = 255.9f / 7.f; | |
| 3108 return static_cast<SpdyPriority>(7.f - weight / kSteps); | |
| 3109 } | |
| 3110 | |
| 3111 // Incrementally decompress the control frame's header block, feeding the | |
| 3112 // result to the visitor in chunks. Continue this until the visitor | |
| 3113 // indicates that it cannot process any more data, or (more commonly) we | |
| 3114 // run out of data to deliver. | |
| 3115 bool SpdyFramer::IncrementallyDecompressControlFrameHeaderData( | |
| 3116 SpdyStreamId stream_id, | |
| 3117 const char* data, | |
| 3118 size_t len) { | |
| 3119 // Get a decompressor or set error. | |
| 3120 z_stream* decomp = GetHeaderDecompressor(); | |
| 3121 if (decomp == NULL) { | |
| 3122 LOG(DFATAL) << "Couldn't get decompressor for handling compressed headers."; | |
| 3123 set_error(SPDY_DECOMPRESS_FAILURE); | |
| 3124 return false; | |
| 3125 } | |
| 3126 | |
| 3127 bool processed_successfully = true; | |
| 3128 char buffer[kHeaderDataChunkMaxSize]; | |
| 3129 | |
| 3130 decomp->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data)); | |
| 3131 decomp->avail_in = len; | |
| 3132 // If we get a SYN_STREAM/SYN_REPLY/HEADERS frame with stream ID zero, we | |
| 3133 // signal an error back in ProcessControlFrameBeforeHeaderBlock. So if we've | |
| 3134 // reached this method successfully, stream_id should be nonzero. | |
| 3135 DCHECK_LT(0u, stream_id); | |
| 3136 while (decomp->avail_in > 0 && processed_successfully) { | |
| 3137 decomp->next_out = reinterpret_cast<Bytef*>(buffer); | |
| 3138 decomp->avail_out = arraysize(buffer); | |
| 3139 | |
| 3140 int rv = inflate(decomp, Z_SYNC_FLUSH); | |
| 3141 if (rv == Z_NEED_DICT) { | |
| 3142 const char* dictionary = (protocol_version() <= SPDY2) ? kV2Dictionary | |
| 3143 : kV3Dictionary; | |
| 3144 const int dictionary_size = (protocol_version() <= SPDY2) ? | |
| 3145 kV2DictionarySize : kV3DictionarySize; | |
| 3146 const DictionaryIds& ids = g_dictionary_ids.Get(); | |
| 3147 const uLong dictionary_id = (protocol_version() <= SPDY2) ? | |
| 3148 ids.v2_dictionary_id : ids.v3_dictionary_id; | |
| 3149 // Need to try again with the right dictionary. | |
| 3150 if (decomp->adler == dictionary_id) { | |
| 3151 rv = inflateSetDictionary(decomp, | |
| 3152 reinterpret_cast<const Bytef*>(dictionary), | |
| 3153 dictionary_size); | |
| 3154 if (rv == Z_OK) | |
| 3155 rv = inflate(decomp, Z_SYNC_FLUSH); | |
| 3156 } | |
| 3157 } | |
| 3158 | |
| 3159 // Inflate will generate a Z_BUF_ERROR if it runs out of input | |
| 3160 // without producing any output. The input is consumed and | |
| 3161 // buffered internally by zlib so we can detect this condition by | |
| 3162 // checking if avail_in is 0 after the call to inflate. | |
| 3163 bool input_exhausted = ((rv == Z_BUF_ERROR) && (decomp->avail_in == 0)); | |
| 3164 if ((rv == Z_OK) || input_exhausted) { | |
| 3165 size_t decompressed_len = arraysize(buffer) - decomp->avail_out; | |
| 3166 if (decompressed_len > 0) { | |
| 3167 processed_successfully = visitor_->OnControlFrameHeaderData( | |
| 3168 stream_id, buffer, decompressed_len); | |
| 3169 } | |
| 3170 if (!processed_successfully) { | |
| 3171 // Assume that the problem was the header block was too large for the | |
| 3172 // visitor. | |
| 3173 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE); | |
| 3174 } | |
| 3175 } else { | |
| 3176 DLOG(WARNING) << "inflate failure: " << rv << " " << len; | |
| 3177 set_error(SPDY_DECOMPRESS_FAILURE); | |
| 3178 processed_successfully = false; | |
| 3179 } | |
| 3180 } | |
| 3181 return processed_successfully; | |
| 3182 } | |
| 3183 | |
| 3184 bool SpdyFramer::IncrementallyDeliverControlFrameHeaderData( | |
| 3185 SpdyStreamId stream_id, const char* data, size_t len) { | |
| 3186 bool read_successfully = true; | |
| 3187 while (read_successfully && len > 0) { | |
| 3188 size_t bytes_to_deliver = std::min(len, kHeaderDataChunkMaxSize); | |
| 3189 read_successfully = visitor_->OnControlFrameHeaderData(stream_id, data, | |
| 3190 bytes_to_deliver); | |
| 3191 data += bytes_to_deliver; | |
| 3192 len -= bytes_to_deliver; | |
| 3193 if (!read_successfully) { | |
| 3194 // Assume that the problem was the header block was too large for the | |
| 3195 // visitor. | |
| 3196 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE); | |
| 3197 } | |
| 3198 } | |
| 3199 return read_successfully; | |
| 3200 } | |
| 3201 | |
| 3202 void SpdyFramer::SerializeNameValueBlockWithoutCompression( | |
| 3203 SpdyFrameBuilder* builder, | |
| 3204 const SpdyNameValueBlock& name_value_block) const { | |
| 3205 // Serialize number of headers. | |
| 3206 if (protocol_version() <= SPDY2) { | |
| 3207 builder->WriteUInt16(static_cast<uint16>(name_value_block.size())); | |
| 3208 } else { | |
| 3209 builder->WriteUInt32(name_value_block.size()); | |
| 3210 } | |
| 3211 | |
| 3212 // Serialize each header. | |
| 3213 for (SpdyHeaderBlock::const_iterator it = name_value_block.begin(); | |
| 3214 it != name_value_block.end(); | |
| 3215 ++it) { | |
| 3216 if (protocol_version() <= SPDY2) { | |
| 3217 builder->WriteString(it->first); | |
| 3218 builder->WriteString(it->second); | |
| 3219 } else { | |
| 3220 builder->WriteStringPiece32(it->first); | |
| 3221 builder->WriteStringPiece32(it->second); | |
| 3222 } | |
| 3223 } | |
| 3224 } | |
| 3225 | |
| 3226 void SpdyFramer::SerializeNameValueBlock( | |
| 3227 SpdyFrameBuilder* builder, | |
| 3228 const SpdyFrameWithNameValueBlockIR& frame) { | |
| 3229 CHECK_GE(SPDY3, protocol_version()); | |
| 3230 if (!enable_compression_) { | |
| 3231 return SerializeNameValueBlockWithoutCompression(builder, | |
| 3232 frame.name_value_block()); | |
| 3233 } | |
| 3234 | |
| 3235 // First build an uncompressed version to be fed into the compressor. | |
| 3236 const size_t uncompressed_len = GetSerializedLength( | |
| 3237 protocol_version(), &(frame.name_value_block())); | |
| 3238 SpdyFrameBuilder uncompressed_builder(uncompressed_len, protocol_version()); | |
| 3239 SerializeNameValueBlockWithoutCompression(&uncompressed_builder, | |
| 3240 frame.name_value_block()); | |
| 3241 scoped_ptr<SpdyFrame> uncompressed_payload(uncompressed_builder.take()); | |
| 3242 | |
| 3243 z_stream* compressor = GetHeaderCompressor(); | |
| 3244 if (!compressor) { | |
| 3245 LOG(DFATAL) << "Could not obtain compressor."; | |
| 3246 return; | |
| 3247 } | |
| 3248 // Create an output frame. | |
| 3249 // Since we'll be performing lots of flushes when compressing the data, | |
| 3250 // zlib's lower bounds may be insufficient. | |
| 3251 // | |
| 3252 // TODO(akalin): Avoid the duplicate calculation with | |
| 3253 // GetSerializedLength(const SpdyHeaderBlock&). | |
| 3254 const int compressed_max_size = | |
| 3255 2 * deflateBound(compressor, uncompressed_len); | |
| 3256 | |
| 3257 // TODO(phajdan.jr): Clean up after we no longer need | |
| 3258 // to workaround http://crbug.com/139744. | |
| 3259 #if defined(USE_SYSTEM_ZLIB) | |
| 3260 compressor->next_in = reinterpret_cast<Bytef*>(uncompressed_payload->data()); | |
| 3261 compressor->avail_in = uncompressed_len; | |
| 3262 #endif // defined(USE_SYSTEM_ZLIB) | |
| 3263 compressor->next_out = reinterpret_cast<Bytef*>( | |
| 3264 builder->GetWritableBuffer(compressed_max_size)); | |
| 3265 compressor->avail_out = compressed_max_size; | |
| 3266 | |
| 3267 // TODO(phajdan.jr): Clean up after we no longer need | |
| 3268 // to workaround http://crbug.com/139744. | |
| 3269 #if defined(USE_SYSTEM_ZLIB) | |
| 3270 int rv = deflate(compressor, Z_SYNC_FLUSH); | |
| 3271 if (rv != Z_OK) { // How can we know that it compressed everything? | |
| 3272 // This shouldn't happen, right? | |
| 3273 LOG(WARNING) << "deflate failure: " << rv; | |
| 3274 // TODO(akalin): Upstream this return. | |
| 3275 return; | |
| 3276 } | |
| 3277 #else | |
| 3278 WriteHeaderBlockToZ(&frame.name_value_block(), compressor); | |
| 3279 #endif // defined(USE_SYSTEM_ZLIB) | |
| 3280 | |
| 3281 int compressed_size = compressed_max_size - compressor->avail_out; | |
| 3282 builder->Seek(compressed_size); | |
| 3283 builder->RewriteLength(*this); | |
| 3284 } | |
| 3285 | |
| 3286 } // namespace net | |
| OLD | NEW |