OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
12 #include "base/metrics/stats_counters.h" | 12 #include "base/metrics/stats_counters.h" |
13 #include "base/third_party/valgrind/memcheck.h" | 13 #include "base/third_party/valgrind/memcheck.h" |
14 #include "net/spdy/spdy_frame_builder.h" | 14 #include "net/spdy/spdy_frame_builder.h" |
15 #include "net/spdy/spdy_frame_reader.h" | |
15 #include "net/spdy/spdy_bitmasks.h" | 16 #include "net/spdy/spdy_bitmasks.h" |
16 | 17 |
17 #if defined(USE_SYSTEM_ZLIB) | 18 #if defined(USE_SYSTEM_ZLIB) |
18 #include <zlib.h> | 19 #include <zlib.h> |
19 #else | 20 #else |
20 #include "third_party/zlib/zlib.h" | 21 #include "third_party/zlib/zlib.h" |
21 #endif | 22 #endif |
22 | 23 |
23 using std::vector; | 24 using std::vector; |
24 | 25 |
25 namespace spdy { | 26 namespace spdy { |
26 | 27 |
27 SpdyCredential::SpdyCredential() : slot(0) { } | |
28 SpdyCredential::~SpdyCredential() { } | |
29 | |
30 // Compute the id of our dictionary so that we know we're using the | 28 // Compute the id of our dictionary so that we know we're using the |
31 // right one when asked for it. | 29 // right one when asked for it. |
32 uLong CalculateDictionaryId() { | 30 uLong CalculateDictionaryId(const char* dictionary, |
31 const size_t dictionary_size) { | |
33 uLong initial_value = adler32(0L, Z_NULL, 0); | 32 uLong initial_value = adler32(0L, Z_NULL, 0); |
34 return adler32(initial_value, | 33 return adler32(initial_value, |
35 reinterpret_cast<const Bytef*>(SpdyFramer::kDictionary), | 34 reinterpret_cast<const Bytef*>(dictionary), |
36 SpdyFramer::kDictionarySize); | 35 dictionary_size); |
37 } | 36 } |
38 | 37 |
39 // Adler ID for the SPDY header compressor dictionary. | 38 // Adler ID for the SPDY header compressor dictionaries. |
40 const uLong kDictionaryId = CalculateDictionaryId(); | 39 const uLong kV2DictionaryId = CalculateDictionaryId(kV2Dictionary, |
41 | 40 kV2DictionarySize); |
42 int DecompressHeaderBlockInZStream(z_stream* decompressor) { | 41 const uLong kV3DictionaryId = CalculateDictionaryId(kV3Dictionary, |
43 int rv = inflate(decompressor, Z_SYNC_FLUSH); | 42 kV3DictionarySize); |
44 if (rv == Z_NEED_DICT) { | |
45 // Need to try again with the right dictionary. | |
46 if (decompressor->adler == kDictionaryId) { | |
47 rv = inflateSetDictionary(decompressor, | |
48 (const Bytef*)SpdyFramer::kDictionary, | |
49 SpdyFramer::kDictionarySize); | |
50 if (rv == Z_OK) | |
51 rv = inflate(decompressor, Z_SYNC_FLUSH); | |
52 } | |
53 } | |
54 return rv; | |
55 } | |
56 | |
57 // Retrieve serialized length of SpdyHeaderBlock. | |
58 size_t GetSerializedLength(const SpdyHeaderBlock* headers) { | |
59 size_t total_length = SpdyControlFrame::kNumNameValuePairsSize; | |
60 SpdyHeaderBlock::const_iterator it; | |
61 for (it = headers->begin(); it != headers->end(); ++it) { | |
62 // We add space for the length of the name and the length of the value as | |
63 // well as the length of the name and the length of the value. | |
64 total_length += SpdyControlFrame::kLengthOfNameSize + | |
65 it->first.size() + | |
66 SpdyControlFrame::kLengthOfValueSize + | |
67 it->second.size(); | |
68 } | |
69 return total_length; | |
70 } | |
71 | |
72 // Serializes a SpdyHeaderBlock. | |
73 void WriteHeaderBlock(SpdyFrameBuilder* frame, const SpdyHeaderBlock* headers) { | |
74 frame->WriteUInt16(headers->size()); // Number of headers. | |
75 SpdyHeaderBlock::const_iterator it; | |
76 for (it = headers->begin(); it != headers->end(); ++it) { | |
77 bool wrote_header; | |
78 wrote_header = frame->WriteString(it->first); | |
79 wrote_header &= frame->WriteString(it->second); | |
80 DCHECK(wrote_header); | |
81 } | |
82 } | |
83 | 43 |
84 // Creates a FlagsAndLength. | 44 // Creates a FlagsAndLength. |
85 FlagsAndLength CreateFlagsAndLength(SpdyControlFlags flags, size_t length) { | 45 FlagsAndLength CreateFlagsAndLength(SpdyControlFlags flags, size_t length) { |
86 DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask)); | 46 DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask)); |
87 FlagsAndLength flags_length; | 47 FlagsAndLength flags_length; |
88 flags_length.length_ = htonl(static_cast<uint32>(length)); | 48 flags_length.length_ = htonl(static_cast<uint32>(length)); |
89 DCHECK_EQ(0, flags & ~kControlFlagsMask); | 49 DCHECK_EQ(0, flags & ~kControlFlagsMask); |
90 flags_length.flags_[0] = flags; | 50 flags_length.flags_[0] = flags; |
91 return flags_length; | 51 return flags_length; |
92 } | 52 } |
93 | 53 |
94 // By default is compression on or off. | 54 // By default is compression on or off. |
95 bool SpdyFramer::compression_default_ = true; | 55 bool SpdyFramer::compression_default_ = true; |
96 | 56 |
97 // The initial size of the control frame buffer; this is used internally | 57 // The initial size of the control frame buffer; this is used internally |
98 // as we parse through control frames. (It is exposed here for unit test | 58 // as we parse through control frames. (It is exposed here for unit test |
99 // purposes.) | 59 // purposes.) |
100 size_t SpdyFramer::kControlFrameBufferInitialSize = 32 * 1024; | 60 size_t SpdyFramer::kControlFrameBufferInitialSize = 32 * 1024; |
101 | 61 |
102 // The maximum size of the control frame buffer that we support. | 62 // The maximum size of the control frame buffer that we support. |
103 // TODO(mbelshe): We should make this stream-based so there are no limits. | 63 // TODO(mbelshe): We should make this stream-based so there are no limits. |
104 size_t SpdyFramer::kControlFrameBufferMaxSize = 64 * 1024; | 64 size_t SpdyFramer::kControlFrameBufferMaxSize = 64 * 1024; |
105 | 65 |
106 int SpdyFramer::spdy_version_ = kSpdyProtocolVersion; | 66 // The initial size of the control frame buffer when compression is disabled. |
67 // This exists because we don't do stream (de)compressed control frame data to | |
68 // our visitor; we instead buffer the entirety of the control frame and then | |
69 // decompress in one fell swoop. | |
70 // Since this is only used for control frame headers, the maximum control | |
71 // frame header size (18B) is sufficient; all remaining control frame data is | |
72 // streamed to the visitor. | |
73 // In addition to the maximum control frame header size, we account for any | |
74 // LOAS checksumming (16B) that may occur in the VTL case. | |
75 size_t SpdyFramer::kUncompressedControlFrameBufferInitialSize = 18 + 16; | |
Ryan Hamilton
2012/03/10 03:23:02
Hm. Ok, I guess this explains the value, but we d
ramant (doing other things)
2012/03/10 19:45:29
I think it could get used in unittests (when in so
Ryan Hamilton
2012/03/11 15:52:02
Let's find out from hkhalil. The way I read the c
| |
107 | 76 |
108 const SpdyStreamId SpdyFramer::kInvalidStream = -1; | 77 const SpdyStreamId SpdyFramer::kInvalidStream = -1; |
109 const size_t SpdyFramer::kHeaderDataChunkMaxSize = 1024; | 78 const size_t SpdyFramer::kHeaderDataChunkMaxSize = 1024; |
110 | 79 |
80 | |
111 #ifdef DEBUG_SPDY_STATE_CHANGES | 81 #ifdef DEBUG_SPDY_STATE_CHANGES |
112 #define CHANGE_STATE(newstate) \ | 82 #define CHANGE_STATE(newstate) \ |
113 { \ | 83 { \ |
114 do { \ | 84 do { \ |
115 LOG(INFO) << "Changing state from: " \ | 85 LOG(INFO) << "Changing state from: " \ |
116 << StateToString(state_) \ | 86 << StateToString(state_) \ |
117 << " to " << StateToString(newstate) << "\n"; \ | 87 << " to " << StateToString(newstate) << "\n"; \ |
118 state_ = newstate; \ | 88 state_ = newstate; \ |
119 } while (false); \ | 89 } while (false); \ |
120 } | 90 } |
121 #else | 91 #else |
122 #define CHANGE_STATE(newstate) (state_ = newstate) | 92 #define CHANGE_STATE(newstate) (state_ = newstate) |
123 #endif | 93 #endif |
124 | 94 |
125 SpdyFramer::SpdyFramer() | 95 SettingsFlagsAndId SettingsFlagsAndId::FromWireFormat(int version, |
96 uint32 wire) { | |
97 if (version < 3) { | |
98 ConvertFlagsAndIdForSpdy2(&wire); | |
99 } | |
100 return SettingsFlagsAndId(ntohl(wire) >> 24, ntohl(wire) & 0x00ffffff); | |
101 } | |
102 | |
103 SettingsFlagsAndId::SettingsFlagsAndId(uint8 flags, uint32 id) | |
104 : flags_(flags), id_(id & 0x00ffffff) { | |
105 DCHECK_GT(static_cast<uint32>(1 << 24), id); | |
106 } | |
107 | |
108 uint32 SettingsFlagsAndId::GetWireFormat(int version) const { | |
109 uint32 wire = htonl(id_ & 0x00ffffff) | htonl(flags_ << 24); | |
110 if (version < 3) { | |
111 ConvertFlagsAndIdForSpdy2(&wire); | |
112 } | |
113 return wire; | |
114 } | |
115 | |
116 // SPDY 2 had a bug in it with respect to byte ordering of id/flags field. | |
117 // This method is used to preserve buggy behavior and works on both | |
118 // little-endian and big-endian hosts. | |
119 // This method is also bidirectional (can be used to translate SPDY 2 to SPDY 3 | |
120 // as well as vice versa). | |
121 void SettingsFlagsAndId::ConvertFlagsAndIdForSpdy2(uint32* val) { | |
122 uint8* wire_array = reinterpret_cast<uint8*>(val); | |
123 std::swap(wire_array[0], wire_array[3]); | |
124 std::swap(wire_array[1], wire_array[2]); | |
125 } | |
126 | |
127 SpdyCredential::SpdyCredential() : slot(0) { } | |
128 SpdyCredential::~SpdyCredential() { } | |
129 | |
130 SpdyFramer::SpdyFramer(int version) | |
126 : state_(SPDY_RESET), | 131 : state_(SPDY_RESET), |
127 error_code_(SPDY_NO_ERROR), | 132 error_code_(SPDY_NO_ERROR), |
128 remaining_data_(0), | 133 remaining_data_(0), |
129 remaining_control_payload_(0), | 134 remaining_control_payload_(0), |
130 remaining_control_header_(0), | 135 remaining_control_header_(0), |
131 current_frame_buffer_(NULL), | 136 current_frame_buffer_(NULL), |
132 current_frame_len_(0), | 137 current_frame_len_(0), |
133 current_frame_capacity_(0), | 138 current_frame_capacity_(0), |
134 validate_control_frame_sizes_(true), | 139 validate_control_frame_sizes_(true), |
135 enable_compression_(compression_default_), | 140 enable_compression_(compression_default_), |
136 visitor_(NULL), | 141 visitor_(NULL), |
137 display_protocol_("SPDY") { | 142 display_protocol_("SPDY"), |
143 spdy_version_(version), | |
144 syn_frame_processed_(false), | |
145 probable_http_response_(false) { | |
146 DCHECK_GE(3, version); | |
147 DCHECK_LE(2, version); | |
138 } | 148 } |
139 | 149 |
140 SpdyFramer::~SpdyFramer() { | 150 SpdyFramer::~SpdyFramer() { |
141 if (header_compressor_.get()) { | 151 if (header_compressor_.get()) { |
142 deflateEnd(header_compressor_.get()); | 152 deflateEnd(header_compressor_.get()); |
143 } | 153 } |
144 if (header_decompressor_.get()) { | 154 if (header_decompressor_.get()) { |
145 inflateEnd(header_decompressor_.get()); | 155 inflateEnd(header_decompressor_.get()); |
146 } | 156 } |
147 CleanupStreamCompressorsAndDecompressors(); | 157 CleanupStreamCompressorsAndDecompressors(); |
148 delete [] current_frame_buffer_; | 158 delete [] current_frame_buffer_; |
149 } | 159 } |
150 | 160 |
151 void SpdyFramer::Reset() { | 161 void SpdyFramer::Reset() { |
152 state_ = SPDY_RESET; | 162 state_ = SPDY_RESET; |
153 error_code_ = SPDY_NO_ERROR; | 163 error_code_ = SPDY_NO_ERROR; |
154 remaining_data_ = 0; | 164 remaining_data_ = 0; |
155 remaining_control_payload_ = 0; | 165 remaining_control_payload_ = 0; |
156 remaining_control_header_ = 0; | 166 remaining_control_header_ = 0; |
157 current_frame_len_ = 0; | 167 current_frame_len_ = 0; |
168 settings_scratch_.Reset(); | |
158 // TODO(hkhalil): Remove once initial_size == kControlFrameBufferInitialSize. | 169 // TODO(hkhalil): Remove once initial_size == kControlFrameBufferInitialSize. |
159 size_t initial_size = kControlFrameBufferInitialSize; | 170 size_t initial_size = kControlFrameBufferInitialSize; |
160 if (!enable_compression_) { | 171 if (!enable_compression_) { |
161 initial_size = kUncompressedControlFrameBufferInitialSize; | 172 initial_size = kUncompressedControlFrameBufferInitialSize; |
162 } | 173 } |
163 if (current_frame_capacity_ != initial_size) { | 174 if (current_frame_capacity_ != initial_size) { |
164 delete [] current_frame_buffer_; | 175 delete [] current_frame_buffer_; |
165 current_frame_buffer_ = 0; | 176 current_frame_buffer_ = 0; |
166 current_frame_capacity_ = 0; | 177 current_frame_capacity_ = 0; |
167 ExpandControlFrameBuffer(initial_size); | 178 ExpandControlFrameBuffer(initial_size); |
(...skipping 17 matching lines...) Expand all Loading... | |
185 case SPDY_IGNORE_REMAINING_PAYLOAD: | 196 case SPDY_IGNORE_REMAINING_PAYLOAD: |
186 return "IGNORE_REMAINING_PAYLOAD"; | 197 return "IGNORE_REMAINING_PAYLOAD"; |
187 case SPDY_FORWARD_STREAM_FRAME: | 198 case SPDY_FORWARD_STREAM_FRAME: |
188 return "FORWARD_STREAM_FRAME"; | 199 return "FORWARD_STREAM_FRAME"; |
189 case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK: | 200 case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK: |
190 return "SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK"; | 201 return "SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK"; |
191 case SPDY_CONTROL_FRAME_HEADER_BLOCK: | 202 case SPDY_CONTROL_FRAME_HEADER_BLOCK: |
192 return "SPDY_CONTROL_FRAME_HEADER_BLOCK"; | 203 return "SPDY_CONTROL_FRAME_HEADER_BLOCK"; |
193 case SPDY_CREDENTIAL_FRAME_PAYLOAD: | 204 case SPDY_CREDENTIAL_FRAME_PAYLOAD: |
194 return "SPDY_CREDENTIAL_FRAME_PAYLOAD"; | 205 return "SPDY_CREDENTIAL_FRAME_PAYLOAD"; |
206 case SPDY_SETTINGS_FRAME_PAYLOAD: | |
207 return "SPDY_SETTINGS_FRAME_PAYLOAD"; | |
195 } | 208 } |
196 return "UNKNOWN_STATE"; | 209 return "UNKNOWN_STATE"; |
197 } | 210 } |
198 | 211 |
199 void SpdyFramer::set_error(SpdyError error) { | 212 void SpdyFramer::set_error(SpdyError error) { |
200 DCHECK(visitor_); | 213 DCHECK(visitor_); |
201 error_code_ = error; | 214 error_code_ = error; |
202 CHANGE_STATE(SPDY_ERROR); | 215 CHANGE_STATE(SPDY_ERROR); |
203 visitor_->OnError(this); | 216 visitor_->OnError(this); |
204 } | 217 } |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
297 continue; | 310 continue; |
298 } | 311 } |
299 | 312 |
300 case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK: { | 313 case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK: { |
301 // Control frames that contain header blocks (SYN_STREAM, SYN_REPLY, | 314 // Control frames that contain header blocks (SYN_STREAM, SYN_REPLY, |
302 // HEADERS) take a different path through the state machine - they | 315 // HEADERS) take a different path through the state machine - they |
303 // will go: | 316 // will go: |
304 // 1. SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK | 317 // 1. SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK |
305 // 2. SPDY_CONTROL_FRAME_HEADER_BLOCK | 318 // 2. SPDY_CONTROL_FRAME_HEADER_BLOCK |
306 // | 319 // |
320 // SETTINGS frames take a slightly modified route: | |
321 // 1. SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK | |
322 // 2. SPDY_SETTINGS_FRAME_PAYLOAD | |
323 // | |
307 // All other control frames will use the alternate route directly to | 324 // All other control frames will use the alternate route directly to |
308 // SPDY_CONTROL_FRAME_PAYLOAD | 325 // SPDY_CONTROL_FRAME_PAYLOAD |
309 int bytes_read = ProcessControlFrameBeforeHeaderBlock(data, len); | 326 int bytes_read = ProcessControlFrameBeforeHeaderBlock(data, len); |
310 len -= bytes_read; | 327 len -= bytes_read; |
311 data += bytes_read; | 328 data += bytes_read; |
312 continue; | 329 continue; |
313 } | 330 } |
314 | 331 |
332 case SPDY_SETTINGS_FRAME_PAYLOAD: { | |
333 int bytes_read = ProcessSettingsFramePayload(data, len); | |
334 len -= bytes_read; | |
335 data += bytes_read; | |
336 continue; | |
337 } | |
338 | |
315 case SPDY_CONTROL_FRAME_HEADER_BLOCK: { | 339 case SPDY_CONTROL_FRAME_HEADER_BLOCK: { |
316 int bytes_read = ProcessControlFrameHeaderBlock(data, len); | 340 int bytes_read = ProcessControlFrameHeaderBlock(data, len); |
317 len -= bytes_read; | 341 len -= bytes_read; |
318 data += bytes_read; | 342 data += bytes_read; |
319 continue; | 343 continue; |
320 } | 344 } |
321 | 345 |
322 case SPDY_CREDENTIAL_FRAME_PAYLOAD: { | 346 case SPDY_CREDENTIAL_FRAME_PAYLOAD: { |
323 size_t bytes_read = ProcessCredentialFramePayload(data, len); | 347 size_t bytes_read = ProcessCredentialFramePayload(data, len); |
324 len -= bytes_read; | 348 len -= bytes_read; |
325 data += bytes_read; | 349 data += bytes_read; |
326 continue; | |
327 } | 350 } |
328 | 351 |
329 case SPDY_CONTROL_FRAME_PAYLOAD: { | 352 case SPDY_CONTROL_FRAME_PAYLOAD: { |
330 size_t bytes_read = ProcessControlFramePayload(data, len); | 353 size_t bytes_read = ProcessControlFramePayload(data, len); |
331 len -= bytes_read; | 354 len -= bytes_read; |
332 data += bytes_read; | 355 data += bytes_read; |
333 } | 356 } |
334 // intentional fallthrough | 357 // intentional fallthrough |
335 case SPDY_IGNORE_REMAINING_PAYLOAD: | 358 case SPDY_IGNORE_REMAINING_PAYLOAD: |
336 // control frame has too-large payload | 359 // control frame has too-large payload |
337 // intentional fallthrough | 360 // intentional fallthrough |
338 case SPDY_FORWARD_STREAM_FRAME: { | 361 case SPDY_FORWARD_STREAM_FRAME: { |
339 size_t bytes_read = ProcessDataFramePayload(data, len); | 362 size_t bytes_read = ProcessDataFramePayload(data, len); |
340 len -= bytes_read; | 363 len -= bytes_read; |
341 data += bytes_read; | 364 data += bytes_read; |
342 continue; | 365 continue; |
343 } | 366 } |
344 default: | 367 default: |
368 LOG(ERROR) << "Invalid value for " << display_protocol_ | |
369 << " framer state: " << state_; | |
345 // This ensures that we don't infinite-loop if state_ gets an | 370 // This ensures that we don't infinite-loop if state_ gets an |
346 // invalid value somehow, such as due to a SpdyFramer getting deleted | 371 // invalid value somehow, such as due to a SpdyFramer getting deleted |
347 // from a callback it calls. | 372 // from a callback it calls. |
348 goto bottom; | 373 goto bottom; |
349 } | 374 } |
350 } | 375 } |
351 bottom: | 376 bottom: |
352 return original_len - len; | 377 return original_len - len; |
353 } | 378 } |
354 | 379 |
(...skipping 21 matching lines...) Expand all Loading... | |
376 visitor_->OnDataFrameHeader(&data_frame); | 401 visitor_->OnDataFrameHeader(&data_frame); |
377 if (current_frame.flags() & DATA_FLAG_FIN) { | 402 if (current_frame.flags() & DATA_FLAG_FIN) { |
378 visitor_->OnStreamFrameData(data_frame.stream_id(), NULL, 0); | 403 visitor_->OnStreamFrameData(data_frame.stream_id(), NULL, 0); |
379 } | 404 } |
380 CHANGE_STATE(SPDY_AUTO_RESET); | 405 CHANGE_STATE(SPDY_AUTO_RESET); |
381 } else { | 406 } else { |
382 remaining_data_ = current_frame.length(); | 407 remaining_data_ = current_frame.length(); |
383 | 408 |
384 // This is just a sanity check for help debugging early frame errors. | 409 // This is just a sanity check for help debugging early frame errors. |
385 if (remaining_data_ > 1000000u) { | 410 if (remaining_data_ > 1000000u) { |
386 LOG(WARNING) << "Unexpectedly large frame. " << display_protocol_ | 411 // The strncmp for 5 is safe because we only hit this point if we |
387 << " session is likely corrupt."; | 412 // have SpdyFrame::kHeaderSize (8) bytes |
413 if (!syn_frame_processed_ && | |
414 strncmp(current_frame_buffer_, "HTTP/", 5) == 0) { | |
415 LOG(WARNING) << "Unexpected HTTP response to spdy request"; | |
416 probable_http_response_ = true; | |
417 } else { | |
418 LOG(WARNING) << "Unexpectedly large frame. " << display_protocol_ | |
419 << " session is likely corrupt."; | |
420 } | |
388 } | 421 } |
389 | 422 |
390 // if we're here, then we have the common header all received. | 423 // if we're here, then we have the common header all received. |
391 if (!current_frame.is_control_frame()) { | 424 if (!current_frame.is_control_frame()) { |
392 SpdyDataFrame data_frame(current_frame_buffer_, false); | 425 SpdyDataFrame data_frame(current_frame_buffer_, false); |
393 visitor_->OnDataFrameHeader(&data_frame); | 426 visitor_->OnDataFrameHeader(&data_frame); |
394 CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME); | 427 CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME); |
395 } else { | 428 } else { |
396 ProcessControlFrameHeader(); | 429 ProcessControlFrameHeader(); |
397 } | 430 } |
398 } | 431 } |
399 return original_len - len; | 432 return original_len - len; |
400 } | 433 } |
401 | 434 |
402 void SpdyFramer::ProcessControlFrameHeader() { | 435 void SpdyFramer::ProcessControlFrameHeader() { |
403 DCHECK_EQ(SPDY_NO_ERROR, error_code_); | 436 DCHECK_EQ(SPDY_NO_ERROR, error_code_); |
404 DCHECK_LE(static_cast<size_t>(SpdyFrame::kHeaderSize), current_frame_len_); | 437 DCHECK_LE(static_cast<size_t>(SpdyFrame::kHeaderSize), current_frame_len_); |
405 SpdyControlFrame current_control_frame(current_frame_buffer_, false); | 438 SpdyControlFrame current_control_frame(current_frame_buffer_, false); |
406 | 439 |
407 // We check version before we check validity: version can never be 'invalid', | 440 // We check version before we check validity: version can never be 'invalid', |
408 // it can only be unsupported. | 441 // it can only be unsupported. |
409 if (current_control_frame.version() != spdy_version_) { | 442 if (current_control_frame.version() != spdy_version_) { |
443 DLOG(INFO) << "Unsupported SPDY version " << current_control_frame.version() | |
444 << " (expected " << spdy_version_ << ")"; | |
410 set_error(SPDY_UNSUPPORTED_VERSION); | 445 set_error(SPDY_UNSUPPORTED_VERSION); |
411 return; | 446 return; |
412 } | 447 } |
413 | 448 |
414 // Next up, check to see if we have valid data. This should be after version | 449 // Next up, check to see if we have valid data. This should be after version |
415 // checking (otherwise if the the type were out of bounds due to a version | 450 // checking (otherwise if the the type were out of bounds due to a version |
416 // upgrade we would misclassify the error) and before checking the type | 451 // upgrade we would misclassify the error) and before checking the type |
417 // (type can definitely be out of bounds) | 452 // (type can definitely be out of bounds) |
418 if (!current_control_frame.AppearsToBeAValidControlFrame()) { | 453 if (!current_control_frame.AppearsToBeAValidControlFrame()) { |
419 set_error(SPDY_INVALID_CONTROL_FRAME); | 454 set_error(SPDY_INVALID_CONTROL_FRAME); |
(...skipping 18 matching lines...) Expand all Loading... | |
438 if (current_control_frame.length() < | 473 if (current_control_frame.length() < |
439 SpdySynReplyControlFrame::size() - SpdyControlFrame::kHeaderSize) | 474 SpdySynReplyControlFrame::size() - SpdyControlFrame::kHeaderSize) |
440 set_error(SPDY_INVALID_CONTROL_FRAME); | 475 set_error(SPDY_INVALID_CONTROL_FRAME); |
441 break; | 476 break; |
442 case RST_STREAM: | 477 case RST_STREAM: |
443 if (current_control_frame.length() != | 478 if (current_control_frame.length() != |
444 SpdyRstStreamControlFrame::size() - SpdyFrame::kHeaderSize) | 479 SpdyRstStreamControlFrame::size() - SpdyFrame::kHeaderSize) |
445 set_error(SPDY_INVALID_CONTROL_FRAME); | 480 set_error(SPDY_INVALID_CONTROL_FRAME); |
446 break; | 481 break; |
447 case SETTINGS: | 482 case SETTINGS: |
483 // Make sure that we have an integral number of 8-byte key/value pairs, | |
484 // plus a 4-byte length field. | |
448 if (current_control_frame.length() < | 485 if (current_control_frame.length() < |
449 SpdySettingsControlFrame::size() - SpdyControlFrame::kHeaderSize) | 486 SpdySettingsControlFrame::size() - SpdyControlFrame::kHeaderSize || |
487 (current_control_frame.length() % 8 != 4)) { | |
488 DLOG(WARNING) << "Invalid length for SETTINGS frame: " | |
489 << current_control_frame.length(); | |
450 set_error(SPDY_INVALID_CONTROL_FRAME); | 490 set_error(SPDY_INVALID_CONTROL_FRAME); |
491 } | |
451 break; | 492 break; |
452 case GOAWAY: | 493 case GOAWAY: |
453 if (current_control_frame.length() != | 494 if (current_control_frame.length() != |
454 SpdyGoAwayControlFrame::size() - SpdyFrame::kHeaderSize) | 495 SpdyGoAwayControlFrame::size() - SpdyFrame::kHeaderSize) |
455 set_error(SPDY_INVALID_CONTROL_FRAME); | 496 set_error(SPDY_INVALID_CONTROL_FRAME); |
456 break; | 497 break; |
457 case HEADERS: | 498 case HEADERS: |
458 if (current_control_frame.length() < | 499 if (current_control_frame.length() < |
459 SpdyHeadersControlFrame::size() - SpdyControlFrame::kHeaderSize) | 500 SpdyHeadersControlFrame::size() - SpdyControlFrame::kHeaderSize) |
460 set_error(SPDY_INVALID_CONTROL_FRAME); | 501 set_error(SPDY_INVALID_CONTROL_FRAME); |
(...skipping 17 matching lines...) Expand all Loading... | |
478 default: | 519 default: |
479 LOG(WARNING) << "Valid " << display_protocol_ | 520 LOG(WARNING) << "Valid " << display_protocol_ |
480 << " control frame with unhandled type: " | 521 << " control frame with unhandled type: " |
481 << current_control_frame.type(); | 522 << current_control_frame.type(); |
482 DCHECK(false); | 523 DCHECK(false); |
483 set_error(SPDY_INVALID_CONTROL_FRAME); | 524 set_error(SPDY_INVALID_CONTROL_FRAME); |
484 break; | 525 break; |
485 } | 526 } |
486 } | 527 } |
487 | 528 |
488 // We only support version 1 of this protocol. | |
489 if (current_control_frame.version() != spdy_version_) { | |
490 set_error(SPDY_UNSUPPORTED_VERSION); | |
491 return; | |
492 } | |
493 | |
494 remaining_control_payload_ = current_control_frame.length(); | 529 remaining_control_payload_ = current_control_frame.length(); |
495 if (remaining_control_payload_ > | 530 if (remaining_control_payload_ > |
496 kControlFrameBufferMaxSize - SpdyFrame::kHeaderSize) { | 531 kControlFrameBufferMaxSize - SpdyFrame::kHeaderSize) { |
497 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE); | 532 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE); |
498 return; | 533 return; |
499 } | 534 } |
500 | 535 |
501 if (current_control_frame.type() == CREDENTIAL) { | 536 if (current_control_frame.type() == CREDENTIAL) { |
502 visitor_->OnControl(¤t_control_frame); | 537 visitor_->OnControl(¤t_control_frame); |
503 CHANGE_STATE(SPDY_CREDENTIAL_FRAME_PAYLOAD); | 538 CHANGE_STATE(SPDY_CREDENTIAL_FRAME_PAYLOAD); |
504 return; | 539 return; |
505 } | 540 } |
506 | 541 |
507 int32 frame_size_without_header_block; | 542 // Determine the frame size without variable-length data. |
543 int32 frame_size_without_variable_data; | |
508 switch (current_control_frame.type()) { | 544 switch (current_control_frame.type()) { |
509 case SYN_STREAM: | 545 case SYN_STREAM: |
510 frame_size_without_header_block = SpdySynStreamControlFrame::size(); | 546 syn_frame_processed_ = true; |
547 frame_size_without_variable_data = SpdySynStreamControlFrame::size(); | |
511 break; | 548 break; |
512 case SYN_REPLY: | 549 case SYN_REPLY: |
513 frame_size_without_header_block = SpdySynReplyControlFrame::size(); | 550 syn_frame_processed_ = true; |
551 frame_size_without_variable_data = SpdySynReplyControlFrame::size(); | |
552 // SPDY 2 had two bytes of unused space preceeding payload. | |
553 if (spdy_version_ < 3) { | |
554 frame_size_without_variable_data += 2; | |
555 } | |
514 break; | 556 break; |
515 case HEADERS: | 557 case HEADERS: |
516 frame_size_without_header_block = SpdyHeadersControlFrame::size(); | 558 frame_size_without_variable_data = SpdyHeadersControlFrame::size(); |
559 // SPDY 2 had two bytes of unused space preceeding payload. | |
560 if (spdy_version_ < 3) { | |
561 frame_size_without_variable_data += 2; | |
562 } | |
563 break; | |
564 case SETTINGS: | |
565 frame_size_without_variable_data = SpdySettingsControlFrame::size(); | |
517 break; | 566 break; |
518 default: | 567 default: |
519 frame_size_without_header_block = -1; | 568 frame_size_without_variable_data = -1; |
520 LOG_IF(DFATAL, remaining_control_payload_ + SpdyFrame::kHeaderSize > | |
521 current_frame_capacity_) | |
522 << display_protocol_ | |
523 << " control frame buffer too small for fixed-length frame."; | |
524 ExpandControlFrameBuffer(remaining_control_payload_); | |
525 break; | 569 break; |
526 } | 570 } |
527 | 571 |
528 if (frame_size_without_header_block > 0) { | 572 if (frame_size_without_variable_data == -1) { |
573 LOG_IF(ERROR, remaining_control_payload_ + SpdyFrame::kHeaderSize > | |
574 current_frame_capacity_) | |
575 << display_protocol_ | |
576 << " control frame buffer too small for fixed-length frame."; | |
577 // TODO(hkhalil): Remove ExpandControlFrameBuffer(). | |
578 ExpandControlFrameBuffer(remaining_control_payload_); | |
579 } | |
580 if (frame_size_without_variable_data > 0) { | |
529 // We have a control frame with a header block. We need to parse the | 581 // We have a control frame with a header block. We need to parse the |
530 // remainder of the control frame's header before we can parse the header | 582 // remainder of the control frame's header before we can parse the header |
531 // block. The start of the header block varies with the control type. | 583 // block. The start of the header block varies with the control type. |
532 DCHECK_GE(static_cast<uint32>(frame_size_without_header_block), | 584 DCHECK_GE(frame_size_without_variable_data, |
533 current_frame_len_); | 585 static_cast<int32>(current_frame_len_)); |
534 remaining_control_header_ = frame_size_without_header_block - | 586 remaining_control_header_ = frame_size_without_variable_data - |
535 current_frame_len_; | 587 current_frame_len_; |
536 remaining_control_payload_ += SpdyFrame::kHeaderSize - | 588 remaining_control_payload_ += SpdyFrame::kHeaderSize - |
537 frame_size_without_header_block; | 589 frame_size_without_variable_data; |
538 CHANGE_STATE(SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK); | 590 CHANGE_STATE(SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK); |
539 return; | 591 return; |
540 } | 592 } |
541 | 593 |
542 CHANGE_STATE(SPDY_CONTROL_FRAME_PAYLOAD); | 594 CHANGE_STATE(SPDY_CONTROL_FRAME_PAYLOAD); |
543 } | 595 } |
544 | 596 |
545 size_t SpdyFramer::UpdateCurrentFrameBuffer(const char** data, size_t* len, | 597 size_t SpdyFramer::UpdateCurrentFrameBuffer(const char** data, size_t* len, |
546 size_t max_bytes) { | 598 size_t max_bytes) { |
547 size_t bytes_to_read = std::min(*len, max_bytes); | 599 size_t bytes_to_read = std::min(*len, max_bytes); |
548 DCHECK_GE(current_frame_capacity_, current_frame_len_ + bytes_to_read); | 600 DCHECK_GE(current_frame_capacity_, current_frame_len_ + bytes_to_read); |
549 memcpy(¤t_frame_buffer_[current_frame_len_], *data, bytes_to_read); | 601 memcpy(¤t_frame_buffer_[current_frame_len_], *data, bytes_to_read); |
550 current_frame_len_ += bytes_to_read; | 602 current_frame_len_ += bytes_to_read; |
551 *data += bytes_to_read; | 603 *data += bytes_to_read; |
552 *len -= bytes_to_read; | 604 *len -= bytes_to_read; |
553 return bytes_to_read; | 605 return bytes_to_read; |
554 } | 606 } |
555 | 607 |
608 size_t SpdyFramer::GetSerializedLength(const SpdyHeaderBlock* headers) const { | |
609 const size_t num_name_value_pairs_size | |
610 = (spdy_version_ < 3) ? sizeof(uint16) : sizeof(uint32); | |
611 const size_t length_of_name_size = num_name_value_pairs_size; | |
612 const size_t length_of_value_size = num_name_value_pairs_size; | |
613 | |
614 size_t total_length = num_name_value_pairs_size; | |
615 for (SpdyHeaderBlock::const_iterator it = headers->begin(); | |
616 it != headers->end(); | |
617 ++it) { | |
618 // We add space for the length of the name and the length of the value as | |
619 // well as the length of the name and the length of the value. | |
620 total_length += length_of_name_size + it->first.size() + | |
621 length_of_value_size + it->second.size(); | |
622 } | |
623 return total_length; | |
624 } | |
625 | |
626 void SpdyFramer::WriteHeaderBlock(SpdyFrameBuilder* frame, | |
627 const SpdyHeaderBlock* headers) const { | |
628 if (spdy_version_ < 3) { | |
629 frame->WriteUInt16(headers->size()); // Number of headers. | |
630 } else { | |
631 frame->WriteUInt32(headers->size()); // Number of headers. | |
632 } | |
633 SpdyHeaderBlock::const_iterator it; | |
634 for (it = headers->begin(); it != headers->end(); ++it) { | |
635 bool wrote_header; | |
636 if (spdy_version_ < 3) { | |
637 wrote_header = frame->WriteString(it->first); | |
638 wrote_header &= frame->WriteString(it->second); | |
639 } else { | |
640 wrote_header = frame->WriteStringPiece32(it->first); | |
641 wrote_header &= frame->WriteStringPiece32(it->second); | |
642 } | |
643 DCHECK(wrote_header); | |
644 } | |
645 } | |
646 | |
647 | |
556 size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data, | 648 size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data, |
557 size_t len) { | 649 size_t len) { |
558 DCHECK_EQ(SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK, state_); | 650 DCHECK_EQ(SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK, state_); |
559 DCHECK_GT(remaining_control_header_, 0u); | 651 DCHECK_GT(remaining_control_header_, 0u); |
560 size_t original_len = len; | 652 size_t original_len = len; |
561 | 653 |
562 if (remaining_control_header_) { | 654 if (remaining_control_header_) { |
563 size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len, | 655 size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len, |
564 remaining_control_header_); | 656 remaining_control_header_); |
565 remaining_control_header_ -= bytes_read; | 657 remaining_control_header_ -= bytes_read; |
566 if (remaining_control_header_ == 0) { | 658 if (remaining_control_header_ == 0) { |
567 SpdyControlFrame control_frame(current_frame_buffer_, false); | 659 SpdyControlFrame control_frame(current_frame_buffer_, false); |
568 DCHECK(control_frame.type() == SYN_STREAM || | 660 DCHECK(control_frame.type() == SYN_STREAM || |
569 control_frame.type() == SYN_REPLY || | 661 control_frame.type() == SYN_REPLY || |
570 control_frame.type() == HEADERS); | 662 control_frame.type() == HEADERS || |
663 control_frame.type() == SETTINGS); | |
571 visitor_->OnControl(&control_frame); | 664 visitor_->OnControl(&control_frame); |
572 | 665 |
573 CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK); | 666 if (control_frame.type() == SETTINGS) { |
667 CHANGE_STATE(SPDY_SETTINGS_FRAME_PAYLOAD); | |
668 } else { | |
669 CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK); | |
670 } | |
574 } | 671 } |
575 } | 672 } |
576 return original_len - len; | 673 return original_len - len; |
577 } | 674 } |
578 | 675 |
579 // Does not buffer the control payload. Instead, either passes directly to the | 676 // Does not buffer the control payload. Instead, either passes directly to the |
580 // visitor or decompresses and then passes directly to the visitor, via | 677 // visitor or decompresses and then passes directly to the visitor, via |
581 // IncrementallyDeliverControlFrameHeaderData() or | 678 // IncrementallyDeliverControlFrameHeaderData() or |
582 // IncrementallyDecompressControlFrameHeaderData() respectively. | 679 // IncrementallyDecompressControlFrameHeaderData() respectively. |
583 size_t SpdyFramer::ProcessControlFrameHeaderBlock(const char* data, | 680 size_t SpdyFramer::ProcessControlFrameHeaderBlock(const char* data, |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
618 | 715 |
619 // Handle error. | 716 // Handle error. |
620 if (!processed_successfully) { | 717 if (!processed_successfully) { |
621 return data_len; | 718 return data_len; |
622 } | 719 } |
623 | 720 |
624 // Return amount processed. | 721 // Return amount processed. |
625 return process_bytes; | 722 return process_bytes; |
626 } | 723 } |
627 | 724 |
725 size_t SpdyFramer::ProcessSettingsFramePayload(const char* data, | |
726 size_t data_len) { | |
727 DCHECK_EQ(SPDY_SETTINGS_FRAME_PAYLOAD, state_); | |
728 SpdyControlFrame control_frame(current_frame_buffer_, false); | |
729 DCHECK_EQ(control_frame.type(), SETTINGS); | |
730 size_t unprocessed_bytes = std::min(data_len, remaining_control_payload_); | |
731 size_t processed_bytes = 0; | |
732 DCHECK_GT(unprocessed_bytes, 0u); | |
733 | |
734 // Loop over our incoming data. | |
735 while (unprocessed_bytes > 0) { | |
736 // Process up to one setting at a time. | |
737 size_t processing = std::min( | |
738 unprocessed_bytes, | |
739 static_cast<size_t>(8 - settings_scratch_.setting_buf_len)); | |
740 | |
741 // Check if we have a complete setting in our input. | |
742 if (processing == 8) { | |
743 // Parse the setting directly out of the input without buffering. | |
744 if (!ProcessSetting(data + processed_bytes)) { | |
745 set_error(SPDY_INVALID_CONTROL_FRAME); | |
746 return processed_bytes; | |
747 } | |
748 } else { | |
749 // Continue updating settings_scratch_.setting_buf. | |
750 memcpy(settings_scratch_.setting_buf + settings_scratch_.setting_buf_len, | |
751 data + processed_bytes, | |
752 processing); | |
753 settings_scratch_.setting_buf_len += processing; | |
754 | |
755 // Check if we have a complete setting buffered. | |
756 if (settings_scratch_.setting_buf_len == 8) { | |
757 if (!ProcessSetting(settings_scratch_.setting_buf)) { | |
758 set_error(SPDY_INVALID_CONTROL_FRAME); | |
759 return processed_bytes; | |
760 } | |
761 // Reset settings_scratch_.setting_buf for our next setting. | |
762 settings_scratch_.setting_buf_len = 0; | |
763 } | |
764 } | |
765 | |
766 // Iterate. | |
767 unprocessed_bytes -= processing; | |
768 processed_bytes += processing; | |
769 } | |
770 | |
771 // Check if we're done handling this SETTINGS frame. | |
772 remaining_control_payload_ -= processed_bytes; | |
773 if (remaining_control_payload_ == 0) { | |
774 CHANGE_STATE(SPDY_AUTO_RESET); | |
775 } | |
776 | |
777 return processed_bytes; | |
778 } | |
779 | |
780 bool SpdyFramer::ProcessSetting(const char* data) { | |
781 // Extract fields. | |
782 // Maintain behavior of old SPDY 2 bug with byte ordering of flags/id. | |
783 const uint32 id_and_flags_wire = *(reinterpret_cast<const uint32*>(data)); | |
784 SettingsFlagsAndId id_and_flags = | |
785 SettingsFlagsAndId::FromWireFormat(spdy_version_, id_and_flags_wire); | |
786 uint8 flags = id_and_flags.flags(); | |
787 uint32 value = ntohl(*(reinterpret_cast<const uint32*>(data + 4))); | |
788 | |
789 // Validate id. | |
790 switch (id_and_flags.id()) { | |
791 case SETTINGS_UPLOAD_BANDWIDTH: | |
792 case SETTINGS_DOWNLOAD_BANDWIDTH: | |
793 case SETTINGS_ROUND_TRIP_TIME: | |
794 case SETTINGS_MAX_CONCURRENT_STREAMS: | |
795 case SETTINGS_CURRENT_CWND: | |
796 case SETTINGS_DOWNLOAD_RETRANS_RATE: | |
797 case SETTINGS_INITIAL_WINDOW_SIZE: | |
798 // Valid values. | |
799 break; | |
800 default: | |
801 DLOG(WARNING) << "Unknown SETTINGS ID: " << id_and_flags.id(); | |
802 return false; | |
803 } | |
804 SpdySettingsIds id = static_cast<SpdySettingsIds>(id_and_flags.id()); | |
805 | |
806 // Detect duplciates. | |
807 if (static_cast<uint32>(id) <= settings_scratch_.last_setting_id) { | |
808 DLOG(WARNING) << "Duplicate entry or invalid ordering for id " << id | |
809 << " in " << display_protocol_ << " SETTINGS frame " | |
810 << "(last settikng id was " | |
811 << settings_scratch_.last_setting_id << ")."; | |
812 return false; | |
813 } | |
814 settings_scratch_.last_setting_id = id; | |
815 | |
816 // Validate flags. | |
817 uint8 kFlagsMask = SETTINGS_FLAG_PLEASE_PERSIST | SETTINGS_FLAG_PERSISTED; | |
818 if ((flags & ~(kFlagsMask)) != 0) { | |
819 DLOG(WARNING) << "Unknown SETTINGS flags provided for id " << id << ": " | |
820 << flags; | |
821 return false; | |
822 } | |
823 | |
824 // Validation succeeded. Pass on to visitor. | |
825 visitor_->OnSetting(id, flags, value); | |
826 return true; | |
827 } | |
828 | |
628 size_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) { | 829 size_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) { |
629 size_t original_len = len; | 830 size_t original_len = len; |
630 if (remaining_control_payload_) { | 831 if (remaining_control_payload_) { |
631 size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len, | 832 size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len, |
632 remaining_control_payload_); | 833 remaining_control_payload_); |
633 remaining_control_payload_ -= bytes_read; | 834 remaining_control_payload_ -= bytes_read; |
634 remaining_data_ -= bytes_read; | 835 remaining_data_ -= bytes_read; |
635 if (remaining_control_payload_ == 0) { | 836 if (remaining_control_payload_ == 0) { |
636 SpdyControlFrame control_frame(current_frame_buffer_, false); | 837 SpdyControlFrame control_frame(current_frame_buffer_, false); |
637 DCHECK(!control_frame.has_header_block()); | 838 DCHECK(!control_frame.has_header_block()); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
722 DCHECK_LE(alloc_size, kControlFrameBufferMaxSize); | 923 DCHECK_LE(alloc_size, kControlFrameBufferMaxSize); |
723 if (alloc_size <= current_frame_capacity_) | 924 if (alloc_size <= current_frame_capacity_) |
724 return; | 925 return; |
725 char* new_buffer = new char[alloc_size]; | 926 char* new_buffer = new char[alloc_size]; |
726 memcpy(new_buffer, current_frame_buffer_, current_frame_len_); | 927 memcpy(new_buffer, current_frame_buffer_, current_frame_len_); |
727 delete [] current_frame_buffer_; | 928 delete [] current_frame_buffer_; |
728 current_frame_capacity_ = alloc_size; | 929 current_frame_capacity_ = alloc_size; |
729 current_frame_buffer_ = new_buffer; | 930 current_frame_buffer_ = new_buffer; |
730 } | 931 } |
731 | 932 |
732 /* static */ | |
733 bool SpdyFramer::ParseHeaderBlockInBuffer(const char* header_data, | 933 bool SpdyFramer::ParseHeaderBlockInBuffer(const char* header_data, |
734 size_t header_length, | 934 size_t header_length, |
735 SpdyHeaderBlock* block) { | 935 SpdyHeaderBlock* block) { |
736 SpdyFrameBuilder builder(header_data, header_length); | 936 SpdyFrameReader reader(header_data, header_length); |
737 void* iter = NULL; | 937 |
738 uint16 num_headers; | 938 // Read number of headers. |
739 if (builder.ReadUInt16(&iter, &num_headers)) { | 939 uint32 num_headers; |
740 for (int index = 0; index < num_headers; ++index) { | 940 if (spdy_version_ < 3) { |
741 std::string name; | 941 uint16 temp; |
742 std::string value; | 942 if (!reader.ReadUInt16(&temp)) { |
743 if (!builder.ReadString(&iter, &name)) | 943 DLOG(INFO) << "Unable to read number of headers."; |
744 return false; | 944 return false; |
745 if (!builder.ReadString(&iter, &value)) | |
746 return false; | |
747 if (block->find(name) == block->end()) { | |
748 (*block)[name] = value; | |
749 } else { | |
750 return false; | |
751 } | |
752 } | 945 } |
753 return true; | 946 num_headers = temp; |
754 } | 947 } else { |
755 return false; | 948 if (!reader.ReadUInt32(&num_headers)) { |
756 } | 949 DLOG(INFO) << "Unable to read number of headers."; |
757 | 950 return false; |
758 bool SpdyFramer::ParseHeaderBlock(const SpdyFrame* frame, | 951 } |
759 SpdyHeaderBlock* block) { | |
760 SpdyControlFrame control_frame(frame->data(), false); | |
761 uint32 type = control_frame.type(); | |
762 if (type != SYN_STREAM && type != SYN_REPLY && type != HEADERS) | |
763 return false; | |
764 | |
765 // Find the header data within the control frame. | |
766 scoped_ptr<SpdyFrame> decompressed_frame(DecompressFrame(*frame)); | |
767 if (!decompressed_frame.get()) | |
768 return false; | |
769 | |
770 const char *header_data = NULL; | |
771 int header_length = 0; | |
772 | |
773 switch (type) { | |
774 case SYN_STREAM: | |
775 { | |
776 SpdySynStreamControlFrame syn_frame(decompressed_frame->data(), false); | |
777 header_data = syn_frame.header_block(); | |
778 header_length = syn_frame.header_block_len(); | |
779 } | |
780 break; | |
781 case SYN_REPLY: | |
782 { | |
783 SpdySynReplyControlFrame syn_frame(decompressed_frame->data(), false); | |
784 header_data = syn_frame.header_block(); | |
785 header_length = syn_frame.header_block_len(); | |
786 } | |
787 break; | |
788 case HEADERS: | |
789 { | |
790 SpdyHeadersControlFrame header_frame(decompressed_frame->data(), false); | |
791 header_data = header_frame.header_block(); | |
792 header_length = header_frame.header_block_len(); | |
793 } | |
794 break; | |
795 } | 952 } |
796 | 953 |
797 SpdyFrameBuilder builder(header_data, header_length); | 954 // Read each header. |
798 void* iter = NULL; | 955 for (uint32 index = 0; index < num_headers; ++index) { |
799 uint16 num_headers; | 956 base::StringPiece temp; |
800 if (builder.ReadUInt16(&iter, &num_headers)) { | 957 |
801 int index; | 958 // Read header name. |
802 for (index = 0; index < num_headers; ++index) { | 959 if ((spdy_version_ < 3) ? !reader.ReadStringPiece16(&temp) |
803 std::string name; | 960 : !reader.ReadStringPiece32(&temp)) { |
804 std::string value; | 961 DLOG(INFO) << "Unable to read header name (" << index + 1 << " of " |
805 if (!builder.ReadString(&iter, &name)) | 962 << num_headers << ")."; |
806 break; | 963 return false; |
807 if (!builder.ReadString(&iter, &value)) | |
808 break; | |
809 if (!name.size() || !value.size()) | |
810 return false; | |
811 if (block->find(name) == block->end()) { | |
812 (*block)[name] = value; | |
813 } else { | |
814 return false; | |
815 } | |
816 } | 964 } |
817 return index == num_headers && | 965 std::string name; |
818 iter == header_data + header_length; | 966 temp.CopyToString(&name); |
967 | |
968 // Read header value. | |
969 if ((spdy_version_ < 3) ? !reader.ReadStringPiece16(&temp) | |
970 : !reader.ReadStringPiece32(&temp)) { | |
971 DLOG(INFO) << "Unable to read header value (" << index + 1 << " of " | |
972 << num_headers << ")."; | |
973 return false; | |
974 } | |
975 std::string value; | |
976 temp.CopyToString(&value); | |
977 | |
978 // Ensure no duplicates. | |
979 if (block->find(name) != block->end()) { | |
980 DLOG(INFO) << "Duplicate header '" << name << "' (" << index + 1 << " of " | |
981 << num_headers << ")."; | |
982 return false; | |
983 } | |
984 | |
985 // Store header. | |
986 (*block)[name] = value; | |
819 } | 987 } |
820 return false; | 988 return true; |
821 } | 989 } |
822 | 990 |
823 /* static */ | 991 /* static */ |
824 bool SpdyFramer::ParseSettings(const SpdySettingsControlFrame* frame, | 992 bool SpdyFramer::ParseSettings(const SpdySettingsControlFrame* frame, |
825 SpdySettings* settings) { | 993 SpdySettings* settings) { |
826 DCHECK_EQ(frame->type(), SETTINGS); | 994 DCHECK_EQ(frame->type(), SETTINGS); |
827 DCHECK(settings); | 995 DCHECK(settings); |
828 | 996 |
829 SpdyFrameBuilder parser(frame->header_block(), frame->header_block_len()); | 997 SpdyFrameReader parser(frame->header_block(), frame->header_block_len()); |
830 void* iter = NULL; | |
831 for (size_t index = 0; index < frame->num_entries(); ++index) { | 998 for (size_t index = 0; index < frame->num_entries(); ++index) { |
832 uint32 id; | 999 uint32 id_and_flags_wire; |
833 uint32 value; | 1000 uint32 value; |
834 if (!parser.ReadUInt32(&iter, &id)) | 1001 // SettingsFlagsAndId accepts off-the-wire (network byte order) data, so we |
1002 // use ReadBytes() instead of ReadUInt32() as the latter calls ntohl(). | |
1003 if (!parser.ReadBytes(&id_and_flags_wire, 4)) { | |
835 return false; | 1004 return false; |
836 if (!parser.ReadUInt32(&iter, &value)) | 1005 } |
1006 if (!parser.ReadUInt32(&value)) | |
837 return false; | 1007 return false; |
838 settings->insert(settings->end(), std::make_pair(id, value)); | 1008 SettingsFlagsAndId id_and_flags = |
1009 SettingsFlagsAndId::FromWireFormat(frame->version(), id_and_flags_wire); | |
1010 settings->insert(settings->end(), std::make_pair(id_and_flags, value)); | |
839 } | 1011 } |
840 return true; | 1012 return true; |
841 } | 1013 } |
842 | 1014 |
843 /* static */ | 1015 /* static */ |
844 bool SpdyFramer::ParseCredentialData(const char* data, size_t len, | 1016 bool SpdyFramer::ParseCredentialData(const char* data, size_t len, |
845 SpdyCredential* credential) { | 1017 SpdyCredential* credential) { |
846 DCHECK(credential); | 1018 DCHECK(credential); |
847 | 1019 |
848 void* iter = NULL; | 1020 SpdyFrameReader parser(data, len); |
849 SpdyFrameBuilder parser(data, len); | 1021 base::StringPiece temp; |
850 if (!parser.ReadUInt16(&iter, &credential->slot)) | 1022 if (!parser.ReadUInt16(&credential->slot)) { |
851 return false; | 1023 return false; |
1024 } | |
852 | 1025 |
853 uint32 proof_len; | 1026 if (!parser.ReadStringPiece32(&temp)) { |
854 const char* proof_data; | |
855 if (!parser.ReadReadLen32PrefixedData(&iter, &proof_data, &proof_len)) | |
856 return false; | 1027 return false; |
857 credential->proof.assign(proof_data, proof_len); | 1028 } |
1029 temp.CopyToString(&credential->proof); | |
858 | 1030 |
859 while (parser.IteratorHasRoomFor(iter, 1)) { | 1031 while (!parser.IsDoneReading()) { |
860 uint32 cert_len; | 1032 if (!parser.ReadStringPiece32(&temp)) { |
861 const char* cert_data; | |
862 if (!parser.ReadReadLen32PrefixedData(&iter, &cert_data, &cert_len)) | |
863 return false; | 1033 return false; |
864 credential->certs.push_back(""); | 1034 } |
865 credential->certs.back().assign(cert_data, cert_len); | 1035 std::string cert; |
1036 temp.CopyToString(&cert); | |
1037 credential->certs.push_back(cert); | |
866 } | 1038 } |
867 return true; | 1039 return true; |
868 } | 1040 } |
869 | 1041 |
870 SpdySynStreamControlFrame* SpdyFramer::CreateSynStream( | 1042 SpdySynStreamControlFrame* SpdyFramer::CreateSynStream( |
871 SpdyStreamId stream_id, SpdyStreamId associated_stream_id, int priority, | 1043 SpdyStreamId stream_id, |
872 SpdyControlFlags flags, bool compressed, const SpdyHeaderBlock* headers) { | 1044 SpdyStreamId associated_stream_id, |
873 DCHECK_GT(stream_id, static_cast<SpdyStreamId>(0)); | 1045 SpdyPriority priority, |
1046 SpdyControlFlags flags, | |
1047 bool compressed, | |
1048 const SpdyHeaderBlock* headers) { | |
874 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); | 1049 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); |
875 DCHECK_EQ(0u, associated_stream_id & ~kStreamIdMask); | 1050 DCHECK_EQ(0u, associated_stream_id & ~kStreamIdMask); |
876 | 1051 |
877 // Find our length. | 1052 // Find our length. |
878 size_t expected_frame_size = SpdySynStreamControlFrame::size() + | 1053 size_t expected_frame_size = SpdySynStreamControlFrame::size() + |
879 GetSerializedLength(headers); | 1054 GetSerializedLength(headers); |
880 | 1055 |
881 // Create our FlagsAndLength. | 1056 // Create our FlagsAndLength. |
882 FlagsAndLength flags_length = CreateFlagsAndLength( | 1057 FlagsAndLength flags_length = CreateFlagsAndLength( |
883 flags, | 1058 flags, |
884 expected_frame_size - SpdyFrame::kHeaderSize); | 1059 expected_frame_size - SpdyFrame::kHeaderSize); |
885 | 1060 |
886 SpdyFrameBuilder frame(expected_frame_size); | 1061 SpdyFrameBuilder frame(expected_frame_size); |
887 frame.WriteUInt16(kControlFlagMask | spdy_version_); | 1062 frame.WriteUInt16(kControlFlagMask | spdy_version_); |
888 frame.WriteUInt16(SYN_STREAM); | 1063 frame.WriteUInt16(SYN_STREAM); |
889 frame.WriteBytes(&flags_length, sizeof(flags_length)); | 1064 frame.WriteBytes(&flags_length, sizeof(flags_length)); |
890 frame.WriteUInt32(stream_id); | 1065 frame.WriteUInt32(stream_id); |
891 frame.WriteUInt32(associated_stream_id); | 1066 frame.WriteUInt32(associated_stream_id); |
892 frame.WriteUInt16(ntohs(priority) << 6); // Priority. | 1067 // Cap as appropriate. |
1068 if (priority > GetLowestPriority()) { | |
1069 DLOG(ERROR) << "Priority out-of-bounds."; | |
1070 priority = GetLowestPriority(); | |
1071 } | |
1072 // Priority is 2 bits for <spdy3, 3 bits otherwise. | |
1073 frame.WriteUInt16(ntohs(priority) << (spdy_version_ < 3 ? 6 : 5)); | |
893 WriteHeaderBlock(&frame, headers); | 1074 WriteHeaderBlock(&frame, headers); |
894 | 1075 |
895 scoped_ptr<SpdySynStreamControlFrame> syn_frame( | 1076 scoped_ptr<SpdySynStreamControlFrame> syn_frame( |
896 reinterpret_cast<SpdySynStreamControlFrame*>(frame.take())); | 1077 reinterpret_cast<SpdySynStreamControlFrame*>(frame.take())); |
897 if (compressed) { | 1078 if (compressed) { |
898 return reinterpret_cast<SpdySynStreamControlFrame*>( | 1079 return reinterpret_cast<SpdySynStreamControlFrame*>( |
899 CompressControlFrame(*syn_frame.get())); | 1080 CompressControlFrame(*syn_frame.get())); |
900 } | 1081 } |
901 return syn_frame.release(); | 1082 return syn_frame.release(); |
902 } | 1083 } |
903 | 1084 |
904 SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(SpdyStreamId stream_id, | 1085 SpdySynReplyControlFrame* SpdyFramer::CreateSynReply( |
905 SpdyControlFlags flags, bool compressed, const SpdyHeaderBlock* headers) { | 1086 SpdyStreamId stream_id, |
1087 SpdyControlFlags flags, | |
1088 bool compressed, | |
1089 const SpdyHeaderBlock* headers) { | |
906 DCHECK_GT(stream_id, 0u); | 1090 DCHECK_GT(stream_id, 0u); |
907 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); | 1091 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); |
908 | 1092 |
909 // Find our length. | 1093 // Find our length. |
910 size_t expected_frame_size = SpdySynReplyControlFrame::size() + | 1094 size_t expected_frame_size = SpdySynReplyControlFrame::size() + |
911 GetSerializedLength(headers); | 1095 GetSerializedLength(headers); |
1096 // In SPDY 2, there were 2 unused bytes before payload. | |
1097 if (spdy_version_ < 3) { | |
1098 expected_frame_size += 2; | |
1099 } | |
912 | 1100 |
913 // Create our FlagsAndLength. | 1101 // Create our FlagsAndLength. |
914 FlagsAndLength flags_length = CreateFlagsAndLength( | 1102 FlagsAndLength flags_length = CreateFlagsAndLength( |
915 flags, | 1103 flags, |
916 expected_frame_size - SpdyFrame::kHeaderSize); | 1104 expected_frame_size - SpdyFrame::kHeaderSize); |
917 | 1105 |
918 SpdyFrameBuilder frame(expected_frame_size); | 1106 SpdyFrameBuilder frame(expected_frame_size); |
919 frame.WriteUInt16(kControlFlagMask | spdy_version_); | 1107 frame.WriteUInt16(kControlFlagMask | spdy_version_); |
920 frame.WriteUInt16(SYN_REPLY); | 1108 frame.WriteUInt16(SYN_REPLY); |
921 frame.WriteBytes(&flags_length, sizeof(flags_length)); | 1109 frame.WriteBytes(&flags_length, sizeof(flags_length)); |
922 frame.WriteUInt32(stream_id); | 1110 frame.WriteUInt32(stream_id); |
923 frame.WriteUInt16(0); // Unused | 1111 if (spdy_version_ < 3) { |
1112 frame.WriteUInt16(0); // Unused | |
1113 } | |
924 WriteHeaderBlock(&frame, headers); | 1114 WriteHeaderBlock(&frame, headers); |
925 | 1115 |
926 scoped_ptr<SpdySynReplyControlFrame> reply_frame( | 1116 scoped_ptr<SpdySynReplyControlFrame> reply_frame( |
927 reinterpret_cast<SpdySynReplyControlFrame*>(frame.take())); | 1117 reinterpret_cast<SpdySynReplyControlFrame*>(frame.take())); |
928 if (compressed) { | 1118 if (compressed) { |
929 return reinterpret_cast<SpdySynReplyControlFrame*>( | 1119 return reinterpret_cast<SpdySynReplyControlFrame*>( |
930 CompressControlFrame(*reply_frame.get())); | 1120 CompressControlFrame(*reply_frame.get())); |
931 } | 1121 } |
932 return reply_frame.release(); | 1122 return reply_frame.release(); |
933 } | 1123 } |
934 | 1124 |
935 /* static */ | 1125 SpdyRstStreamControlFrame* SpdyFramer::CreateRstStream( |
936 SpdyRstStreamControlFrame* SpdyFramer::CreateRstStream(SpdyStreamId stream_id, | 1126 SpdyStreamId stream_id, |
937 SpdyStatusCodes status) { | 1127 SpdyStatusCodes status) const { |
938 DCHECK_GT(stream_id, 0u); | 1128 DCHECK_GT(stream_id, 0u); |
939 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); | 1129 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); |
940 DCHECK_NE(status, INVALID); | 1130 DCHECK_NE(status, INVALID); |
941 DCHECK_LT(status, NUM_STATUS_CODES); | 1131 DCHECK_LT(status, NUM_STATUS_CODES); |
942 | 1132 |
943 SpdyFrameBuilder frame(SpdyRstStreamControlFrame::size()); | 1133 SpdyFrameBuilder frame(SpdyRstStreamControlFrame::size()); |
944 frame.WriteUInt16(kControlFlagMask | spdy_version_); | 1134 frame.WriteUInt16(kControlFlagMask | spdy_version_); |
945 frame.WriteUInt16(RST_STREAM); | 1135 frame.WriteUInt16(RST_STREAM); |
946 frame.WriteUInt32(8); | 1136 frame.WriteUInt32(8); |
947 frame.WriteUInt32(stream_id); | 1137 frame.WriteUInt32(stream_id); |
948 frame.WriteUInt32(status); | 1138 frame.WriteUInt32(status); |
949 return reinterpret_cast<SpdyRstStreamControlFrame*>(frame.take()); | 1139 return reinterpret_cast<SpdyRstStreamControlFrame*>(frame.take()); |
950 } | 1140 } |
951 | 1141 |
952 /* static */ | |
953 SpdySettingsControlFrame* SpdyFramer::CreateSettings( | 1142 SpdySettingsControlFrame* SpdyFramer::CreateSettings( |
954 const SpdySettings& values) { | 1143 const SpdySettings& values) const { |
955 SpdyFrameBuilder frame(SpdySettingsControlFrame::size() + 8 * values.size()); | 1144 SpdyFrameBuilder frame(SpdySettingsControlFrame::size() + 8 * values.size()); |
956 frame.WriteUInt16(kControlFlagMask | spdy_version_); | 1145 frame.WriteUInt16(kControlFlagMask | spdy_version_); |
957 frame.WriteUInt16(SETTINGS); | 1146 frame.WriteUInt16(SETTINGS); |
958 size_t settings_size = | 1147 size_t settings_size = |
959 SpdySettingsControlFrame::size() - SpdyFrame::kHeaderSize + | 1148 SpdySettingsControlFrame::size() - SpdyFrame::kHeaderSize + |
960 8 * values.size(); | 1149 8 * values.size(); |
961 frame.WriteUInt32(settings_size); | 1150 frame.WriteUInt32(settings_size); |
962 frame.WriteUInt32(values.size()); | 1151 frame.WriteUInt32(values.size()); |
963 SpdySettings::const_iterator it = values.begin(); | 1152 SpdySettings::const_iterator it = values.begin(); |
964 while (it != values.end()) { | 1153 while (it != values.end()) { |
965 frame.WriteUInt32(it->first.id_); | 1154 uint32 id_and_flags_wire = it->first.GetWireFormat(spdy_version_); |
1155 frame.WriteBytes(&id_and_flags_wire, 4); | |
966 frame.WriteUInt32(it->second); | 1156 frame.WriteUInt32(it->second); |
967 ++it; | 1157 ++it; |
968 } | 1158 } |
969 return reinterpret_cast<SpdySettingsControlFrame*>(frame.take()); | 1159 return reinterpret_cast<SpdySettingsControlFrame*>(frame.take()); |
970 } | 1160 } |
971 | 1161 |
972 /* static */ | 1162 SpdyPingControlFrame* SpdyFramer::CreatePingFrame(uint32 unique_id) const { |
973 SpdyNoOpControlFrame* SpdyFramer::CreateNopFrame() { | |
974 SpdyFrameBuilder frame(SpdyNoOpControlFrame::size()); | |
975 frame.WriteUInt16(kControlFlagMask | spdy_version_); | |
976 frame.WriteUInt16(NOOP); | |
977 frame.WriteUInt32(0); | |
978 return reinterpret_cast<SpdyNoOpControlFrame*>(frame.take()); | |
979 } | |
980 | |
981 /* static */ | |
982 SpdyPingControlFrame* SpdyFramer::CreatePingFrame(uint32 unique_id) { | |
983 SpdyFrameBuilder frame(SpdyPingControlFrame::size()); | 1163 SpdyFrameBuilder frame(SpdyPingControlFrame::size()); |
984 frame.WriteUInt16(kControlFlagMask | spdy_version_); | 1164 frame.WriteUInt16(kControlFlagMask | spdy_version_); |
985 frame.WriteUInt16(PING); | 1165 frame.WriteUInt16(PING); |
986 size_t ping_size = SpdyPingControlFrame::size() - SpdyFrame::kHeaderSize; | 1166 size_t ping_size = SpdyPingControlFrame::size() - SpdyFrame::kHeaderSize; |
987 frame.WriteUInt32(ping_size); | 1167 frame.WriteUInt32(ping_size); |
988 frame.WriteUInt32(unique_id); | 1168 frame.WriteUInt32(unique_id); |
989 return reinterpret_cast<SpdyPingControlFrame*>(frame.take()); | 1169 return reinterpret_cast<SpdyPingControlFrame*>(frame.take()); |
990 } | 1170 } |
991 | 1171 |
992 /* static */ | |
993 SpdyGoAwayControlFrame* SpdyFramer::CreateGoAway( | 1172 SpdyGoAwayControlFrame* SpdyFramer::CreateGoAway( |
994 SpdyStreamId last_accepted_stream_id) { | 1173 SpdyStreamId last_accepted_stream_id) const { |
995 DCHECK_EQ(0u, last_accepted_stream_id & ~kStreamIdMask); | 1174 DCHECK_EQ(0u, last_accepted_stream_id & ~kStreamIdMask); |
996 | 1175 |
997 SpdyFrameBuilder frame(SpdyGoAwayControlFrame::size()); | 1176 SpdyFrameBuilder frame(SpdyGoAwayControlFrame::size()); |
998 frame.WriteUInt16(kControlFlagMask | spdy_version_); | 1177 frame.WriteUInt16(kControlFlagMask | spdy_version_); |
999 frame.WriteUInt16(GOAWAY); | 1178 frame.WriteUInt16(GOAWAY); |
1000 size_t go_away_size = SpdyGoAwayControlFrame::size() - SpdyFrame::kHeaderSize; | 1179 size_t go_away_size = SpdyGoAwayControlFrame::size() - SpdyFrame::kHeaderSize; |
1001 frame.WriteUInt32(go_away_size); | 1180 frame.WriteUInt32(go_away_size); |
1002 frame.WriteUInt32(last_accepted_stream_id); | 1181 frame.WriteUInt32(last_accepted_stream_id); |
1003 return reinterpret_cast<SpdyGoAwayControlFrame*>(frame.take()); | 1182 return reinterpret_cast<SpdyGoAwayControlFrame*>(frame.take()); |
1004 } | 1183 } |
1005 | 1184 |
1006 SpdyHeadersControlFrame* SpdyFramer::CreateHeaders(SpdyStreamId stream_id, | 1185 SpdyHeadersControlFrame* SpdyFramer::CreateHeaders( |
1007 SpdyControlFlags flags, bool compressed, const SpdyHeaderBlock* headers) { | 1186 SpdyStreamId stream_id, |
1187 SpdyControlFlags flags, | |
1188 bool compressed, | |
1189 const SpdyHeaderBlock* headers) { | |
1008 // Basically the same as CreateSynReply(). | 1190 // Basically the same as CreateSynReply(). |
1009 DCHECK_GT(stream_id, 0u); | 1191 DCHECK_GT(stream_id, 0u); |
1010 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); | 1192 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); |
1011 | 1193 |
1012 // Find our length. | 1194 // Find our length. |
1013 size_t expected_frame_size = SpdyHeadersControlFrame::size() + | 1195 size_t expected_frame_size = SpdyHeadersControlFrame::size() + |
1014 GetSerializedLength(headers); | 1196 GetSerializedLength(headers); |
1197 // In SPDY 2, there were 2 unused bytes before payload. | |
1198 if (spdy_version_ < 3) { | |
1199 expected_frame_size += 2; | |
1200 } | |
1015 | 1201 |
1016 // Create our FlagsAndLength. | 1202 // Create our FlagsAndLength. |
1017 FlagsAndLength flags_length = CreateFlagsAndLength( | 1203 FlagsAndLength flags_length = CreateFlagsAndLength( |
1018 flags, | 1204 flags, |
1019 expected_frame_size - SpdyFrame::kHeaderSize); | 1205 expected_frame_size - SpdyFrame::kHeaderSize); |
1020 | 1206 |
1021 SpdyFrameBuilder frame(expected_frame_size); | 1207 SpdyFrameBuilder frame(expected_frame_size); |
1022 frame.WriteUInt16(kControlFlagMask | spdy_version_); | 1208 frame.WriteUInt16(kControlFlagMask | spdy_version_); |
1023 frame.WriteUInt16(HEADERS); | 1209 frame.WriteUInt16(HEADERS); |
1024 frame.WriteBytes(&flags_length, sizeof(flags_length)); | 1210 frame.WriteBytes(&flags_length, sizeof(flags_length)); |
1025 frame.WriteUInt32(stream_id); | 1211 frame.WriteUInt32(stream_id); |
1026 frame.WriteUInt16(0); // Unused | 1212 if (spdy_version_ < 3) { |
1213 frame.WriteUInt16(0); // Unused | |
1214 } | |
1027 WriteHeaderBlock(&frame, headers); | 1215 WriteHeaderBlock(&frame, headers); |
1028 DCHECK_EQ(static_cast<size_t>(frame.length()), expected_frame_size); | 1216 DCHECK_EQ(static_cast<size_t>(frame.length()), expected_frame_size); |
1029 | 1217 |
1030 scoped_ptr<SpdyHeadersControlFrame> headers_frame( | 1218 scoped_ptr<SpdyHeadersControlFrame> headers_frame( |
1031 reinterpret_cast<SpdyHeadersControlFrame*>(frame.take())); | 1219 reinterpret_cast<SpdyHeadersControlFrame*>(frame.take())); |
1032 if (compressed) { | 1220 if (compressed) { |
1033 return reinterpret_cast<SpdyHeadersControlFrame*>( | 1221 return reinterpret_cast<SpdyHeadersControlFrame*>( |
1034 CompressControlFrame(*headers_frame.get())); | 1222 CompressControlFrame(*headers_frame.get())); |
1035 } | 1223 } |
1036 return headers_frame.release(); | 1224 return headers_frame.release(); |
1037 } | 1225 } |
1038 | 1226 |
1039 /* static */ | |
1040 SpdyWindowUpdateControlFrame* SpdyFramer::CreateWindowUpdate( | 1227 SpdyWindowUpdateControlFrame* SpdyFramer::CreateWindowUpdate( |
1041 SpdyStreamId stream_id, | 1228 SpdyStreamId stream_id, |
1042 uint32 delta_window_size) { | 1229 uint32 delta_window_size) const { |
1043 DCHECK_GT(stream_id, 0u); | 1230 DCHECK_GT(stream_id, 0u); |
1044 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); | 1231 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); |
1045 DCHECK_GT(delta_window_size, 0u); | 1232 DCHECK_GT(delta_window_size, 0u); |
1046 DCHECK_LE(delta_window_size, spdy::kSpdyStreamMaximumWindowSize); | 1233 DCHECK_LE(delta_window_size, |
1234 static_cast<uint32>(spdy::kSpdyStreamMaximumWindowSize)); | |
1047 | 1235 |
1048 SpdyFrameBuilder frame(SpdyWindowUpdateControlFrame::size()); | 1236 SpdyFrameBuilder frame(SpdyWindowUpdateControlFrame::size()); |
1049 frame.WriteUInt16(kControlFlagMask | spdy_version_); | 1237 frame.WriteUInt16(kControlFlagMask | spdy_version_); |
1050 frame.WriteUInt16(WINDOW_UPDATE); | 1238 frame.WriteUInt16(WINDOW_UPDATE); |
1051 size_t window_update_size = SpdyWindowUpdateControlFrame::size() - | 1239 size_t window_update_size = SpdyWindowUpdateControlFrame::size() - |
1052 SpdyFrame::kHeaderSize; | 1240 SpdyFrame::kHeaderSize; |
1053 frame.WriteUInt32(window_update_size); | 1241 frame.WriteUInt32(window_update_size); |
1054 frame.WriteUInt32(stream_id); | 1242 frame.WriteUInt32(stream_id); |
1055 frame.WriteUInt32(delta_window_size); | 1243 frame.WriteUInt32(delta_window_size); |
1056 return reinterpret_cast<SpdyWindowUpdateControlFrame*>(frame.take()); | 1244 return reinterpret_cast<SpdyWindowUpdateControlFrame*>(frame.take()); |
1057 } | 1245 } |
1058 | 1246 |
1059 /* static */ | |
1060 SpdyCredentialControlFrame* SpdyFramer::CreateCredentialFrame( | 1247 SpdyCredentialControlFrame* SpdyFramer::CreateCredentialFrame( |
1061 const SpdyCredential& credential) { | 1248 const SpdyCredential& credential) const { |
1062 // Calculate the size of the frame by adding the size of the | 1249 // Calculate the size of the frame by adding the size of the |
1063 // variable length data to the size of the fixed length data. | 1250 // variable length data to the size of the fixed length data. |
1064 size_t frame_size = SpdyCredentialControlFrame::size() + | 1251 size_t frame_size = SpdyCredentialControlFrame::size() + |
1065 credential.proof.length(); | 1252 credential.proof.length(); |
1066 DCHECK_EQ(SpdyCredentialControlFrame::size(), 14u); | 1253 DCHECK_EQ(SpdyCredentialControlFrame::size(), 14u); |
1067 for (vector<std::string>::const_iterator cert = credential.certs.begin(); | 1254 for (std::vector<std::string>::const_iterator cert = credential.certs.begin(); |
1068 cert != credential.certs.end(); | 1255 cert != credential.certs.end(); |
1069 cert++) { | 1256 ++cert) { |
1070 frame_size += sizeof(uint32); // size of the cert_length field | 1257 frame_size += sizeof(uint32); // size of the cert_length field |
1071 frame_size += cert->length(); // size of the cert_data field | 1258 frame_size += cert->length(); // size of the cert_data field |
1072 } | 1259 } |
1073 size_t payload_size = frame_size - SpdyFrame::kHeaderSize; | 1260 size_t payload_size = frame_size - SpdyFrame::kHeaderSize; |
1074 | 1261 |
1075 SpdyFrameBuilder frame(frame_size); | 1262 SpdyFrameBuilder frame(frame_size); |
1076 // Create our FlagsAndLength. | 1263 // Create our FlagsAndLength. |
1077 SpdyControlFlags flags = spdy::CONTROL_FLAG_NONE; | 1264 SpdyControlFlags flags = CONTROL_FLAG_NONE; |
1078 FlagsAndLength flags_length = CreateFlagsAndLength(flags, payload_size); | 1265 FlagsAndLength flags_length = CreateFlagsAndLength(flags, payload_size); |
1079 | 1266 |
1080 frame.WriteUInt16(kControlFlagMask | spdy_version_); | 1267 frame.WriteUInt16(kControlFlagMask | spdy_version_); |
1081 frame.WriteUInt16(CREDENTIAL); | 1268 frame.WriteUInt16(CREDENTIAL); |
1082 frame.WriteBytes(&flags_length, sizeof(flags_length)); | 1269 frame.WriteBytes(&flags_length, sizeof(flags_length)); |
1083 frame.WriteUInt16(credential.slot); | 1270 frame.WriteUInt16(credential.slot); |
1084 frame.WriteUInt32(credential.proof.size()); | 1271 frame.WriteUInt32(credential.proof.size()); |
1085 frame.WriteBytes(credential.proof.c_str(), credential.proof.size()); | 1272 frame.WriteBytes(credential.proof.c_str(), credential.proof.size()); |
1086 for (vector<std::string>::const_iterator cert = credential.certs.begin(); | 1273 for (std::vector<std::string>::const_iterator cert = credential.certs.begin(); |
1087 cert != credential.certs.end(); | 1274 cert != credential.certs.end(); |
1088 cert++) { | 1275 ++cert) { |
1089 frame.WriteUInt32(cert->length()); | 1276 frame.WriteUInt32(cert->length()); |
1090 frame.WriteBytes(cert->c_str(), cert->length()); | 1277 frame.WriteBytes(cert->c_str(), cert->length()); |
1091 } | 1278 } |
1092 return reinterpret_cast<SpdyCredentialControlFrame*>(frame.take()); | 1279 return reinterpret_cast<SpdyCredentialControlFrame*>(frame.take()); |
1093 } | 1280 } |
1094 | 1281 |
1095 SpdyDataFrame* SpdyFramer::CreateDataFrame(SpdyStreamId stream_id, | 1282 SpdyDataFrame* SpdyFramer::CreateDataFrame(SpdyStreamId stream_id, |
1096 const char* data, | 1283 const char* data, |
1097 uint32 len, SpdyDataFlags flags) { | 1284 uint32 len, SpdyDataFlags flags) { |
1098 DCHECK_GT(stream_id, 0u); | |
1099 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); | 1285 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); |
1100 | 1286 |
1101 SpdyFrameBuilder frame(SpdyDataFrame::size() + len); | 1287 SpdyFrameBuilder frame(SpdyDataFrame::size() + len); |
1102 frame.WriteUInt32(stream_id); | 1288 frame.WriteUInt32(stream_id); |
1103 | 1289 |
1104 DCHECK_EQ(0u, len & ~static_cast<size_t>(kLengthMask)); | 1290 DCHECK_EQ(0u, len & ~static_cast<size_t>(kLengthMask)); |
1105 FlagsAndLength flags_length; | 1291 FlagsAndLength flags_length; |
1106 flags_length.length_ = htonl(len); | 1292 flags_length.length_ = htonl(len); |
1107 DCHECK_EQ(0, flags & ~kDataFlagsMask); | 1293 DCHECK_EQ(0, flags & ~kDataFlagsMask); |
1108 flags_length.flags_[0] = flags; | 1294 flags_length.flags_[0] = flags; |
1109 frame.WriteBytes(&flags_length, sizeof(flags_length)); | 1295 frame.WriteBytes(&flags_length, sizeof(flags_length)); |
1110 | 1296 |
1111 frame.WriteBytes(data, len); | 1297 frame.WriteBytes(data, len); |
1112 scoped_ptr<SpdyFrame> data_frame(frame.take()); | 1298 scoped_ptr<SpdyFrame> data_frame(frame.take()); |
1113 SpdyDataFrame* rv; | 1299 SpdyDataFrame* rv; |
1114 if (flags & DATA_FLAG_COMPRESSED) { | 1300 if (flags & DATA_FLAG_COMPRESSED) { |
1115 rv = reinterpret_cast<SpdyDataFrame*>(CompressFrame(*data_frame.get())); | 1301 LOG(DFATAL) << "DATA_FLAG_COMPRESSED invalid for " << display_protocol_ |
1116 } else { | 1302 << "."; |
1117 rv = reinterpret_cast<SpdyDataFrame*>(data_frame.release()); | |
1118 } | 1303 } |
1304 rv = reinterpret_cast<SpdyDataFrame*>(data_frame.release()); | |
1119 | 1305 |
1120 if (flags & DATA_FLAG_FIN) { | 1306 if (flags & DATA_FLAG_FIN) { |
1121 CleanupCompressorForStream(stream_id); | 1307 CleanupCompressorForStream(stream_id); |
1122 } | 1308 } |
1123 | 1309 |
1124 return rv; | 1310 return rv; |
1125 } | 1311 } |
1126 | 1312 |
1127 // The following compression setting are based on Brian Olson's analysis. See | 1313 // The following compression setting are based on Brian Olson's analysis. See |
1128 // https://groups.google.com/group/spdy-dev/browse_thread/thread/dfaf498542fac79 2 | 1314 // https://groups.google.com/group/spdy-dev/browse_thread/thread/dfaf498542fac79 2 |
1129 // for more details. | 1315 // for more details. |
1130 static const int kCompressorLevel = 9; | 1316 static const int kCompressorLevel = 9; |
1131 static const int kCompressorWindowSizeInBits = 11; | 1317 static const int kCompressorWindowSizeInBits = 11; |
1132 static const int kCompressorMemLevel = 1; | 1318 static const int kCompressorMemLevel = 1; |
1133 | 1319 |
1134 // This is just a hacked dictionary to use for shrinking HTTP-like headers. | |
1135 // TODO(mbelshe): Use a scientific methodology for computing the dictionary. | |
1136 const char SpdyFramer::kDictionary[] = | |
1137 "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-" | |
1138 "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi" | |
1139 "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser" | |
1140 "-agent10010120020120220320420520630030130230330430530630740040140240340440" | |
1141 "5406407408409410411412413414415416417500501502503504505accept-rangesageeta" | |
1142 "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic" | |
1143 "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran" | |
1144 "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati" | |
1145 "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo" | |
1146 "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe" | |
1147 "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic" | |
1148 "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1" | |
1149 ".1statusversionurl"; | |
1150 const int SpdyFramer::kDictionarySize = arraysize(kDictionary); | |
1151 | |
1152 SpdyFrame* SpdyFramer::CompressFrame(const SpdyFrame& frame) { | 1320 SpdyFrame* SpdyFramer::CompressFrame(const SpdyFrame& frame) { |
1153 if (frame.is_control_frame()) { | 1321 if (frame.is_control_frame()) { |
1154 return CompressControlFrame( | 1322 return CompressControlFrame( |
1155 reinterpret_cast<const SpdyControlFrame&>(frame)); | 1323 reinterpret_cast<const SpdyControlFrame&>(frame)); |
1156 } | 1324 } |
1157 return CompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame)); | 1325 return NULL; |
1158 } | |
1159 | |
1160 SpdyFrame* SpdyFramer::DecompressFrame(const SpdyFrame& frame) { | |
1161 if (frame.is_control_frame()) { | |
1162 return DecompressControlFrame( | |
1163 reinterpret_cast<const SpdyControlFrame&>(frame)); | |
1164 } | |
1165 return DecompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame)); | |
1166 } | 1326 } |
1167 | 1327 |
1168 bool SpdyFramer::IsCompressible(const SpdyFrame& frame) const { | 1328 bool SpdyFramer::IsCompressible(const SpdyFrame& frame) const { |
1169 // The important frames to compress are those which contain large | 1329 // The important frames to compress are those which contain large |
1170 // amounts of compressible data - namely the headers in the SYN_STREAM | 1330 // amounts of compressible data - namely the headers in the SYN_STREAM |
1171 // and SYN_REPLY. | 1331 // and SYN_REPLY. |
1172 // TODO(mbelshe): Reconcile this with the spec when the spec is | |
1173 // explicit about which frames compress and which do not. | |
1174 if (frame.is_control_frame()) { | 1332 if (frame.is_control_frame()) { |
1175 const SpdyControlFrame& control_frame = | 1333 const SpdyControlFrame& control_frame = |
1176 reinterpret_cast<const SpdyControlFrame&>(frame); | 1334 reinterpret_cast<const SpdyControlFrame&>(frame); |
1177 return control_frame.type() == SYN_STREAM || | 1335 return control_frame.type() == SYN_STREAM || |
1178 control_frame.type() == SYN_REPLY; | 1336 control_frame.type() == SYN_REPLY; |
1179 } | 1337 } |
1180 | 1338 |
1181 const SpdyDataFrame& data_frame = | 1339 // We don't compress Data frames. |
1182 reinterpret_cast<const SpdyDataFrame&>(frame); | 1340 return false; |
1183 return (data_frame.flags() & DATA_FLAG_COMPRESSED) != 0; | |
1184 } | 1341 } |
1185 | 1342 |
1186 z_stream* SpdyFramer::GetHeaderCompressor() { | 1343 z_stream* SpdyFramer::GetHeaderCompressor() { |
1187 if (header_compressor_.get()) | 1344 if (header_compressor_.get()) |
1188 return header_compressor_.get(); // Already initialized. | 1345 return header_compressor_.get(); // Already initialized. |
1189 | 1346 |
1190 header_compressor_.reset(new z_stream); | 1347 header_compressor_.reset(new z_stream); |
1191 memset(header_compressor_.get(), 0, sizeof(z_stream)); | 1348 memset(header_compressor_.get(), 0, sizeof(z_stream)); |
1192 | 1349 |
1193 int success = deflateInit2(header_compressor_.get(), | 1350 int success = deflateInit2(header_compressor_.get(), |
1194 kCompressorLevel, | 1351 kCompressorLevel, |
1195 Z_DEFLATED, | 1352 Z_DEFLATED, |
1196 kCompressorWindowSizeInBits, | 1353 kCompressorWindowSizeInBits, |
1197 kCompressorMemLevel, | 1354 kCompressorMemLevel, |
1198 Z_DEFAULT_STRATEGY); | 1355 Z_DEFAULT_STRATEGY); |
1199 if (success == Z_OK) | 1356 if (success == Z_OK) { |
1357 const char* dictionary = (spdy_version_ < 3) ? kV2Dictionary | |
1358 : kV3Dictionary; | |
1359 const int dictionary_size = (spdy_version_ < 3) ? kV2DictionarySize | |
1360 : kV3DictionarySize; | |
1200 success = deflateSetDictionary(header_compressor_.get(), | 1361 success = deflateSetDictionary(header_compressor_.get(), |
1201 reinterpret_cast<const Bytef*>(kDictionary), | 1362 reinterpret_cast<const Bytef*>(dictionary), |
1202 kDictionarySize); | 1363 dictionary_size); |
1364 } | |
1203 if (success != Z_OK) { | 1365 if (success != Z_OK) { |
1204 LOG(WARNING) << "deflateSetDictionary failure: " << success; | 1366 LOG(WARNING) << "deflateSetDictionary failure: " << success; |
1205 header_compressor_.reset(NULL); | 1367 header_compressor_.reset(NULL); |
1206 return NULL; | 1368 return NULL; |
1207 } | 1369 } |
1208 return header_compressor_.get(); | 1370 return header_compressor_.get(); |
1209 } | 1371 } |
1210 | 1372 |
1211 z_stream* SpdyFramer::GetHeaderDecompressor() { | 1373 z_stream* SpdyFramer::GetHeaderDecompressor() { |
1212 if (header_decompressor_.get()) | 1374 if (header_decompressor_.get()) |
1213 return header_decompressor_.get(); // Already initialized. | 1375 return header_decompressor_.get(); // Already initialized. |
1214 | 1376 |
1215 header_decompressor_.reset(new z_stream); | 1377 header_decompressor_.reset(new z_stream); |
1216 memset(header_decompressor_.get(), 0, sizeof(z_stream)); | 1378 memset(header_decompressor_.get(), 0, sizeof(z_stream)); |
1217 | 1379 |
1218 int success = inflateInit(header_decompressor_.get()); | 1380 int success = inflateInit(header_decompressor_.get()); |
1219 if (success != Z_OK) { | 1381 if (success != Z_OK) { |
1220 LOG(WARNING) << "inflateInit failure: " << success; | 1382 LOG(WARNING) << "inflateInit failure: " << success; |
1221 header_decompressor_.reset(NULL); | 1383 header_decompressor_.reset(NULL); |
1222 return NULL; | 1384 return NULL; |
1223 } | 1385 } |
1224 return header_decompressor_.get(); | 1386 return header_decompressor_.get(); |
1225 } | 1387 } |
1226 | 1388 |
1227 z_stream* SpdyFramer::GetStreamCompressor(SpdyStreamId stream_id) { | |
1228 CompressorMap::iterator it = stream_compressors_.find(stream_id); | |
1229 if (it != stream_compressors_.end()) | |
1230 return it->second; // Already initialized. | |
1231 | |
1232 scoped_ptr<z_stream> compressor(new z_stream); | |
1233 memset(compressor.get(), 0, sizeof(z_stream)); | |
1234 | |
1235 int success = deflateInit2(compressor.get(), | |
1236 kCompressorLevel, | |
1237 Z_DEFLATED, | |
1238 kCompressorWindowSizeInBits, | |
1239 kCompressorMemLevel, | |
1240 Z_DEFAULT_STRATEGY); | |
1241 if (success != Z_OK) { | |
1242 LOG(WARNING) << "deflateInit failure: " << success; | |
1243 return NULL; | |
1244 } | |
1245 return stream_compressors_[stream_id] = compressor.release(); | |
1246 } | |
1247 | |
1248 z_stream* SpdyFramer::GetStreamDecompressor(SpdyStreamId stream_id) { | 1389 z_stream* SpdyFramer::GetStreamDecompressor(SpdyStreamId stream_id) { |
1249 CompressorMap::iterator it = stream_decompressors_.find(stream_id); | 1390 CompressorMap::iterator it = stream_decompressors_.find(stream_id); |
1250 if (it != stream_decompressors_.end()) | 1391 if (it != stream_decompressors_.end()) |
1251 return it->second; // Already initialized. | 1392 return it->second; // Already initialized. |
1252 | 1393 |
1253 scoped_ptr<z_stream> decompressor(new z_stream); | 1394 scoped_ptr<z_stream> decompressor(new z_stream); |
1254 memset(decompressor.get(), 0, sizeof(z_stream)); | 1395 memset(decompressor.get(), 0, sizeof(z_stream)); |
1255 | 1396 |
1256 int success = inflateInit(decompressor.get()); | 1397 int success = inflateInit(decompressor.get()); |
1257 if (success != Z_OK) { | 1398 if (success != Z_OK) { |
(...skipping 23 matching lines...) Expand all Loading... | |
1281 } | 1422 } |
1282 break; | 1423 break; |
1283 case SYN_REPLY: | 1424 case SYN_REPLY: |
1284 { | 1425 { |
1285 const SpdySynReplyControlFrame& syn_frame = | 1426 const SpdySynReplyControlFrame& syn_frame = |
1286 reinterpret_cast<const SpdySynReplyControlFrame&>(frame); | 1427 reinterpret_cast<const SpdySynReplyControlFrame&>(frame); |
1287 frame_size = SpdySynReplyControlFrame::size(); | 1428 frame_size = SpdySynReplyControlFrame::size(); |
1288 *payload_length = syn_frame.header_block_len(); | 1429 *payload_length = syn_frame.header_block_len(); |
1289 *header_length = frame_size; | 1430 *header_length = frame_size; |
1290 *payload = frame.data() + *header_length; | 1431 *payload = frame.data() + *header_length; |
1432 // SPDY 2 had two bytes of unused space preceeding payload. | |
1433 if (spdy_version_ < 3) { | |
1434 *header_length += 2; | |
1435 *payload += 2; | |
1436 } | |
1291 } | 1437 } |
1292 break; | 1438 break; |
1293 case HEADERS: | 1439 case HEADERS: |
1294 { | 1440 { |
1295 const SpdyHeadersControlFrame& headers_frame = | 1441 const SpdyHeadersControlFrame& headers_frame = |
1296 reinterpret_cast<const SpdyHeadersControlFrame&>(frame); | 1442 reinterpret_cast<const SpdyHeadersControlFrame&>(frame); |
1297 frame_size = SpdyHeadersControlFrame::size(); | 1443 frame_size = SpdyHeadersControlFrame::size(); |
1298 *payload_length = headers_frame.header_block_len(); | 1444 *payload_length = headers_frame.header_block_len(); |
1299 *header_length = frame_size; | 1445 *header_length = frame_size; |
1300 *payload = frame.data() + *header_length; | 1446 *payload = frame.data() + *header_length; |
1447 // SPDY 2 had two bytes of unused space preceeding payload. | |
1448 if (spdy_version_ < 3) { | |
1449 *header_length += 2; | |
1450 *payload += 2; | |
1451 } | |
1301 } | 1452 } |
1302 break; | 1453 break; |
1303 default: | 1454 default: |
1304 // TODO(mbelshe): set an error? | 1455 // TODO(mbelshe): set an error? |
1305 return false; // We can't compress this frame! | 1456 return false; // We can't compress this frame! |
1306 } | 1457 } |
1307 } else { | 1458 } else { |
1308 frame_size = SpdyFrame::kHeaderSize; | 1459 frame_size = SpdyFrame::kHeaderSize; |
1309 *header_length = frame_size; | 1460 *header_length = frame_size; |
1310 *payload_length = frame.length(); | 1461 *payload_length = frame.length(); |
1311 *payload = frame.data() + SpdyFrame::kHeaderSize; | 1462 *payload = frame.data() + SpdyFrame::kHeaderSize; |
1312 } | 1463 } |
1313 return true; | 1464 return true; |
1314 } | 1465 } |
1315 | 1466 |
1316 SpdyControlFrame* SpdyFramer::CompressControlFrame( | 1467 SpdyControlFrame* SpdyFramer::CompressControlFrame( |
1317 const SpdyControlFrame& frame) { | 1468 const SpdyControlFrame& frame) { |
1318 z_stream* compressor = GetHeaderCompressor(); | 1469 z_stream* compressor = GetHeaderCompressor(); |
1319 if (!compressor) | 1470 if (!compressor) |
1320 return NULL; | 1471 return NULL; |
1321 return reinterpret_cast<SpdyControlFrame*>( | |
1322 CompressFrameWithZStream(frame, compressor)); | |
1323 } | |
1324 | 1472 |
1325 SpdyDataFrame* SpdyFramer::CompressDataFrame(const SpdyDataFrame& frame) { | |
1326 z_stream* compressor = GetStreamCompressor(frame.stream_id()); | |
1327 if (!compressor) | |
1328 return NULL; | |
1329 return reinterpret_cast<SpdyDataFrame*>( | |
1330 CompressFrameWithZStream(frame, compressor)); | |
1331 } | |
1332 | |
1333 SpdyControlFrame* SpdyFramer::DecompressControlFrame( | |
1334 const SpdyControlFrame& frame) { | |
1335 z_stream* decompressor = GetHeaderDecompressor(); | |
1336 if (!decompressor) { | |
1337 LOG(DFATAL) << "Couldn't get decompressor for handling control frame."; | |
1338 set_error(SPDY_DECOMPRESS_FAILURE); | |
1339 return NULL; | |
1340 } | |
1341 return reinterpret_cast<SpdyControlFrame*>( | |
1342 DecompressFrameWithZStream(frame, decompressor)); | |
1343 } | |
1344 | |
1345 SpdyDataFrame* SpdyFramer::DecompressDataFrame(const SpdyDataFrame& frame) { | |
1346 z_stream* decompressor = GetStreamDecompressor(frame.stream_id()); | |
1347 if (!decompressor) | |
1348 return NULL; | |
1349 return reinterpret_cast<SpdyDataFrame*>( | |
1350 DecompressFrameWithZStream(frame, decompressor)); | |
1351 } | |
1352 | |
1353 SpdyFrame* SpdyFramer::CompressFrameWithZStream(const SpdyFrame& frame, | |
1354 z_stream* compressor) { | |
1355 int payload_length; | 1473 int payload_length; |
1356 int header_length; | 1474 int header_length; |
1357 const char* payload; | 1475 const char* payload; |
1358 | 1476 |
1359 base::StatsCounter compressed_frames("spdy.CompressedFrames"); | 1477 base::StatsCounter compressed_frames("spdy.CompressedFrames"); |
1360 base::StatsCounter pre_compress_bytes("spdy.PreCompressSize"); | 1478 base::StatsCounter pre_compress_bytes("spdy.PreCompressSize"); |
1361 base::StatsCounter post_compress_bytes("spdy.PostCompressSize"); | 1479 base::StatsCounter post_compress_bytes("spdy.PostCompressSize"); |
1362 | 1480 |
1363 if (!enable_compression_) | 1481 if (!enable_compression_) |
1364 return DuplicateFrame(frame); | 1482 return reinterpret_cast<SpdyControlFrame*>(DuplicateFrame(frame)); |
1365 | 1483 |
1366 if (!GetFrameBoundaries(frame, &payload_length, &header_length, &payload)) | 1484 if (!GetFrameBoundaries(frame, &payload_length, &header_length, &payload)) |
1367 return NULL; | 1485 return NULL; |
1368 | 1486 |
1369 // Create an output frame. | 1487 // Create an output frame. |
1370 int compressed_max_size = deflateBound(compressor, payload_length); | 1488 int compressed_max_size = deflateBound(compressor, payload_length); |
1371 int new_frame_size = header_length + compressed_max_size; | 1489 int new_frame_size = header_length + compressed_max_size; |
1372 scoped_ptr<SpdyFrame> new_frame(new SpdyFrame(new_frame_size)); | 1490 if ((frame.type() == SYN_REPLY || frame.type() == HEADERS) && |
1491 spdy_version_ < 3) { | |
1492 new_frame_size += 2; | |
1493 } | |
1494 DCHECK_GE(new_frame_size, | |
1495 static_cast<int>(frame.length() + SpdyFrame::kHeaderSize)); | |
1496 scoped_ptr<SpdyControlFrame> new_frame(new SpdyControlFrame(new_frame_size)); | |
1373 memcpy(new_frame->data(), frame.data(), | 1497 memcpy(new_frame->data(), frame.data(), |
1374 frame.length() + SpdyFrame::kHeaderSize); | 1498 frame.length() + SpdyFrame::kHeaderSize); |
1375 | 1499 |
1376 compressor->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload)); | 1500 compressor->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload)); |
1377 compressor->avail_in = payload_length; | 1501 compressor->avail_in = payload_length; |
1378 compressor->next_out = reinterpret_cast<Bytef*>(new_frame->data()) + | 1502 compressor->next_out = reinterpret_cast<Bytef*>(new_frame->data()) + |
1379 header_length; | 1503 header_length; |
1380 compressor->avail_out = compressed_max_size; | 1504 compressor->avail_out = compressed_max_size; |
1381 | 1505 |
1382 // Data packets have a 'compressed' flag. | 1506 // Data packets have a 'compressed' flag. |
1507 // TODO(hkhalil): Remove post code-yellow. It's impossible to execute this | |
1508 // branch given that SpdyControlFrame::is_control_frame always returns true. | |
1509 DCHECK(new_frame->is_control_frame()); | |
1383 if (!new_frame->is_control_frame()) { | 1510 if (!new_frame->is_control_frame()) { |
1384 SpdyDataFrame* data_frame = | 1511 SpdyDataFrame* data_frame = |
1385 reinterpret_cast<SpdyDataFrame*>(new_frame.get()); | 1512 reinterpret_cast<SpdyDataFrame*>(new_frame.get()); |
1386 data_frame->set_flags(data_frame->flags() | DATA_FLAG_COMPRESSED); | 1513 data_frame->set_flags(data_frame->flags() | DATA_FLAG_COMPRESSED); |
1387 } | 1514 } |
1388 | 1515 |
1389 // Make sure that all the data we pass to zlib is defined. | 1516 // Make sure that all the data we pass to zlib is defined. |
1390 // This way, all Valgrind reports on the compressed data are zlib's fault. | 1517 // This way, all Valgrind reports on the compressed data are zlib's fault. |
1391 (void)VALGRIND_CHECK_MEM_IS_DEFINED(compressor->next_in, | 1518 (void)VALGRIND_CHECK_MEM_IS_DEFINED(compressor->next_in, |
1392 compressor->avail_in); | 1519 compressor->avail_in); |
(...skipping 16 matching lines...) Expand all Loading... | |
1409 header_length + compressed_size - SpdyFrame::kHeaderSize); | 1536 header_length + compressed_size - SpdyFrame::kHeaderSize); |
1410 | 1537 |
1411 pre_compress_bytes.Add(payload_length); | 1538 pre_compress_bytes.Add(payload_length); |
1412 post_compress_bytes.Add(new_frame->length()); | 1539 post_compress_bytes.Add(new_frame->length()); |
1413 | 1540 |
1414 compressed_frames.Increment(); | 1541 compressed_frames.Increment(); |
1415 | 1542 |
1416 return new_frame.release(); | 1543 return new_frame.release(); |
1417 } | 1544 } |
1418 | 1545 |
1419 SpdyFrame* SpdyFramer::DecompressFrameWithZStream(const SpdyFrame& frame, | |
1420 z_stream* decompressor) { | |
1421 int payload_length; | |
1422 int header_length; | |
1423 const char* payload; | |
1424 | |
1425 base::StatsCounter decompressed_frames("spdy.DecompressedFrames"); | |
1426 base::StatsCounter pre_decompress_bytes("spdy.PreDeCompressSize"); | |
1427 base::StatsCounter post_decompress_bytes("spdy.PostDeCompressSize"); | |
1428 | |
1429 if (!enable_compression_) | |
1430 return DuplicateFrame(frame); | |
1431 | |
1432 if (!GetFrameBoundaries(frame, &payload_length, &header_length, &payload)) | |
1433 return NULL; | |
1434 | |
1435 if (!frame.is_control_frame()) { | |
1436 const SpdyDataFrame& data_frame = | |
1437 reinterpret_cast<const SpdyDataFrame&>(frame); | |
1438 if ((data_frame.flags() & DATA_FLAG_COMPRESSED) == 0) | |
1439 return DuplicateFrame(frame); | |
1440 } | |
1441 | |
1442 // Create an output frame. Assume it does not need to be longer than | |
1443 // the input data. | |
1444 size_t decompressed_max_size = kControlFrameBufferInitialSize; | |
1445 int new_frame_size = header_length + decompressed_max_size; | |
1446 if (frame.length() > decompressed_max_size) | |
1447 return NULL; | |
1448 scoped_ptr<SpdyFrame> new_frame(new SpdyFrame(new_frame_size)); | |
1449 memcpy(new_frame->data(), frame.data(), | |
1450 frame.length() + SpdyFrame::kHeaderSize); | |
1451 | |
1452 decompressor->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload)); | |
1453 decompressor->avail_in = payload_length; | |
1454 decompressor->next_out = reinterpret_cast<Bytef*>(new_frame->data()) + | |
1455 header_length; | |
1456 decompressor->avail_out = decompressed_max_size; | |
1457 | |
1458 int rv = inflate(decompressor, Z_SYNC_FLUSH); | |
1459 if (rv == Z_NEED_DICT) { | |
1460 // Need to try again with the right dictionary. | |
1461 if (decompressor->adler == kDictionaryId) { | |
1462 rv = inflateSetDictionary(decompressor, | |
1463 (const Bytef*)SpdyFramer::kDictionary, | |
1464 SpdyFramer::kDictionarySize); | |
1465 if (rv == Z_OK) | |
1466 rv = inflate(decompressor, Z_SYNC_FLUSH); | |
1467 } | |
1468 } | |
1469 if (rv != Z_OK) { // How can we know that it decompressed everything? | |
1470 LOG(WARNING) << "inflate failure: " << rv; | |
1471 return NULL; | |
1472 } | |
1473 | |
1474 // Unset the compressed flag for data frames. | |
1475 if (!new_frame->is_control_frame()) { | |
1476 SpdyDataFrame* data_frame = | |
1477 reinterpret_cast<SpdyDataFrame*>(new_frame.get()); | |
1478 data_frame->set_flags(data_frame->flags() & ~DATA_FLAG_COMPRESSED); | |
1479 } | |
1480 | |
1481 int decompressed_size = decompressed_max_size - decompressor->avail_out; | |
1482 new_frame->set_length( | |
1483 header_length + decompressed_size - SpdyFrame::kHeaderSize); | |
1484 | |
1485 // If there is data left, then the frame didn't fully decompress. This | |
1486 // means that there is stranded data at the end of this frame buffer which | |
1487 // will be ignored. | |
1488 DCHECK_EQ(decompressor->avail_in, 0u); | |
1489 | |
1490 pre_decompress_bytes.Add(frame.length()); | |
1491 post_decompress_bytes.Add(new_frame->length()); | |
1492 | |
1493 decompressed_frames.Increment(); | |
1494 | |
1495 return new_frame.release(); | |
1496 } | |
1497 | |
1498 // Incrementally decompress the control frame's header block, feeding the | 1546 // Incrementally decompress the control frame's header block, feeding the |
1499 // result to the visitor in chunks. Continue this until the visitor | 1547 // result to the visitor in chunks. Continue this until the visitor |
1500 // indicates that it cannot process any more data, or (more commonly) we | 1548 // indicates that it cannot process any more data, or (more commonly) we |
1501 // run out of data to deliver. | 1549 // run out of data to deliver. |
1502 bool SpdyFramer::IncrementallyDecompressControlFrameHeaderData( | 1550 bool SpdyFramer::IncrementallyDecompressControlFrameHeaderData( |
1503 const SpdyControlFrame* control_frame, | 1551 const SpdyControlFrame* control_frame, |
1504 const char* data, | 1552 const char* data, |
1505 size_t len) { | 1553 size_t len) { |
1506 // Get a decompressor or set error. | 1554 // Get a decompressor or set error. |
1507 z_stream* decomp = GetHeaderDecompressor(); | 1555 z_stream* decomp = GetHeaderDecompressor(); |
1508 if (decomp == NULL) { | 1556 if (decomp == NULL) { |
1509 LOG(DFATAL) << "Couldn't get decompressor for handling compressed headers."; | 1557 LOG(DFATAL) << "Couldn't get decompressor for handling compressed headers."; |
1510 set_error(SPDY_DECOMPRESS_FAILURE); | 1558 set_error(SPDY_DECOMPRESS_FAILURE); |
1511 return false; | 1559 return false; |
1512 } | 1560 } |
1513 | 1561 |
1514 bool processed_successfully = true; | 1562 bool processed_successfully = true; |
1515 char buffer[kHeaderDataChunkMaxSize]; | 1563 char buffer[kHeaderDataChunkMaxSize]; |
1516 | 1564 |
1517 decomp->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data)); | 1565 decomp->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data)); |
1518 decomp->avail_in = len; | 1566 decomp->avail_in = len; |
1519 const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame); | 1567 const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame); |
1520 DCHECK_LT(0u, stream_id); | 1568 DCHECK_LT(0u, stream_id); |
1521 while (decomp->avail_in > 0 && processed_successfully) { | 1569 while (decomp->avail_in > 0 && processed_successfully) { |
1522 decomp->next_out = reinterpret_cast<Bytef*>(buffer); | 1570 decomp->next_out = reinterpret_cast<Bytef*>(buffer); |
1523 decomp->avail_out = arraysize(buffer); | 1571 decomp->avail_out = arraysize(buffer); |
1524 int rv = DecompressHeaderBlockInZStream(decomp); | 1572 |
1525 if (rv != Z_OK && rv != Z_BUF_ERROR) { | 1573 int rv = inflate(decomp, Z_SYNC_FLUSH); |
1526 set_error(SPDY_DECOMPRESS_FAILURE); | 1574 if (rv == Z_NEED_DICT) { |
1527 DLOG(WARNING) << "inflate failure: " << rv; | 1575 const char* dictionary = (spdy_version_ < 3) ? kV2Dictionary |
1528 processed_successfully = false; | 1576 : kV3Dictionary; |
1529 } else { | 1577 const int dictionary_size = (spdy_version_ < 3) ? kV2DictionarySize |
1578 : kV3DictionarySize; | |
1579 const uLong dictionary_id = (spdy_version_ < 3) ? kV2DictionaryId | |
1580 : kV3DictionaryId; | |
1581 // Need to try again with the right dictionary. | |
1582 if (decomp->adler == dictionary_id) { | |
1583 rv = inflateSetDictionary(decomp, | |
1584 reinterpret_cast<const Bytef*>(dictionary), | |
1585 dictionary_size); | |
1586 if (rv == Z_OK) | |
1587 rv = inflate(decomp, Z_SYNC_FLUSH); | |
1588 } | |
1589 } | |
1590 | |
1591 // Inflate will generate a Z_BUF_ERROR if it runs out of input | |
1592 // without producing any output. The input is consumed and | |
1593 // buffered internally by zlib so we can detect this condition by | |
1594 // checking if avail_in is 0 after the call to inflate. | |
1595 bool input_exhausted = ((rv == Z_BUF_ERROR) && (decomp->avail_in == 0)); | |
1596 if ((rv == Z_OK) || input_exhausted) { | |
1530 size_t decompressed_len = arraysize(buffer) - decomp->avail_out; | 1597 size_t decompressed_len = arraysize(buffer) - decomp->avail_out; |
1531 if (decompressed_len > 0) { | 1598 if (decompressed_len > 0) { |
1532 processed_successfully = visitor_->OnControlFrameHeaderData( | 1599 processed_successfully = visitor_->OnControlFrameHeaderData( |
1533 stream_id, buffer, decompressed_len); | 1600 stream_id, buffer, decompressed_len); |
1534 } | 1601 } |
1535 if (!processed_successfully) { | 1602 if (!processed_successfully) { |
1536 // Assume that the problem was the header block was too large for the | 1603 // Assume that the problem was the header block was too large for the |
1537 // visitor. | 1604 // visitor. |
1538 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE); | 1605 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE); |
1539 } | 1606 } |
1607 } else { | |
1608 DLOG(WARNING) << "inflate failure: " << rv << " " << len; | |
1609 set_error(SPDY_DECOMPRESS_FAILURE); | |
1610 processed_successfully = false; | |
1540 } | 1611 } |
1541 } | 1612 } |
1542 return processed_successfully; | 1613 return processed_successfully; |
1543 } | 1614 } |
1544 | 1615 |
1545 bool SpdyFramer::IncrementallyDeliverControlFrameHeaderData( | 1616 bool SpdyFramer::IncrementallyDeliverControlFrameHeaderData( |
1546 const SpdyControlFrame* control_frame, const char* data, size_t len) { | 1617 const SpdyControlFrame* control_frame, const char* data, size_t len) { |
1547 bool read_successfully = true; | 1618 bool read_successfully = true; |
1548 const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame); | 1619 const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame); |
1549 DCHECK_LT(0u, stream_id); | |
1550 while (read_successfully && len > 0) { | 1620 while (read_successfully && len > 0) { |
1551 size_t bytes_to_deliver = std::min(len, kHeaderDataChunkMaxSize); | 1621 size_t bytes_to_deliver = std::min(len, kHeaderDataChunkMaxSize); |
1552 read_successfully = visitor_->OnControlFrameHeaderData(stream_id, data, | 1622 read_successfully = visitor_->OnControlFrameHeaderData(stream_id, data, |
1553 bytes_to_deliver); | 1623 bytes_to_deliver); |
1554 data += bytes_to_deliver; | 1624 data += bytes_to_deliver; |
1555 len -= bytes_to_deliver; | 1625 len -= bytes_to_deliver; |
1556 if (!read_successfully) { | 1626 if (!read_successfully) { |
1557 // Assume that the problem was the header block was too large for the | 1627 // Assume that the problem was the header block was too large for the |
1558 // visitor. | 1628 // visitor. |
1559 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE); | 1629 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1615 switch (type) { | 1685 switch (type) { |
1616 case SYN_STREAM: | 1686 case SYN_STREAM: |
1617 return SpdySynStreamControlFrame::size(); | 1687 return SpdySynStreamControlFrame::size(); |
1618 case SYN_REPLY: | 1688 case SYN_REPLY: |
1619 return SpdySynReplyControlFrame::size(); | 1689 return SpdySynReplyControlFrame::size(); |
1620 case RST_STREAM: | 1690 case RST_STREAM: |
1621 return SpdyRstStreamControlFrame::size(); | 1691 return SpdyRstStreamControlFrame::size(); |
1622 case SETTINGS: | 1692 case SETTINGS: |
1623 return SpdySettingsControlFrame::size(); | 1693 return SpdySettingsControlFrame::size(); |
1624 case NOOP: | 1694 case NOOP: |
1625 return SpdyNoOpControlFrame::size(); | 1695 // Even though NOOP is no longer supported, we still correctly report its |
1696 // size so that it can be handled correctly as incoming data if | |
1697 // implementations so desire. | |
1698 return SpdyFrame::kHeaderSize; | |
1626 case PING: | 1699 case PING: |
1627 return SpdyPingControlFrame::size(); | 1700 return SpdyPingControlFrame::size(); |
1628 case GOAWAY: | 1701 case GOAWAY: |
1629 return SpdyGoAwayControlFrame::size(); | 1702 return SpdyGoAwayControlFrame::size(); |
1630 case HEADERS: | 1703 case HEADERS: |
1631 return SpdyHeadersControlFrame::size(); | 1704 return SpdyHeadersControlFrame::size(); |
1632 case WINDOW_UPDATE: | 1705 case WINDOW_UPDATE: |
1633 return SpdyWindowUpdateControlFrame::size(); | 1706 return SpdyWindowUpdateControlFrame::size(); |
1634 case CREDENTIAL: | 1707 case CREDENTIAL: |
1635 return SpdyCredentialControlFrame::size(); | 1708 return SpdyCredentialControlFrame::size(); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1675 case PING: | 1748 case PING: |
1676 case GOAWAY: | 1749 case GOAWAY: |
1677 case CREDENTIAL: | 1750 case CREDENTIAL: |
1678 case NUM_CONTROL_FRAME_TYPES: // makes compiler happy | 1751 case NUM_CONTROL_FRAME_TYPES: // makes compiler happy |
1679 break; | 1752 break; |
1680 } | 1753 } |
1681 } | 1754 } |
1682 return stream_id; | 1755 return stream_id; |
1683 } | 1756 } |
1684 | 1757 |
1685 size_t SpdyFramer::BytesSafeToRead() const { | |
1686 switch (state_) { | |
1687 case SPDY_ERROR: | |
1688 case SPDY_DONE: | |
1689 case SPDY_AUTO_RESET: | |
1690 case SPDY_RESET: | |
1691 return 0; | |
1692 case SPDY_READING_COMMON_HEADER: | |
1693 DCHECK_LT(current_frame_len_, | |
1694 static_cast<size_t>(SpdyFrame::kHeaderSize)); | |
1695 return SpdyFrame::kHeaderSize - current_frame_len_; | |
1696 // TODO(rtenneti): Add support for SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK | |
1697 // and SPDY_CONTROL_FRAME_HEADER_BLOCK. | |
1698 case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK: | |
1699 case SPDY_CONTROL_FRAME_HEADER_BLOCK: | |
1700 return 0; | |
1701 case SPDY_CONTROL_FRAME_PAYLOAD: | |
1702 case SPDY_CREDENTIAL_FRAME_PAYLOAD: | |
1703 case SPDY_IGNORE_REMAINING_PAYLOAD: | |
1704 case SPDY_FORWARD_STREAM_FRAME: | |
1705 return remaining_data_; | |
1706 } | |
1707 // We should never get to here. | |
1708 return 0; | |
1709 } | |
1710 | |
1711 void SpdyFramer::set_enable_compression(bool value) { | 1758 void SpdyFramer::set_enable_compression(bool value) { |
1712 enable_compression_ = value; | 1759 enable_compression_ = value; |
1713 } | 1760 } |
1714 | 1761 |
1762 void SpdyFramer::set_validate_control_frame_sizes(bool value) { | |
1763 validate_control_frame_sizes_ = value; | |
1764 } | |
1765 | |
1715 void SpdyFramer::set_enable_compression_default(bool value) { | 1766 void SpdyFramer::set_enable_compression_default(bool value) { |
1716 compression_default_ = value; | 1767 compression_default_ = value; |
1717 } | 1768 } |
1718 | 1769 |
1719 void SpdyFramer::set_validate_control_frame_sizes(bool value) { | |
1720 validate_control_frame_sizes_ = value; | |
1721 } | |
1722 | |
1723 } // namespace spdy | 1770 } // namespace spdy |
OLD | NEW |