| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // TODO(rtenhove) clean up frame buffer size calculations so that we aren't | 5 // TODO(rtenhove) clean up frame buffer size calculations so that we aren't |
| 6 // constantly adding and subtracting header sizes; this is ugly and error- | 6 // constantly adding and subtracting header sizes; this is ugly and error- |
| 7 // prone. | 7 // prone. |
| 8 | 8 |
| 9 #include "net/spdy/spdy_framer.h" | 9 #include "net/spdy/spdy_framer.h" |
| 10 | 10 |
| 11 #include "base/metrics/stats_counters.h" | 11 #include "base/metrics/stats_counters.h" |
| 12 #include "base/scoped_ptr.h" | 12 #include "base/scoped_ptr.h" |
| 13 #include "net/spdy/spdy_frame_builder.h" | 13 #include "net/spdy/spdy_frame_builder.h" |
| 14 #include "net/spdy/spdy_bitmasks.h" | 14 #include "net/spdy/spdy_bitmasks.h" |
| 15 | 15 |
| 16 #if defined(USE_SYSTEM_ZLIB) | 16 #if defined(USE_SYSTEM_ZLIB) |
| 17 #include <zlib.h> | 17 #include <zlib.h> |
| 18 #else | 18 #else |
| 19 #include "third_party/zlib/zlib.h" | 19 #include "third_party/zlib/zlib.h" |
| 20 #endif | 20 #endif |
| 21 | 21 |
| 22 namespace { |
| 23 |
| 24 // The following compression setting are based on Brian Olson's analysis. See |
| 25 // https://groups.google.com/group/spdy-dev/browse_thread/thread/dfaf498542fac79
2 |
| 26 // for more details. |
| 27 const int kCompressorLevel = 9; |
| 28 const int kCompressorWindowSizeInBits = 11; |
| 29 const int kCompressorMemLevel = 1; |
| 30 |
| 31 uLong dictionary_id = 0; |
| 32 |
| 33 } // namespace |
| 34 |
| 22 namespace spdy { | 35 namespace spdy { |
| 23 | 36 |
| 37 // This is just a hacked dictionary to use for shrinking HTTP-like headers. |
| 38 // TODO(mbelshe): Use a scientific methodology for computing the dictionary. |
| 39 const char SpdyFramer::kDictionary[] = |
| 40 "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-" |
| 41 "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi" |
| 42 "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser" |
| 43 "-agent10010120020120220320420520630030130230330430530630740040140240340440" |
| 44 "5406407408409410411412413414415416417500501502503504505accept-rangesageeta" |
| 45 "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic" |
| 46 "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran" |
| 47 "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati" |
| 48 "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo" |
| 49 "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe" |
| 50 "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic" |
| 51 "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1" |
| 52 ".1statusversionurl"; |
| 53 const int SpdyFramer::kDictionarySize = arraysize(kDictionary); |
| 54 |
| 24 // By default is compression on or off. | 55 // By default is compression on or off. |
| 25 bool SpdyFramer::compression_default_ = true; | 56 bool SpdyFramer::compression_default_ = true; |
| 26 int SpdyFramer::spdy_version_ = kSpdyProtocolVersion; | 57 int SpdyFramer::spdy_version_ = kSpdyProtocolVersion; |
| 27 | 58 |
| 28 // The initial size of the control frame buffer; this is used internally | 59 // The initial size of the control frame buffer; this is used internally |
| 29 // as we parse through control frames. (It is exposed here for unit test | 60 // as we parse through control frames. (It is exposed here for unit test |
| 30 // purposes.) | 61 // purposes.) |
| 31 size_t SpdyFramer::kControlFrameBufferInitialSize = 8 * 1024; | 62 size_t SpdyFramer::kControlFrameBufferInitialSize = 8 * 1024; |
| 32 | 63 |
| 33 // The maximum size of the control frame buffer that we support. | 64 // The maximum size of the control frame buffer that we support. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 64 if (header_compressor_.get()) { | 95 if (header_compressor_.get()) { |
| 65 deflateEnd(header_compressor_.get()); | 96 deflateEnd(header_compressor_.get()); |
| 66 } | 97 } |
| 67 if (header_decompressor_.get()) { | 98 if (header_decompressor_.get()) { |
| 68 inflateEnd(header_decompressor_.get()); | 99 inflateEnd(header_decompressor_.get()); |
| 69 } | 100 } |
| 70 CleanupStreamCompressorsAndDecompressors(); | 101 CleanupStreamCompressorsAndDecompressors(); |
| 71 delete [] current_frame_buffer_; | 102 delete [] current_frame_buffer_; |
| 72 } | 103 } |
| 73 | 104 |
| 74 void SpdyFramer::Reset() { | |
| 75 state_ = SPDY_RESET; | |
| 76 error_code_ = SPDY_NO_ERROR; | |
| 77 remaining_payload_ = 0; | |
| 78 remaining_control_payload_ = 0; | |
| 79 current_frame_len_ = 0; | |
| 80 if (current_frame_capacity_ != kControlFrameBufferInitialSize) { | |
| 81 delete [] current_frame_buffer_; | |
| 82 current_frame_buffer_ = 0; | |
| 83 current_frame_capacity_ = 0; | |
| 84 ExpandControlFrameBuffer(kControlFrameBufferInitialSize); | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 const char* SpdyFramer::StateToString(int state) { | |
| 89 switch (state) { | |
| 90 case SPDY_ERROR: | |
| 91 return "ERROR"; | |
| 92 case SPDY_DONE: | |
| 93 return "DONE"; | |
| 94 case SPDY_AUTO_RESET: | |
| 95 return "AUTO_RESET"; | |
| 96 case SPDY_RESET: | |
| 97 return "RESET"; | |
| 98 case SPDY_READING_COMMON_HEADER: | |
| 99 return "READING_COMMON_HEADER"; | |
| 100 case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER: | |
| 101 return "INTERPRET_CONTROL_FRAME_COMMON_HEADER"; | |
| 102 case SPDY_CONTROL_FRAME_PAYLOAD: | |
| 103 return "CONTROL_FRAME_PAYLOAD"; | |
| 104 case SPDY_IGNORE_REMAINING_PAYLOAD: | |
| 105 return "IGNORE_REMAINING_PAYLOAD"; | |
| 106 case SPDY_FORWARD_STREAM_FRAME: | |
| 107 return "FORWARD_STREAM_FRAME"; | |
| 108 } | |
| 109 return "UNKNOWN_STATE"; | |
| 110 } | |
| 111 | |
| 112 size_t SpdyFramer::BytesSafeToRead() const { | |
| 113 switch (state_) { | |
| 114 case SPDY_ERROR: | |
| 115 case SPDY_DONE: | |
| 116 case SPDY_AUTO_RESET: | |
| 117 case SPDY_RESET: | |
| 118 return 0; | |
| 119 case SPDY_READING_COMMON_HEADER: | |
| 120 DCHECK_LT(current_frame_len_, SpdyFrame::size()); | |
| 121 return SpdyFrame::size() - current_frame_len_; | |
| 122 case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER: | |
| 123 return 0; | |
| 124 case SPDY_CONTROL_FRAME_PAYLOAD: | |
| 125 case SPDY_IGNORE_REMAINING_PAYLOAD: | |
| 126 case SPDY_FORWARD_STREAM_FRAME: | |
| 127 return remaining_payload_; | |
| 128 } | |
| 129 // We should never get to here. | |
| 130 return 0; | |
| 131 } | |
| 132 | |
| 133 void SpdyFramer::set_error(SpdyError error) { | |
| 134 DCHECK(visitor_); | |
| 135 error_code_ = error; | |
| 136 CHANGE_STATE(SPDY_ERROR); | |
| 137 visitor_->OnError(this); | |
| 138 } | |
| 139 | |
| 140 const char* SpdyFramer::ErrorCodeToString(int error_code) { | |
| 141 switch (error_code) { | |
| 142 case SPDY_NO_ERROR: | |
| 143 return "NO_ERROR"; | |
| 144 case SPDY_INVALID_CONTROL_FRAME: | |
| 145 return "INVALID_CONTROL_FRAME"; | |
| 146 case SPDY_CONTROL_PAYLOAD_TOO_LARGE: | |
| 147 return "CONTROL_PAYLOAD_TOO_LARGE"; | |
| 148 case SPDY_ZLIB_INIT_FAILURE: | |
| 149 return "ZLIB_INIT_FAILURE"; | |
| 150 case SPDY_UNSUPPORTED_VERSION: | |
| 151 return "UNSUPPORTED_VERSION"; | |
| 152 case SPDY_DECOMPRESS_FAILURE: | |
| 153 return "DECOMPRESS_FAILURE"; | |
| 154 case SPDY_COMPRESS_FAILURE: | |
| 155 return "COMPRESS_FAILURE"; | |
| 156 } | |
| 157 return "UNKNOWN_ERROR"; | |
| 158 } | |
| 159 | |
| 160 size_t SpdyFramer::ProcessInput(const char* data, size_t len) { | 105 size_t SpdyFramer::ProcessInput(const char* data, size_t len) { |
| 161 DCHECK(visitor_); | 106 DCHECK(visitor_); |
| 162 DCHECK(data); | 107 DCHECK(data); |
| 163 | 108 |
| 164 size_t original_len = len; | 109 size_t original_len = len; |
| 165 while (len != 0) { | 110 while (len != 0) { |
| 166 switch (state_) { | 111 switch (state_) { |
| 167 case SPDY_ERROR: | 112 case SPDY_ERROR: |
| 168 case SPDY_DONE: | 113 case SPDY_DONE: |
| 169 goto bottom; | 114 goto bottom; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 continue; | 149 continue; |
| 205 } | 150 } |
| 206 default: | 151 default: |
| 207 break; | 152 break; |
| 208 } | 153 } |
| 209 } | 154 } |
| 210 bottom: | 155 bottom: |
| 211 return original_len - len; | 156 return original_len - len; |
| 212 } | 157 } |
| 213 | 158 |
| 214 size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) { | 159 void SpdyFramer::Reset() { |
| 215 // This should only be called when we're in the SPDY_READING_COMMON_HEADER | 160 state_ = SPDY_RESET; |
| 216 // state. | 161 error_code_ = SPDY_NO_ERROR; |
| 217 DCHECK_EQ(state_, SPDY_READING_COMMON_HEADER); | 162 remaining_payload_ = 0; |
| 218 | 163 remaining_control_payload_ = 0; |
| 219 size_t original_len = len; | 164 current_frame_len_ = 0; |
| 220 SpdyFrame current_frame(current_frame_buffer_, false); | 165 if (current_frame_capacity_ != kControlFrameBufferInitialSize) { |
| 221 | 166 delete [] current_frame_buffer_; |
| 222 do { | 167 current_frame_buffer_ = 0; |
| 223 if (current_frame_len_ < SpdyFrame::size()) { | 168 current_frame_capacity_ = 0; |
| 224 size_t bytes_desired = SpdyFrame::size() - current_frame_len_; | 169 ExpandControlFrameBuffer(kControlFrameBufferInitialSize); |
| 225 size_t bytes_to_append = std::min(bytes_desired, len); | |
| 226 char* header_buffer = current_frame_buffer_; | |
| 227 memcpy(&header_buffer[current_frame_len_], data, bytes_to_append); | |
| 228 current_frame_len_ += bytes_to_append; | |
| 229 data += bytes_to_append; | |
| 230 len -= bytes_to_append; | |
| 231 // Check for an empty data frame. | |
| 232 if (current_frame_len_ == SpdyFrame::size() && | |
| 233 !current_frame.is_control_frame() && | |
| 234 current_frame.length() == 0) { | |
| 235 if (current_frame.flags() & CONTROL_FLAG_FIN) { | |
| 236 SpdyDataFrame data_frame(current_frame_buffer_, false); | |
| 237 visitor_->OnStreamFrameData(data_frame.stream_id(), NULL, 0); | |
| 238 } | |
| 239 CHANGE_STATE(SPDY_AUTO_RESET); | |
| 240 } | |
| 241 break; | |
| 242 } | |
| 243 remaining_payload_ = current_frame.length(); | |
| 244 | |
| 245 // This is just a sanity check for help debugging early frame errors. | |
| 246 if (remaining_payload_ > 1000000u) { | |
| 247 LOG(WARNING) << | |
| 248 "Unexpectedly large frame. Spdy session is likely corrupt."; | |
| 249 } | |
| 250 | |
| 251 // if we're here, then we have the common header all received. | |
| 252 if (!current_frame.is_control_frame()) | |
| 253 CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME); | |
| 254 else | |
| 255 CHANGE_STATE(SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER); | |
| 256 } while (false); | |
| 257 | |
| 258 return original_len - len; | |
| 259 } | |
| 260 | |
| 261 void SpdyFramer::ProcessControlFrameHeader() { | |
| 262 DCHECK_EQ(SPDY_NO_ERROR, error_code_); | |
| 263 DCHECK_LE(SpdyFrame::size(), current_frame_len_); | |
| 264 SpdyControlFrame current_control_frame(current_frame_buffer_, false); | |
| 265 | |
| 266 // We check version before we check validity: version can never be 'invalid', | |
| 267 // it can only be unsupported. | |
| 268 if (current_control_frame.version() != spdy_version_) { | |
| 269 set_error(SPDY_UNSUPPORTED_VERSION); | |
| 270 return; | |
| 271 } | 170 } |
| 272 | |
| 273 // Next up, check to see if we have valid data. This should be after version | |
| 274 // checking (otherwise if the the type were out of bounds due to a version | |
| 275 // upgrade we would misclassify the error) and before checking the type | |
| 276 // (type can definitely be out of bounds) | |
| 277 if (!current_control_frame.AppearsToBeAValidControlFrame()) { | |
| 278 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 279 return; | |
| 280 } | |
| 281 | |
| 282 // Do some sanity checking on the control frame sizes. | |
| 283 switch (current_control_frame.type()) { | |
| 284 case SYN_STREAM: | |
| 285 if (current_control_frame.length() < | |
| 286 SpdySynStreamControlFrame::size() - SpdyControlFrame::size()) | |
| 287 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 288 break; | |
| 289 case SYN_REPLY: | |
| 290 if (current_control_frame.length() < | |
| 291 SpdySynReplyControlFrame::size() - SpdyControlFrame::size()) | |
| 292 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 293 break; | |
| 294 case RST_STREAM: | |
| 295 if (current_control_frame.length() != | |
| 296 SpdyRstStreamControlFrame::size() - SpdyFrame::size()) | |
| 297 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 298 break; | |
| 299 case SETTINGS: | |
| 300 if (current_control_frame.length() < | |
| 301 SpdySettingsControlFrame::size() - SpdyControlFrame::size()) | |
| 302 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 303 break; | |
| 304 case NOOP: | |
| 305 // NOOP. Swallow it. | |
| 306 CHANGE_STATE(SPDY_AUTO_RESET); | |
| 307 return; | |
| 308 case GOAWAY: | |
| 309 if (current_control_frame.length() != | |
| 310 SpdyGoAwayControlFrame::size() - SpdyFrame::size()) | |
| 311 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 312 break; | |
| 313 case HEADERS: | |
| 314 if (current_control_frame.length() < | |
| 315 SpdyHeadersControlFrame::size() - SpdyControlFrame::size()) | |
| 316 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 317 break; | |
| 318 case WINDOW_UPDATE: | |
| 319 if (current_control_frame.length() != | |
| 320 SpdyWindowUpdateControlFrame::size() - SpdyControlFrame::size()) | |
| 321 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 322 break; | |
| 323 default: | |
| 324 LOG(WARNING) << "Valid spdy control frame with unknown type: " | |
| 325 << current_control_frame.type(); | |
| 326 DCHECK(false); | |
| 327 set_error(SPDY_INVALID_CONTROL_FRAME); | |
| 328 break; | |
| 329 } | |
| 330 | |
| 331 remaining_control_payload_ = current_control_frame.length(); | |
| 332 if (remaining_control_payload_ > kControlFrameBufferMaxSize) { | |
| 333 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE); | |
| 334 return; | |
| 335 } | |
| 336 | |
| 337 ExpandControlFrameBuffer(remaining_control_payload_); | |
| 338 CHANGE_STATE(SPDY_CONTROL_FRAME_PAYLOAD); | |
| 339 } | |
| 340 | |
| 341 size_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) { | |
| 342 size_t original_len = len; | |
| 343 do { | |
| 344 if (remaining_control_payload_) { | |
| 345 size_t amount_to_consume = std::min(remaining_control_payload_, len); | |
| 346 memcpy(¤t_frame_buffer_[current_frame_len_], data, | |
| 347 amount_to_consume); | |
| 348 current_frame_len_ += amount_to_consume; | |
| 349 data += amount_to_consume; | |
| 350 len -= amount_to_consume; | |
| 351 remaining_control_payload_ -= amount_to_consume; | |
| 352 remaining_payload_ -= amount_to_consume; | |
| 353 if (remaining_control_payload_) | |
| 354 break; | |
| 355 } | |
| 356 SpdyControlFrame control_frame(current_frame_buffer_, false); | |
| 357 visitor_->OnControl(&control_frame); | |
| 358 | |
| 359 // If this is a FIN, tell the caller. | |
| 360 if (control_frame.type() == SYN_REPLY && | |
| 361 control_frame.flags() & CONTROL_FLAG_FIN) { | |
| 362 visitor_->OnStreamFrameData(reinterpret_cast<SpdySynReplyControlFrame*>( | |
| 363 &control_frame)->stream_id(), | |
| 364 NULL, 0); | |
| 365 } | |
| 366 | |
| 367 CHANGE_STATE(SPDY_IGNORE_REMAINING_PAYLOAD); | |
| 368 } while (false); | |
| 369 return original_len - len; | |
| 370 } | |
| 371 | |
| 372 size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) { | |
| 373 size_t original_len = len; | |
| 374 | |
| 375 SpdyDataFrame current_data_frame(current_frame_buffer_, false); | |
| 376 if (remaining_payload_) { | |
| 377 size_t amount_to_forward = std::min(remaining_payload_, len); | |
| 378 if (amount_to_forward && state_ != SPDY_IGNORE_REMAINING_PAYLOAD) { | |
| 379 if (current_data_frame.flags() & DATA_FLAG_COMPRESSED) { | |
| 380 z_stream* decompressor = | |
| 381 GetStreamDecompressor(current_data_frame.stream_id()); | |
| 382 if (!decompressor) | |
| 383 return 0; | |
| 384 | |
| 385 size_t decompressed_max_size = amount_to_forward * 100; | |
| 386 scoped_array<char> decompressed(new char[decompressed_max_size]); | |
| 387 decompressor->next_in = reinterpret_cast<Bytef*>( | |
| 388 const_cast<char*>(data)); | |
| 389 decompressor->avail_in = amount_to_forward; | |
| 390 decompressor->next_out = | |
| 391 reinterpret_cast<Bytef*>(decompressed.get()); | |
| 392 decompressor->avail_out = decompressed_max_size; | |
| 393 | |
| 394 int rv = inflate(decompressor, Z_SYNC_FLUSH); | |
| 395 if (rv != Z_OK) { | |
| 396 LOG(WARNING) << "inflate failure: " << rv; | |
| 397 set_error(SPDY_DECOMPRESS_FAILURE); | |
| 398 return 0; | |
| 399 } | |
| 400 size_t decompressed_size = decompressed_max_size - | |
| 401 decompressor->avail_out; | |
| 402 | |
| 403 // Only inform the visitor if there is data. | |
| 404 if (decompressed_size) | |
| 405 visitor_->OnStreamFrameData(current_data_frame.stream_id(), | |
| 406 decompressed.get(), | |
| 407 decompressed_size); | |
| 408 amount_to_forward -= decompressor->avail_in; | |
| 409 } else { | |
| 410 // The data frame was not compressed. | |
| 411 // Only inform the visitor if there is data. | |
| 412 if (amount_to_forward) | |
| 413 visitor_->OnStreamFrameData(current_data_frame.stream_id(), | |
| 414 data, amount_to_forward); | |
| 415 } | |
| 416 } | |
| 417 data += amount_to_forward; | |
| 418 len -= amount_to_forward; | |
| 419 remaining_payload_ -= amount_to_forward; | |
| 420 | |
| 421 // If the FIN flag is set, and there is no more data in this data | |
| 422 // frame, inform the visitor of EOF via a 0-length data frame. | |
| 423 if (!remaining_payload_ && | |
| 424 current_data_frame.flags() & DATA_FLAG_FIN) { | |
| 425 visitor_->OnStreamFrameData(current_data_frame.stream_id(), NULL, 0); | |
| 426 CleanupDecompressorForStream(current_data_frame.stream_id()); | |
| 427 } | |
| 428 } else { | |
| 429 CHANGE_STATE(SPDY_AUTO_RESET); | |
| 430 } | |
| 431 return original_len - len; | |
| 432 } | |
| 433 | |
| 434 void SpdyFramer::ExpandControlFrameBuffer(size_t size) { | |
| 435 size_t alloc_size = size + SpdyFrame::size(); | |
| 436 DCHECK_LT(alloc_size, kControlFrameBufferMaxSize); | |
| 437 if (alloc_size <= current_frame_capacity_) | |
| 438 return; | |
| 439 char* new_buffer = new char[alloc_size]; | |
| 440 memcpy(new_buffer, current_frame_buffer_, current_frame_len_); | |
| 441 delete [] current_frame_buffer_; | |
| 442 current_frame_capacity_ = alloc_size; | |
| 443 current_frame_buffer_ = new_buffer; | |
| 444 } | 171 } |
| 445 | 172 |
| 446 bool SpdyFramer::ParseHeaderBlock(const SpdyFrame* frame, | 173 bool SpdyFramer::ParseHeaderBlock(const SpdyFrame* frame, |
| 447 SpdyHeaderBlock* block) { | 174 SpdyHeaderBlock* block) { |
| 448 SpdyControlFrame control_frame(frame->data(), false); | 175 SpdyControlFrame control_frame(frame->data(), false); |
| 449 uint32 type = control_frame.type(); | 176 uint32 type = control_frame.type(); |
| 450 if (type != SYN_STREAM && type != SYN_REPLY && type != HEADERS) | 177 if (type != SYN_STREAM && type != SYN_REPLY && type != HEADERS) |
| 451 return false; | 178 return false; |
| 452 | 179 |
| 453 // Find the header data within the control frame. | 180 // Find the header data within the control frame. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 501 } else { | 228 } else { |
| 502 return false; | 229 return false; |
| 503 } | 230 } |
| 504 } | 231 } |
| 505 return index == num_headers && | 232 return index == num_headers && |
| 506 iter == header_data + header_length; | 233 iter == header_data + header_length; |
| 507 } | 234 } |
| 508 return false; | 235 return false; |
| 509 } | 236 } |
| 510 | 237 |
| 511 /* static */ | |
| 512 bool SpdyFramer::ParseSettings(const SpdySettingsControlFrame* frame, | |
| 513 SpdySettings* settings) { | |
| 514 DCHECK_EQ(frame->type(), SETTINGS); | |
| 515 DCHECK(settings); | |
| 516 | |
| 517 SpdyFrameBuilder parser(frame->header_block(), frame->header_block_len()); | |
| 518 void* iter = NULL; | |
| 519 for (size_t index = 0; index < frame->num_entries(); ++index) { | |
| 520 uint32 id; | |
| 521 uint32 value; | |
| 522 if (!parser.ReadUInt32(&iter, &id)) | |
| 523 return false; | |
| 524 if (!parser.ReadUInt32(&iter, &value)) | |
| 525 return false; | |
| 526 settings->insert(settings->end(), std::make_pair(id, value)); | |
| 527 } | |
| 528 return true; | |
| 529 } | |
| 530 | |
| 531 SpdySynStreamControlFrame* SpdyFramer::CreateSynStream( | 238 SpdySynStreamControlFrame* SpdyFramer::CreateSynStream( |
| 532 SpdyStreamId stream_id, SpdyStreamId associated_stream_id, int priority, | 239 SpdyStreamId stream_id, SpdyStreamId associated_stream_id, int priority, |
| 533 SpdyControlFlags flags, bool compressed, SpdyHeaderBlock* headers) { | 240 SpdyControlFlags flags, bool compressed, SpdyHeaderBlock* headers) { |
| 534 SpdyFrameBuilder frame; | 241 SpdyFrameBuilder frame; |
| 535 | 242 |
| 536 DCHECK_GT(stream_id, static_cast<SpdyStreamId>(0)); | 243 DCHECK_GT(stream_id, static_cast<SpdyStreamId>(0)); |
| 537 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); | 244 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); |
| 538 DCHECK_EQ(0u, associated_stream_id & ~kStreamIdMask); | 245 DCHECK_EQ(0u, associated_stream_id & ~kStreamIdMask); |
| 539 | 246 |
| 540 frame.WriteUInt16(kControlFlagMask | spdy_version_); | 247 frame.WriteUInt16(kControlFlagMask | spdy_version_); |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 720 frame.WriteUInt16(kControlFlagMask | spdy_version_); | 427 frame.WriteUInt16(kControlFlagMask | spdy_version_); |
| 721 frame.WriteUInt16(WINDOW_UPDATE); | 428 frame.WriteUInt16(WINDOW_UPDATE); |
| 722 size_t window_update_size = SpdyWindowUpdateControlFrame::size() - | 429 size_t window_update_size = SpdyWindowUpdateControlFrame::size() - |
| 723 SpdyFrame::size(); | 430 SpdyFrame::size(); |
| 724 frame.WriteUInt32(window_update_size); | 431 frame.WriteUInt32(window_update_size); |
| 725 frame.WriteUInt32(stream_id); | 432 frame.WriteUInt32(stream_id); |
| 726 frame.WriteUInt32(delta_window_size); | 433 frame.WriteUInt32(delta_window_size); |
| 727 return reinterpret_cast<SpdyWindowUpdateControlFrame*>(frame.take()); | 434 return reinterpret_cast<SpdyWindowUpdateControlFrame*>(frame.take()); |
| 728 } | 435 } |
| 729 | 436 |
| 437 /* static */ |
| 438 bool SpdyFramer::ParseSettings(const SpdySettingsControlFrame* frame, |
| 439 SpdySettings* settings) { |
| 440 DCHECK_EQ(frame->type(), SETTINGS); |
| 441 DCHECK(settings); |
| 442 |
| 443 SpdyFrameBuilder parser(frame->header_block(), frame->header_block_len()); |
| 444 void* iter = NULL; |
| 445 for (size_t index = 0; index < frame->num_entries(); ++index) { |
| 446 uint32 id; |
| 447 uint32 value; |
| 448 if (!parser.ReadUInt32(&iter, &id)) |
| 449 return false; |
| 450 if (!parser.ReadUInt32(&iter, &value)) |
| 451 return false; |
| 452 settings->insert(settings->end(), std::make_pair(id, value)); |
| 453 } |
| 454 return true; |
| 455 } |
| 456 |
| 730 SpdyDataFrame* SpdyFramer::CreateDataFrame(SpdyStreamId stream_id, | 457 SpdyDataFrame* SpdyFramer::CreateDataFrame(SpdyStreamId stream_id, |
| 731 const char* data, | 458 const char* data, |
| 732 uint32 len, SpdyDataFlags flags) { | 459 uint32 len, SpdyDataFlags flags) { |
| 733 SpdyFrameBuilder frame; | 460 SpdyFrameBuilder frame; |
| 734 | 461 |
| 735 DCHECK_GT(stream_id, 0u); | 462 DCHECK_GT(stream_id, 0u); |
| 736 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); | 463 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); |
| 737 frame.WriteUInt32(stream_id); | 464 frame.WriteUInt32(stream_id); |
| 738 | 465 |
| 739 DCHECK_EQ(0u, len & ~static_cast<size_t>(kLengthMask)); | 466 DCHECK_EQ(0u, len & ~static_cast<size_t>(kLengthMask)); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 752 rv = reinterpret_cast<SpdyDataFrame*>(data_frame.release()); | 479 rv = reinterpret_cast<SpdyDataFrame*>(data_frame.release()); |
| 753 } | 480 } |
| 754 | 481 |
| 755 if (flags & DATA_FLAG_FIN) { | 482 if (flags & DATA_FLAG_FIN) { |
| 756 CleanupCompressorForStream(stream_id); | 483 CleanupCompressorForStream(stream_id); |
| 757 } | 484 } |
| 758 | 485 |
| 759 return rv; | 486 return rv; |
| 760 } | 487 } |
| 761 | 488 |
| 762 // The following compression setting are based on Brian Olson's analysis. See | 489 SpdyFrame* SpdyFramer::CompressFrame(const SpdyFrame& frame) { |
| 763 // https://groups.google.com/group/spdy-dev/browse_thread/thread/dfaf498542fac79
2 | 490 if (frame.is_control_frame()) { |
| 764 // for more details. | 491 return CompressControlFrame( |
| 765 static const int kCompressorLevel = 9; | 492 reinterpret_cast<const SpdyControlFrame&>(frame)); |
| 766 static const int kCompressorWindowSizeInBits = 11; | 493 } |
| 767 static const int kCompressorMemLevel = 1; | 494 return CompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame)); |
| 768 | 495 } |
| 769 // This is just a hacked dictionary to use for shrinking HTTP-like headers. | 496 |
| 770 // TODO(mbelshe): Use a scientific methodology for computing the dictionary. | 497 SpdyFrame* SpdyFramer::DecompressFrame(const SpdyFrame& frame) { |
| 771 const char SpdyFramer::kDictionary[] = | 498 if (frame.is_control_frame()) { |
| 772 "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-" | 499 return DecompressControlFrame( |
| 773 "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi" | 500 reinterpret_cast<const SpdyControlFrame&>(frame)); |
| 774 "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser" | 501 } |
| 775 "-agent10010120020120220320420520630030130230330430530630740040140240340440" | 502 return DecompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame)); |
| 776 "5406407408409410411412413414415416417500501502503504505accept-rangesageeta" | 503 } |
| 777 "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic" | 504 |
| 778 "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran" | 505 SpdyFrame* SpdyFramer::DuplicateFrame(const SpdyFrame& frame) { |
| 779 "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati" | 506 int size = SpdyFrame::size() + frame.length(); |
| 780 "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo" | 507 SpdyFrame* new_frame = new SpdyFrame(size); |
| 781 "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe" | 508 memcpy(new_frame->data(), frame.data(), size); |
| 782 "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic" | 509 return new_frame; |
| 783 "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1" | 510 } |
| 784 ".1statusversionurl"; | 511 |
| 785 const int SpdyFramer::kDictionarySize = arraysize(kDictionary); | 512 bool SpdyFramer::IsCompressible(const SpdyFrame& frame) const { |
| 786 | 513 // The important frames to compress are those which contain large |
| 787 static uLong dictionary_id = 0; | 514 // amounts of compressible data - namely the headers in the SYN_STREAM |
| 515 // and SYN_REPLY. |
| 516 // TODO(mbelshe): Reconcile this with the spec when the spec is |
| 517 // explicit about which frames compress and which do not. |
| 518 if (frame.is_control_frame()) { |
| 519 const SpdyControlFrame& control_frame = |
| 520 reinterpret_cast<const SpdyControlFrame&>(frame); |
| 521 return control_frame.type() == SYN_STREAM || |
| 522 control_frame.type() == SYN_REPLY; |
| 523 } |
| 524 |
| 525 const SpdyDataFrame& data_frame = |
| 526 reinterpret_cast<const SpdyDataFrame&>(frame); |
| 527 return (data_frame.flags() & DATA_FLAG_COMPRESSED) != 0; |
| 528 } |
| 529 |
| 530 const char* SpdyFramer::StateToString(int state) { |
| 531 switch (state) { |
| 532 case SPDY_ERROR: |
| 533 return "ERROR"; |
| 534 case SPDY_DONE: |
| 535 return "DONE"; |
| 536 case SPDY_AUTO_RESET: |
| 537 return "AUTO_RESET"; |
| 538 case SPDY_RESET: |
| 539 return "RESET"; |
| 540 case SPDY_READING_COMMON_HEADER: |
| 541 return "READING_COMMON_HEADER"; |
| 542 case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER: |
| 543 return "INTERPRET_CONTROL_FRAME_COMMON_HEADER"; |
| 544 case SPDY_CONTROL_FRAME_PAYLOAD: |
| 545 return "CONTROL_FRAME_PAYLOAD"; |
| 546 case SPDY_IGNORE_REMAINING_PAYLOAD: |
| 547 return "IGNORE_REMAINING_PAYLOAD"; |
| 548 case SPDY_FORWARD_STREAM_FRAME: |
| 549 return "FORWARD_STREAM_FRAME"; |
| 550 } |
| 551 return "UNKNOWN_STATE"; |
| 552 } |
| 553 |
| 554 const char* SpdyFramer::ErrorCodeToString(int error_code) { |
| 555 switch (error_code) { |
| 556 case SPDY_NO_ERROR: |
| 557 return "NO_ERROR"; |
| 558 case SPDY_INVALID_CONTROL_FRAME: |
| 559 return "INVALID_CONTROL_FRAME"; |
| 560 case SPDY_CONTROL_PAYLOAD_TOO_LARGE: |
| 561 return "CONTROL_PAYLOAD_TOO_LARGE"; |
| 562 case SPDY_ZLIB_INIT_FAILURE: |
| 563 return "ZLIB_INIT_FAILURE"; |
| 564 case SPDY_UNSUPPORTED_VERSION: |
| 565 return "UNSUPPORTED_VERSION"; |
| 566 case SPDY_DECOMPRESS_FAILURE: |
| 567 return "DECOMPRESS_FAILURE"; |
| 568 case SPDY_COMPRESS_FAILURE: |
| 569 return "COMPRESS_FAILURE"; |
| 570 } |
| 571 return "UNKNOWN_ERROR"; |
| 572 } |
| 573 |
| 574 void SpdyFramer::set_enable_compression(bool value) { |
| 575 enable_compression_ = value; |
| 576 } |
| 577 |
| 578 void SpdyFramer::set_enable_compression_default(bool value) { |
| 579 compression_default_ = value; |
| 580 } |
| 581 |
| 582 size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) { |
| 583 // This should only be called when we're in the SPDY_READING_COMMON_HEADER |
| 584 // state. |
| 585 DCHECK_EQ(state_, SPDY_READING_COMMON_HEADER); |
| 586 |
| 587 size_t original_len = len; |
| 588 SpdyFrame current_frame(current_frame_buffer_, false); |
| 589 |
| 590 do { |
| 591 if (current_frame_len_ < SpdyFrame::size()) { |
| 592 size_t bytes_desired = SpdyFrame::size() - current_frame_len_; |
| 593 size_t bytes_to_append = std::min(bytes_desired, len); |
| 594 char* header_buffer = current_frame_buffer_; |
| 595 memcpy(&header_buffer[current_frame_len_], data, bytes_to_append); |
| 596 current_frame_len_ += bytes_to_append; |
| 597 data += bytes_to_append; |
| 598 len -= bytes_to_append; |
| 599 // Check for an empty data frame. |
| 600 if (current_frame_len_ == SpdyFrame::size() && |
| 601 !current_frame.is_control_frame() && |
| 602 current_frame.length() == 0) { |
| 603 if (current_frame.flags() & CONTROL_FLAG_FIN) { |
| 604 SpdyDataFrame data_frame(current_frame_buffer_, false); |
| 605 visitor_->OnStreamFrameData(data_frame.stream_id(), NULL, 0); |
| 606 } |
| 607 CHANGE_STATE(SPDY_AUTO_RESET); |
| 608 } |
| 609 break; |
| 610 } |
| 611 remaining_payload_ = current_frame.length(); |
| 612 |
| 613 // This is just a sanity check for help debugging early frame errors. |
| 614 if (remaining_payload_ > 1000000u) { |
| 615 LOG(WARNING) << |
| 616 "Unexpectedly large frame. Spdy session is likely corrupt."; |
| 617 } |
| 618 |
| 619 // if we're here, then we have the common header all received. |
| 620 if (!current_frame.is_control_frame()) |
| 621 CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME); |
| 622 else |
| 623 CHANGE_STATE(SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER); |
| 624 } while (false); |
| 625 |
| 626 return original_len - len; |
| 627 } |
| 628 |
| 629 void SpdyFramer::ProcessControlFrameHeader() { |
| 630 DCHECK_EQ(SPDY_NO_ERROR, error_code_); |
| 631 DCHECK_LE(SpdyFrame::size(), current_frame_len_); |
| 632 SpdyControlFrame current_control_frame(current_frame_buffer_, false); |
| 633 |
| 634 // We check version before we check validity: version can never be 'invalid', |
| 635 // it can only be unsupported. |
| 636 if (current_control_frame.version() != spdy_version_) { |
| 637 set_error(SPDY_UNSUPPORTED_VERSION); |
| 638 return; |
| 639 } |
| 640 |
| 641 // Next up, check to see if we have valid data. This should be after version |
| 642 // checking (otherwise if the the type were out of bounds due to a version |
| 643 // upgrade we would misclassify the error) and before checking the type |
| 644 // (type can definitely be out of bounds) |
| 645 if (!current_control_frame.AppearsToBeAValidControlFrame()) { |
| 646 set_error(SPDY_INVALID_CONTROL_FRAME); |
| 647 return; |
| 648 } |
| 649 |
| 650 // Do some sanity checking on the control frame sizes. |
| 651 switch (current_control_frame.type()) { |
| 652 case SYN_STREAM: |
| 653 if (current_control_frame.length() < |
| 654 SpdySynStreamControlFrame::size() - SpdyControlFrame::size()) |
| 655 set_error(SPDY_INVALID_CONTROL_FRAME); |
| 656 break; |
| 657 case SYN_REPLY: |
| 658 if (current_control_frame.length() < |
| 659 SpdySynReplyControlFrame::size() - SpdyControlFrame::size()) |
| 660 set_error(SPDY_INVALID_CONTROL_FRAME); |
| 661 break; |
| 662 case RST_STREAM: |
| 663 if (current_control_frame.length() != |
| 664 SpdyRstStreamControlFrame::size() - SpdyFrame::size()) |
| 665 set_error(SPDY_INVALID_CONTROL_FRAME); |
| 666 break; |
| 667 case SETTINGS: |
| 668 if (current_control_frame.length() < |
| 669 SpdySettingsControlFrame::size() - SpdyControlFrame::size()) |
| 670 set_error(SPDY_INVALID_CONTROL_FRAME); |
| 671 break; |
| 672 case NOOP: |
| 673 // NOOP. Swallow it. |
| 674 CHANGE_STATE(SPDY_AUTO_RESET); |
| 675 return; |
| 676 case GOAWAY: |
| 677 if (current_control_frame.length() != |
| 678 SpdyGoAwayControlFrame::size() - SpdyFrame::size()) |
| 679 set_error(SPDY_INVALID_CONTROL_FRAME); |
| 680 break; |
| 681 case HEADERS: |
| 682 if (current_control_frame.length() < |
| 683 SpdyHeadersControlFrame::size() - SpdyControlFrame::size()) |
| 684 set_error(SPDY_INVALID_CONTROL_FRAME); |
| 685 break; |
| 686 case WINDOW_UPDATE: |
| 687 if (current_control_frame.length() != |
| 688 SpdyWindowUpdateControlFrame::size() - SpdyControlFrame::size()) |
| 689 set_error(SPDY_INVALID_CONTROL_FRAME); |
| 690 break; |
| 691 default: |
| 692 LOG(WARNING) << "Valid spdy control frame with unknown type: " |
| 693 << current_control_frame.type(); |
| 694 DCHECK(false); |
| 695 set_error(SPDY_INVALID_CONTROL_FRAME); |
| 696 break; |
| 697 } |
| 698 |
| 699 remaining_control_payload_ = current_control_frame.length(); |
| 700 if (remaining_control_payload_ > kControlFrameBufferMaxSize) { |
| 701 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE); |
| 702 return; |
| 703 } |
| 704 |
| 705 ExpandControlFrameBuffer(remaining_control_payload_); |
| 706 CHANGE_STATE(SPDY_CONTROL_FRAME_PAYLOAD); |
| 707 } |
| 708 |
| 709 size_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) { |
| 710 size_t original_len = len; |
| 711 do { |
| 712 if (remaining_control_payload_) { |
| 713 size_t amount_to_consume = std::min(remaining_control_payload_, len); |
| 714 memcpy(¤t_frame_buffer_[current_frame_len_], data, |
| 715 amount_to_consume); |
| 716 current_frame_len_ += amount_to_consume; |
| 717 data += amount_to_consume; |
| 718 len -= amount_to_consume; |
| 719 remaining_control_payload_ -= amount_to_consume; |
| 720 remaining_payload_ -= amount_to_consume; |
| 721 if (remaining_control_payload_) |
| 722 break; |
| 723 } |
| 724 SpdyControlFrame control_frame(current_frame_buffer_, false); |
| 725 visitor_->OnControl(&control_frame); |
| 726 |
| 727 // If this is a FIN, tell the caller. |
| 728 if (control_frame.type() == SYN_REPLY && |
| 729 control_frame.flags() & CONTROL_FLAG_FIN) { |
| 730 visitor_->OnStreamFrameData(reinterpret_cast<SpdySynReplyControlFrame*>( |
| 731 &control_frame)->stream_id(), |
| 732 NULL, 0); |
| 733 } |
| 734 |
| 735 CHANGE_STATE(SPDY_IGNORE_REMAINING_PAYLOAD); |
| 736 } while (false); |
| 737 return original_len - len; |
| 738 } |
| 739 |
| 740 size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) { |
| 741 size_t original_len = len; |
| 742 |
| 743 SpdyDataFrame current_data_frame(current_frame_buffer_, false); |
| 744 if (remaining_payload_) { |
| 745 size_t amount_to_forward = std::min(remaining_payload_, len); |
| 746 if (amount_to_forward && state_ != SPDY_IGNORE_REMAINING_PAYLOAD) { |
| 747 if (current_data_frame.flags() & DATA_FLAG_COMPRESSED) { |
| 748 z_stream* decompressor = |
| 749 GetStreamDecompressor(current_data_frame.stream_id()); |
| 750 if (!decompressor) |
| 751 return 0; |
| 752 |
| 753 size_t decompressed_max_size = amount_to_forward * 100; |
| 754 scoped_array<char> decompressed(new char[decompressed_max_size]); |
| 755 decompressor->next_in = reinterpret_cast<Bytef*>( |
| 756 const_cast<char*>(data)); |
| 757 decompressor->avail_in = amount_to_forward; |
| 758 decompressor->next_out = |
| 759 reinterpret_cast<Bytef*>(decompressed.get()); |
| 760 decompressor->avail_out = decompressed_max_size; |
| 761 |
| 762 int rv = inflate(decompressor, Z_SYNC_FLUSH); |
| 763 if (rv != Z_OK) { |
| 764 LOG(WARNING) << "inflate failure: " << rv; |
| 765 set_error(SPDY_DECOMPRESS_FAILURE); |
| 766 return 0; |
| 767 } |
| 768 size_t decompressed_size = decompressed_max_size - |
| 769 decompressor->avail_out; |
| 770 |
| 771 // Only inform the visitor if there is data. |
| 772 if (decompressed_size) |
| 773 visitor_->OnStreamFrameData(current_data_frame.stream_id(), |
| 774 decompressed.get(), |
| 775 decompressed_size); |
| 776 amount_to_forward -= decompressor->avail_in; |
| 777 } else { |
| 778 // The data frame was not compressed. |
| 779 // Only inform the visitor if there is data. |
| 780 if (amount_to_forward) |
| 781 visitor_->OnStreamFrameData(current_data_frame.stream_id(), |
| 782 data, amount_to_forward); |
| 783 } |
| 784 } |
| 785 data += amount_to_forward; |
| 786 len -= amount_to_forward; |
| 787 remaining_payload_ -= amount_to_forward; |
| 788 |
| 789 // If the FIN flag is set, and there is no more data in this data |
| 790 // frame, inform the visitor of EOF via a 0-length data frame. |
| 791 if (!remaining_payload_ && |
| 792 current_data_frame.flags() & DATA_FLAG_FIN) { |
| 793 visitor_->OnStreamFrameData(current_data_frame.stream_id(), NULL, 0); |
| 794 CleanupDecompressorForStream(current_data_frame.stream_id()); |
| 795 } |
| 796 } else { |
| 797 CHANGE_STATE(SPDY_AUTO_RESET); |
| 798 } |
| 799 return original_len - len; |
| 800 } |
| 788 | 801 |
| 789 z_stream* SpdyFramer::GetHeaderCompressor() { | 802 z_stream* SpdyFramer::GetHeaderCompressor() { |
| 790 if (header_compressor_.get()) | 803 if (header_compressor_.get()) |
| 791 return header_compressor_.get(); // Already initialized. | 804 return header_compressor_.get(); // Already initialized. |
| 792 | 805 |
| 793 header_compressor_.reset(new z_stream); | 806 header_compressor_.reset(new z_stream); |
| 794 memset(header_compressor_.get(), 0, sizeof(z_stream)); | 807 memset(header_compressor_.get(), 0, sizeof(z_stream)); |
| 795 | 808 |
| 796 int success = deflateInit2(header_compressor_.get(), | 809 int success = deflateInit2(header_compressor_.get(), |
| 797 kCompressorLevel, | 810 kCompressorLevel, |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 866 memset(decompressor.get(), 0, sizeof(z_stream)); | 879 memset(decompressor.get(), 0, sizeof(z_stream)); |
| 867 | 880 |
| 868 int success = inflateInit(decompressor.get()); | 881 int success = inflateInit(decompressor.get()); |
| 869 if (success != Z_OK) { | 882 if (success != Z_OK) { |
| 870 LOG(WARNING) << "inflateInit failure: " << success; | 883 LOG(WARNING) << "inflateInit failure: " << success; |
| 871 return NULL; | 884 return NULL; |
| 872 } | 885 } |
| 873 return stream_decompressors_[stream_id] = decompressor.release(); | 886 return stream_decompressors_[stream_id] = decompressor.release(); |
| 874 } | 887 } |
| 875 | 888 |
| 876 bool SpdyFramer::GetFrameBoundaries(const SpdyFrame& frame, | |
| 877 int* payload_length, | |
| 878 int* header_length, | |
| 879 const char** payload) const { | |
| 880 size_t frame_size; | |
| 881 if (frame.is_control_frame()) { | |
| 882 const SpdyControlFrame& control_frame = | |
| 883 reinterpret_cast<const SpdyControlFrame&>(frame); | |
| 884 switch (control_frame.type()) { | |
| 885 case SYN_STREAM: | |
| 886 { | |
| 887 const SpdySynStreamControlFrame& syn_frame = | |
| 888 reinterpret_cast<const SpdySynStreamControlFrame&>(frame); | |
| 889 frame_size = SpdySynStreamControlFrame::size(); | |
| 890 *payload_length = syn_frame.header_block_len(); | |
| 891 *header_length = frame_size; | |
| 892 *payload = frame.data() + *header_length; | |
| 893 } | |
| 894 break; | |
| 895 case SYN_REPLY: | |
| 896 { | |
| 897 const SpdySynReplyControlFrame& syn_frame = | |
| 898 reinterpret_cast<const SpdySynReplyControlFrame&>(frame); | |
| 899 frame_size = SpdySynReplyControlFrame::size(); | |
| 900 *payload_length = syn_frame.header_block_len(); | |
| 901 *header_length = frame_size; | |
| 902 *payload = frame.data() + *header_length; | |
| 903 } | |
| 904 break; | |
| 905 case HEADERS: | |
| 906 { | |
| 907 const SpdyHeadersControlFrame& headers_frame = | |
| 908 reinterpret_cast<const SpdyHeadersControlFrame&>(frame); | |
| 909 frame_size = SpdyHeadersControlFrame::size(); | |
| 910 *payload_length = headers_frame.header_block_len(); | |
| 911 *header_length = frame_size; | |
| 912 *payload = frame.data() + *header_length; | |
| 913 } | |
| 914 break; | |
| 915 default: | |
| 916 // TODO(mbelshe): set an error? | |
| 917 return false; // We can't compress this frame! | |
| 918 } | |
| 919 } else { | |
| 920 frame_size = SpdyFrame::size(); | |
| 921 *header_length = frame_size; | |
| 922 *payload_length = frame.length(); | |
| 923 *payload = frame.data() + SpdyFrame::size(); | |
| 924 } | |
| 925 return true; | |
| 926 } | |
| 927 | |
| 928 SpdyFrame* SpdyFramer::CompressFrame(const SpdyFrame& frame) { | |
| 929 if (frame.is_control_frame()) { | |
| 930 return CompressControlFrame( | |
| 931 reinterpret_cast<const SpdyControlFrame&>(frame)); | |
| 932 } | |
| 933 return CompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame)); | |
| 934 } | |
| 935 | |
| 936 SpdyFrame* SpdyFramer::DecompressFrame(const SpdyFrame& frame) { | |
| 937 if (frame.is_control_frame()) { | |
| 938 return DecompressControlFrame( | |
| 939 reinterpret_cast<const SpdyControlFrame&>(frame)); | |
| 940 } | |
| 941 return DecompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame)); | |
| 942 } | |
| 943 | |
| 944 SpdyControlFrame* SpdyFramer::CompressControlFrame( | 889 SpdyControlFrame* SpdyFramer::CompressControlFrame( |
| 945 const SpdyControlFrame& frame) { | 890 const SpdyControlFrame& frame) { |
| 946 z_stream* compressor = GetHeaderCompressor(); | 891 z_stream* compressor = GetHeaderCompressor(); |
| 947 if (!compressor) | 892 if (!compressor) |
| 948 return NULL; | 893 return NULL; |
| 949 return reinterpret_cast<SpdyControlFrame*>( | 894 return reinterpret_cast<SpdyControlFrame*>( |
| 950 CompressFrameWithZStream(frame, compressor)); | 895 CompressFrameWithZStream(frame, compressor)); |
| 951 } | 896 } |
| 952 | 897 |
| 898 SpdyDataFrame* SpdyFramer::CompressDataFrame(const SpdyDataFrame& frame) { |
| 899 z_stream* compressor = GetStreamCompressor(frame.stream_id()); |
| 900 if (!compressor) |
| 901 return NULL; |
| 902 return reinterpret_cast<SpdyDataFrame*>( |
| 903 CompressFrameWithZStream(frame, compressor)); |
| 904 } |
| 905 |
| 953 SpdyControlFrame* SpdyFramer::DecompressControlFrame( | 906 SpdyControlFrame* SpdyFramer::DecompressControlFrame( |
| 954 const SpdyControlFrame& frame) { | 907 const SpdyControlFrame& frame) { |
| 955 z_stream* decompressor = GetHeaderDecompressor(); | 908 z_stream* decompressor = GetHeaderDecompressor(); |
| 956 if (!decompressor) | 909 if (!decompressor) |
| 957 return NULL; | 910 return NULL; |
| 958 return reinterpret_cast<SpdyControlFrame*>( | 911 return reinterpret_cast<SpdyControlFrame*>( |
| 959 DecompressFrameWithZStream(frame, decompressor)); | 912 DecompressFrameWithZStream(frame, decompressor)); |
| 960 } | 913 } |
| 961 | 914 |
| 962 SpdyDataFrame* SpdyFramer::CompressDataFrame(const SpdyDataFrame& frame) { | |
| 963 z_stream* compressor = GetStreamCompressor(frame.stream_id()); | |
| 964 if (!compressor) | |
| 965 return NULL; | |
| 966 return reinterpret_cast<SpdyDataFrame*>( | |
| 967 CompressFrameWithZStream(frame, compressor)); | |
| 968 } | |
| 969 | |
| 970 SpdyDataFrame* SpdyFramer::DecompressDataFrame(const SpdyDataFrame& frame) { | 915 SpdyDataFrame* SpdyFramer::DecompressDataFrame(const SpdyDataFrame& frame) { |
| 971 z_stream* decompressor = GetStreamDecompressor(frame.stream_id()); | 916 z_stream* decompressor = GetStreamDecompressor(frame.stream_id()); |
| 972 if (!decompressor) | 917 if (!decompressor) |
| 973 return NULL; | 918 return NULL; |
| 974 return reinterpret_cast<SpdyDataFrame*>( | 919 return reinterpret_cast<SpdyDataFrame*>( |
| 975 DecompressFrameWithZStream(frame, decompressor)); | 920 DecompressFrameWithZStream(frame, decompressor)); |
| 976 } | 921 } |
| 977 | 922 |
| 978 SpdyFrame* SpdyFramer::CompressFrameWithZStream(const SpdyFrame& frame, | 923 SpdyFrame* SpdyFramer::CompressFrameWithZStream(const SpdyFrame& frame, |
| 979 z_stream* compressor) { | 924 z_stream* compressor) { |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1138 it = stream_decompressors_.begin(); | 1083 it = stream_decompressors_.begin(); |
| 1139 while (it != stream_decompressors_.end()) { | 1084 while (it != stream_decompressors_.end()) { |
| 1140 z_stream* decompressor = it->second; | 1085 z_stream* decompressor = it->second; |
| 1141 inflateEnd(decompressor); | 1086 inflateEnd(decompressor); |
| 1142 delete decompressor; | 1087 delete decompressor; |
| 1143 ++it; | 1088 ++it; |
| 1144 } | 1089 } |
| 1145 stream_decompressors_.clear(); | 1090 stream_decompressors_.clear(); |
| 1146 } | 1091 } |
| 1147 | 1092 |
| 1148 SpdyFrame* SpdyFramer::DuplicateFrame(const SpdyFrame& frame) { | 1093 size_t SpdyFramer::BytesSafeToRead() const { |
| 1149 int size = SpdyFrame::size() + frame.length(); | 1094 switch (state_) { |
| 1150 SpdyFrame* new_frame = new SpdyFrame(size); | 1095 case SPDY_ERROR: |
| 1151 memcpy(new_frame->data(), frame.data(), size); | 1096 case SPDY_DONE: |
| 1152 return new_frame; | 1097 case SPDY_AUTO_RESET: |
| 1098 case SPDY_RESET: |
| 1099 return 0; |
| 1100 case SPDY_READING_COMMON_HEADER: |
| 1101 DCHECK_LT(current_frame_len_, SpdyFrame::size()); |
| 1102 return SpdyFrame::size() - current_frame_len_; |
| 1103 case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER: |
| 1104 return 0; |
| 1105 case SPDY_CONTROL_FRAME_PAYLOAD: |
| 1106 case SPDY_IGNORE_REMAINING_PAYLOAD: |
| 1107 case SPDY_FORWARD_STREAM_FRAME: |
| 1108 return remaining_payload_; |
| 1109 } |
| 1110 // We should never get to here. |
| 1111 return 0; |
| 1153 } | 1112 } |
| 1154 | 1113 |
| 1155 bool SpdyFramer::IsCompressible(const SpdyFrame& frame) const { | 1114 void SpdyFramer::set_error(SpdyError error) { |
| 1156 // The important frames to compress are those which contain large | 1115 DCHECK(visitor_); |
| 1157 // amounts of compressible data - namely the headers in the SYN_STREAM | 1116 error_code_ = error; |
| 1158 // and SYN_REPLY. | 1117 CHANGE_STATE(SPDY_ERROR); |
| 1159 // TODO(mbelshe): Reconcile this with the spec when the spec is | 1118 visitor_->OnError(this); |
| 1160 // explicit about which frames compress and which do not. | 1119 } |
| 1120 |
| 1121 void SpdyFramer::ExpandControlFrameBuffer(size_t size) { |
| 1122 size_t alloc_size = size + SpdyFrame::size(); |
| 1123 DCHECK_LT(alloc_size, kControlFrameBufferMaxSize); |
| 1124 if (alloc_size <= current_frame_capacity_) |
| 1125 return; |
| 1126 char* new_buffer = new char[alloc_size]; |
| 1127 memcpy(new_buffer, current_frame_buffer_, current_frame_len_); |
| 1128 delete [] current_frame_buffer_; |
| 1129 current_frame_capacity_ = alloc_size; |
| 1130 current_frame_buffer_ = new_buffer; |
| 1131 } |
| 1132 |
| 1133 bool SpdyFramer::GetFrameBoundaries(const SpdyFrame& frame, |
| 1134 int* payload_length, |
| 1135 int* header_length, |
| 1136 const char** payload) const { |
| 1137 size_t frame_size; |
| 1161 if (frame.is_control_frame()) { | 1138 if (frame.is_control_frame()) { |
| 1162 const SpdyControlFrame& control_frame = | 1139 const SpdyControlFrame& control_frame = |
| 1163 reinterpret_cast<const SpdyControlFrame&>(frame); | 1140 reinterpret_cast<const SpdyControlFrame&>(frame); |
| 1164 return control_frame.type() == SYN_STREAM || | 1141 switch (control_frame.type()) { |
| 1165 control_frame.type() == SYN_REPLY; | 1142 case SYN_STREAM: |
| 1143 { |
| 1144 const SpdySynStreamControlFrame& syn_frame = |
| 1145 reinterpret_cast<const SpdySynStreamControlFrame&>(frame); |
| 1146 frame_size = SpdySynStreamControlFrame::size(); |
| 1147 *payload_length = syn_frame.header_block_len(); |
| 1148 *header_length = frame_size; |
| 1149 *payload = frame.data() + *header_length; |
| 1150 } |
| 1151 break; |
| 1152 case SYN_REPLY: |
| 1153 { |
| 1154 const SpdySynReplyControlFrame& syn_frame = |
| 1155 reinterpret_cast<const SpdySynReplyControlFrame&>(frame); |
| 1156 frame_size = SpdySynReplyControlFrame::size(); |
| 1157 *payload_length = syn_frame.header_block_len(); |
| 1158 *header_length = frame_size; |
| 1159 *payload = frame.data() + *header_length; |
| 1160 } |
| 1161 break; |
| 1162 case HEADERS: |
| 1163 { |
| 1164 const SpdyHeadersControlFrame& headers_frame = |
| 1165 reinterpret_cast<const SpdyHeadersControlFrame&>(frame); |
| 1166 frame_size = SpdyHeadersControlFrame::size(); |
| 1167 *payload_length = headers_frame.header_block_len(); |
| 1168 *header_length = frame_size; |
| 1169 *payload = frame.data() + *header_length; |
| 1170 } |
| 1171 break; |
| 1172 default: |
| 1173 // TODO(mbelshe): set an error? |
| 1174 return false; // We can't compress this frame! |
| 1175 } |
| 1176 } else { |
| 1177 frame_size = SpdyFrame::size(); |
| 1178 *header_length = frame_size; |
| 1179 *payload_length = frame.length(); |
| 1180 *payload = frame.data() + SpdyFrame::size(); |
| 1166 } | 1181 } |
| 1167 | 1182 return true; |
| 1168 const SpdyDataFrame& data_frame = | |
| 1169 reinterpret_cast<const SpdyDataFrame&>(frame); | |
| 1170 return (data_frame.flags() & DATA_FLAG_COMPRESSED) != 0; | |
| 1171 } | |
| 1172 | |
| 1173 void SpdyFramer::set_enable_compression(bool value) { | |
| 1174 enable_compression_ = value; | |
| 1175 } | |
| 1176 | |
| 1177 void SpdyFramer::set_enable_compression_default(bool value) { | |
| 1178 compression_default_ = value; | |
| 1179 } | 1183 } |
| 1180 | 1184 |
| 1181 } // namespace spdy | 1185 } // namespace spdy |
| OLD | NEW |