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