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