• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // 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-
7 // prone.
8 
9 #include "net/spdy/spdy_framer.h"
10 
11 #include "base/memory/scoped_ptr.h"
12 #include "base/metrics/stats_counters.h"
13 #ifndef ANDROID
14 #include "base/third_party/valgrind/memcheck.h"
15 #endif
16 #include "net/spdy/spdy_frame_builder.h"
17 #include "net/spdy/spdy_bitmasks.h"
18 
19 #if defined(USE_SYSTEM_ZLIB)
20 #include <zlib.h>
21 #else
22 #include "third_party/zlib/zlib.h"
23 #endif
24 
25 namespace {
26 
27 // The following compression setting are based on Brian Olson's analysis. See
28 // https://groups.google.com/group/spdy-dev/browse_thread/thread/dfaf498542fac792
29 // for more details.
30 const int kCompressorLevel = 9;
31 const int kCompressorWindowSizeInBits = 11;
32 const int kCompressorMemLevel = 1;
33 
34 // Adler ID for the SPDY header compressor dictionary.
35 uLong dictionary_id = 0;
36 
37 }  // namespace
38 
39 namespace spdy {
40 
41 // This is just a hacked dictionary to use for shrinking HTTP-like headers.
42 // TODO(mbelshe): Use a scientific methodology for computing the dictionary.
43 const char SpdyFramer::kDictionary[] =
44   "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
45   "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
46   "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
47   "-agent10010120020120220320420520630030130230330430530630740040140240340440"
48   "5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
49   "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
50   "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
51   "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
52   "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
53   "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
54   "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
55   "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
56   ".1statusversionurl";
57 const int SpdyFramer::kDictionarySize = arraysize(kDictionary);
58 
59 // By default is compression on or off.
60 bool SpdyFramer::compression_default_ = true;
61 int SpdyFramer::spdy_version_ = kSpdyProtocolVersion;
62 
63 // The initial size of the control frame buffer; this is used internally
64 // as we parse through control frames. (It is exposed here for unit test
65 // purposes.)
66 size_t SpdyFramer::kControlFrameBufferInitialSize = 8 * 1024;
67 
68 // The maximum size of the control frame buffer that we support.
69 // TODO(mbelshe): We should make this stream-based so there are no limits.
70 size_t SpdyFramer::kControlFrameBufferMaxSize = 16 * 1024;
71 
72 const SpdyStreamId SpdyFramer::kInvalidStream = -1;
73 const size_t SpdyFramer::kHeaderDataChunkMaxSize = 1024;
74 
75 #ifdef DEBUG_SPDY_STATE_CHANGES
76 #define CHANGE_STATE(newstate) \
77 { \
78   do { \
79     LOG(INFO) << "Changing state from: " \
80       << StateToString(state_) \
81       << " to " << StateToString(newstate) << "\n"; \
82     state_ = newstate; \
83   } while (false); \
84 }
85 #else
86 #define CHANGE_STATE(newstate) (state_ = newstate)
87 #endif
88 
DecompressHeaderBlockInZStream(z_stream * decompressor)89 int DecompressHeaderBlockInZStream(z_stream* decompressor) {
90   int rv = inflate(decompressor, Z_SYNC_FLUSH);
91   if (rv == Z_NEED_DICT) {
92     // Need to try again with the right dictionary.
93     if (decompressor->adler == dictionary_id) {
94       rv = inflateSetDictionary(decompressor,
95                                 (const Bytef*)SpdyFramer::kDictionary,
96                                 SpdyFramer::kDictionarySize);
97       if (rv == Z_OK)
98         rv = inflate(decompressor, Z_SYNC_FLUSH);
99     }
100   }
101   return rv;
102 }
103 
104 // Retrieve serialized length of SpdyHeaderBlock.
GetSerializedLength(const SpdyHeaderBlock * headers)105 size_t GetSerializedLength(const SpdyHeaderBlock* headers) {
106   size_t total_length = SpdyControlFrame::kNumNameValuePairsSize;
107   SpdyHeaderBlock::const_iterator it;
108   for (it = headers->begin(); it != headers->end(); ++it) {
109     // We add space for the length of the name and the length of the value as
110     // well as the length of the name and the length of the value.
111     total_length += SpdyControlFrame::kLengthOfNameSize +
112                     it->first.size() +
113                     SpdyControlFrame::kLengthOfValueSize +
114                     it->second.size();
115   }
116   return total_length;
117 }
118 
119 // Serializes a SpdyHeaderBlock.
WriteHeaderBlock(SpdyFrameBuilder * frame,const SpdyHeaderBlock * headers)120 void WriteHeaderBlock(SpdyFrameBuilder* frame, const SpdyHeaderBlock* headers) {
121   frame->WriteUInt16(headers->size());  // Number of headers.
122   SpdyHeaderBlock::const_iterator it;
123   for (it = headers->begin(); it != headers->end(); ++it) {
124     bool wrote_header;
125     wrote_header = frame->WriteString(it->first);
126     wrote_header &= frame->WriteString(it->second);
127     DCHECK(wrote_header);
128   }
129 }
130 
131 // Creates a FlagsAndLength.
CreateFlagsAndLength(SpdyControlFlags flags,size_t length)132 FlagsAndLength CreateFlagsAndLength(SpdyControlFlags flags, size_t length) {
133   DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask));
134   FlagsAndLength flags_length;
135   flags_length.length_ = htonl(static_cast<uint32>(length));
136   DCHECK_EQ(0, flags & ~kControlFlagsMask);
137   flags_length.flags_[0] = flags;
138   return flags_length;
139 }
140 
SpdyFramer()141 SpdyFramer::SpdyFramer()
142     : state_(SPDY_RESET),
143       error_code_(SPDY_NO_ERROR),
144       remaining_data_(0),
145       remaining_control_payload_(0),
146       remaining_control_header_(0),
147       current_frame_buffer_(NULL),
148       current_frame_len_(0),
149       current_frame_capacity_(0),
150       validate_control_frame_sizes_(true),
151       enable_compression_(compression_default_),
152       visitor_(NULL) {
153 }
154 
~SpdyFramer()155 SpdyFramer::~SpdyFramer() {
156   if (header_compressor_.get()) {
157     deflateEnd(header_compressor_.get());
158   }
159   if (header_decompressor_.get()) {
160     inflateEnd(header_decompressor_.get());
161   }
162   CleanupStreamCompressorsAndDecompressors();
163   delete [] current_frame_buffer_;
164 }
165 
StatusCodeToString(int status_code)166 const char* SpdyFramer::StatusCodeToString(int status_code) {
167   switch (status_code) {
168     case INVALID:
169       return "INVALID";
170     case PROTOCOL_ERROR:
171       return "PROTOCOL_ERROR";
172     case INVALID_STREAM:
173       return "INVALID_STREAM";
174     case REFUSED_STREAM:
175       return "REFUSED_STREAM";
176     case UNSUPPORTED_VERSION:
177       return "UNSUPPORTED_VERSION";
178     case CANCEL:
179       return "CANCEL";
180     case INTERNAL_ERROR:
181       return "INTERNAL_ERROR";
182     case FLOW_CONTROL_ERROR:
183       return "FLOW_CONTROL_ERROR";
184   }
185   return "UNKNOWN_STATUS";
186 }
187 
ControlTypeToString(SpdyControlType type)188 const char* SpdyFramer::ControlTypeToString(SpdyControlType type) {
189   switch (type) {
190     case SYN_STREAM:
191       return "SYN_STREAM";
192     case SYN_REPLY:
193       return "SYN_REPLY";
194     case RST_STREAM:
195       return "RST_STREAM";
196     case SETTINGS:
197       return "SETTINGS";
198     case NOOP:
199       return "NOOP";
200     case PING:
201       return "PING";
202     case GOAWAY:
203       return "GOAWAY";
204     case HEADERS:
205       return "HEADERS";
206     case WINDOW_UPDATE:
207       return "WINDOW_UPDATE";
208     case NUM_CONTROL_FRAME_TYPES:
209       break;
210   }
211   return "UNKNOWN_CONTROL_TYPE";
212 }
213 
ProcessInput(const char * data,size_t len)214 size_t SpdyFramer::ProcessInput(const char* data, size_t len) {
215   DCHECK(visitor_);
216   DCHECK(data);
217 
218   size_t original_len = len;
219   while (len != 0) {
220     switch (state_) {
221       case SPDY_ERROR:
222       case SPDY_DONE:
223         goto bottom;
224 
225       case SPDY_AUTO_RESET:
226       case SPDY_RESET:
227         Reset();
228         CHANGE_STATE(SPDY_READING_COMMON_HEADER);
229         continue;
230 
231       case SPDY_READING_COMMON_HEADER: {
232         size_t bytes_read = ProcessCommonHeader(data, len);
233         len -= bytes_read;
234         data += bytes_read;
235         continue;
236       }
237 
238       // Arguably, this case is not necessary, as no bytes are consumed here.
239       // I felt it was a nice partitioning, however (which probably indicates
240       // that it should be refactored into its own function!)
241       // TODO(hkhalil): Remove -- while loop above prevents proper handling of
242       // zero-length control frames.
243       case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER:
244         ProcessControlFrameHeader();
245         continue;
246 
247       case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK: {
248         // Control frames that contain header blocks (SYN_STREAM, SYN_REPLY,
249         // HEADERS) take a different path through the state machine - they
250         // will go:
251         //   1. SPDY_INTERPRET_CONTROL_FRAME_COMMON HEADER
252         //   2. SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK
253         //   3. SPDY_CONTROL_FRAME_HEADER_BLOCK
254         //
255         //  All other control frames will use the alternate route:
256         //   1. SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER
257         //   2. SPDY_CONTROL_FRAME_PAYLOAD
258         int bytes_read = ProcessControlFrameBeforeHeaderBlock(data, len);
259         len -= bytes_read;
260         data += bytes_read;
261         continue;
262       }
263 
264       case SPDY_CONTROL_FRAME_HEADER_BLOCK: {
265         int bytes_read = ProcessControlFrameHeaderBlock(data, len);
266         len -= bytes_read;
267         data += bytes_read;
268         continue;
269       }
270 
271       case SPDY_CONTROL_FRAME_PAYLOAD: {
272         size_t bytes_read = ProcessControlFramePayload(data, len);
273         len -= bytes_read;
274         data += bytes_read;
275       }
276         // intentional fallthrough
277       case SPDY_IGNORE_REMAINING_PAYLOAD:
278         // control frame has too-large payload
279         // intentional fallthrough
280       case SPDY_FORWARD_STREAM_FRAME: {
281         size_t bytes_read = ProcessDataFramePayload(data, len);
282         len -= bytes_read;
283         data += bytes_read;
284         continue;
285       }
286       default:
287         break;
288     }
289   }
290  bottom:
291   return original_len - len;
292 }
293 
Reset()294 void SpdyFramer::Reset() {
295   state_ = SPDY_RESET;
296   error_code_ = SPDY_NO_ERROR;
297   remaining_data_ = 0;
298   remaining_control_payload_ = 0;
299   remaining_control_header_ = 0;
300   current_frame_len_ = 0;
301   if (current_frame_capacity_ != kControlFrameBufferInitialSize) {
302     delete [] current_frame_buffer_;
303     current_frame_buffer_ = 0;
304     current_frame_capacity_ = 0;
305     ExpandControlFrameBuffer(kControlFrameBufferInitialSize);
306   }
307 }
308 
ParseHeaderBlock(const SpdyFrame * frame,SpdyHeaderBlock * block)309 bool SpdyFramer::ParseHeaderBlock(const SpdyFrame* frame,
310                                   SpdyHeaderBlock* block) {
311   SpdyControlFrame control_frame(frame->data(), false);
312   uint32 type = control_frame.type();
313   if (type != SYN_STREAM && type != SYN_REPLY && type != HEADERS)
314     return false;
315 
316   // Find the header data within the control frame.
317   scoped_ptr<SpdyFrame> decompressed_frame(DecompressFrame(*frame));
318   if (!decompressed_frame.get())
319     return false;
320 
321   const char *header_data = NULL;
322   int header_length = 0;
323 
324   switch (type) {
325     case SYN_STREAM:
326       {
327         SpdySynStreamControlFrame syn_frame(decompressed_frame->data(), false);
328         header_data = syn_frame.header_block();
329         header_length = syn_frame.header_block_len();
330       }
331       break;
332     case SYN_REPLY:
333       {
334         SpdySynReplyControlFrame syn_frame(decompressed_frame->data(), false);
335         header_data = syn_frame.header_block();
336         header_length = syn_frame.header_block_len();
337       }
338       break;
339     case HEADERS:
340       {
341         SpdyHeadersControlFrame header_frame(decompressed_frame->data(), false);
342         header_data = header_frame.header_block();
343         header_length = header_frame.header_block_len();
344       }
345       break;
346   }
347 
348   SpdyFrameBuilder builder(header_data, header_length);
349   void* iter = NULL;
350   uint16 num_headers;
351   if (builder.ReadUInt16(&iter, &num_headers)) {
352     int index;
353     for (index = 0; index < num_headers; ++index) {
354       std::string name;
355       std::string value;
356       if (!builder.ReadString(&iter, &name))
357         break;
358       if (!builder.ReadString(&iter, &value))
359         break;
360       if (!name.size() || !value.size())
361         return false;
362       if (block->find(name) == block->end()) {
363         (*block)[name] = value;
364       } else {
365         return false;
366       }
367     }
368     return index == num_headers &&
369         iter == header_data + header_length;
370   }
371   return false;
372 }
373 
UpdateCurrentFrameBuffer(const char ** data,size_t * len,size_t max_bytes)374 size_t SpdyFramer::UpdateCurrentFrameBuffer(const char** data, size_t* len,
375                                             size_t max_bytes) {
376   size_t bytes_to_read = std::min(*len, max_bytes);
377   DCHECK_GE(current_frame_capacity_, current_frame_len_ + bytes_to_read);
378   memcpy(&current_frame_buffer_[current_frame_len_], *data, bytes_to_read);
379   current_frame_len_ += bytes_to_read;
380   *data += bytes_to_read;
381   *len -= bytes_to_read;
382   return bytes_to_read;
383 }
384 
ProcessControlFrameBeforeHeaderBlock(const char * data,size_t len)385 size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
386                                                         size_t len) {
387   DCHECK_EQ(SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK, state_);
388   DCHECK_GT(remaining_control_header_, 0u);
389   size_t original_len = len;
390 
391   if (remaining_control_header_) {
392     size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len,
393                                                  remaining_control_header_);
394     remaining_control_header_ -= bytes_read;
395     if (remaining_control_header_ == 0) {
396       SpdyControlFrame control_frame(current_frame_buffer_, false);
397       DCHECK(control_frame.type() == SYN_STREAM ||
398              control_frame.type() == SYN_REPLY ||
399              control_frame.type() == HEADERS);
400       visitor_->OnControl(&control_frame);
401 
402       CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
403     }
404   }
405   return original_len - len;
406 }
407 
408 // Does not buffer the control payload. Instead, either passes directly to the
409 // visitor or decompresses and then passes directly to the visitor, via
410 // IncrementallyDeliverControlFrameHeaderData() or
411 // IncrementallyDecompressControlFrameHeaderData() respectively.
NewProcessControlFrameHeaderBlock(const char * data,size_t data_len)412 size_t SpdyFramer::NewProcessControlFrameHeaderBlock(const char* data,
413                                                      size_t data_len) {
414   DCHECK_EQ(SPDY_CONTROL_FRAME_HEADER_BLOCK, state_);
415   SpdyControlFrame control_frame(current_frame_buffer_, false);
416   bool processed_successfully = true;
417   DCHECK(control_frame.type() == SYN_STREAM ||
418          control_frame.type() == SYN_REPLY ||
419          control_frame.type() == HEADERS);
420   size_t process_bytes = std::min(data_len, remaining_control_payload_);
421   DCHECK_GT(process_bytes, 0u);
422 
423   if (enable_compression_) {
424     processed_successfully = IncrementallyDecompressControlFrameHeaderData(
425         &control_frame, data, process_bytes);
426   } else {
427     processed_successfully = IncrementallyDeliverControlFrameHeaderData(
428         &control_frame, data, process_bytes);
429   }
430   remaining_control_payload_ -= process_bytes;
431 
432   // Handle the case that there is no futher data in this frame.
433   if (remaining_control_payload_ == 0 && processed_successfully) {
434     // The complete header block has been delivered. We send a zero-length
435     // OnControlFrameHeaderData() to indicate this.
436     visitor_->OnControlFrameHeaderData(
437         GetControlFrameStreamId(&control_frame), NULL, 0);
438 
439     // If this is a FIN, tell the caller.
440     if (control_frame.flags() & CONTROL_FLAG_FIN) {
441       visitor_->OnStreamFrameData(GetControlFrameStreamId(&control_frame),
442                                   NULL, 0);
443     }
444 
445     CHANGE_STATE(SPDY_RESET);
446   }
447 
448   // Handle error.
449   if (!processed_successfully) {
450     return data_len;
451   }
452 
453   // Return amount processed.
454   return process_bytes;
455 }
456 
ProcessControlFrameHeaderBlock(const char * data,size_t data_len)457 size_t SpdyFramer::ProcessControlFrameHeaderBlock(const char* data,
458                                                   size_t data_len) {
459   DCHECK_EQ(SPDY_CONTROL_FRAME_HEADER_BLOCK, state_);
460   size_t original_data_len = data_len;
461   SpdyControlFrame control_frame(current_frame_buffer_, false);
462   bool read_successfully = true;
463   DCHECK(control_frame.type() == SYN_STREAM ||
464          control_frame.type() == SYN_REPLY ||
465          control_frame.type() == HEADERS);
466 
467   if (enable_compression_) {
468     // Note that the header block is held in the frame's payload, and is not
469     // part of the frame's headers.
470     if (remaining_control_payload_ > 0) {
471       size_t bytes_read = UpdateCurrentFrameBuffer(
472           &data,
473           &data_len,
474           remaining_control_payload_);
475       remaining_control_payload_ -= bytes_read;
476       if (remaining_control_payload_ == 0) {
477         read_successfully = IncrementallyDecompressControlFrameHeaderData(
478             &control_frame);
479       }
480     }
481   } else {
482     size_t bytes_to_send = std::min(data_len, remaining_control_payload_);
483     DCHECK_GT(bytes_to_send, 0u);
484     read_successfully = IncrementallyDeliverControlFrameHeaderData(
485         &control_frame, data, bytes_to_send);
486     data_len -= bytes_to_send;
487     remaining_control_payload_ -= bytes_to_send;
488   }
489   if (remaining_control_payload_ == 0 && read_successfully) {
490     // The complete header block has been delivered.
491     visitor_->OnControlFrameHeaderData(GetControlFrameStreamId(&control_frame),
492                                        NULL, 0);
493 
494     // If this is a FIN, tell the caller.
495     if (control_frame.flags() & CONTROL_FLAG_FIN) {
496       visitor_->OnStreamFrameData(GetControlFrameStreamId(&control_frame),
497                                   NULL, 0);
498     }
499 
500     CHANGE_STATE(SPDY_RESET);
501   }
502   if (!read_successfully) {
503     return original_data_len;
504   }
505   return original_data_len - data_len;
506 }
507 
508 /* static */
ParseHeaderBlockInBuffer(const char * header_data,size_t header_length,SpdyHeaderBlock * block)509 bool SpdyFramer::ParseHeaderBlockInBuffer(const char* header_data,
510                                           size_t header_length,
511                                           SpdyHeaderBlock* block) {
512   SpdyFrameBuilder builder(header_data, header_length);
513   void* iter = NULL;
514   uint16 num_headers;
515   if (builder.ReadUInt16(&iter, &num_headers)) {
516     for (int index = 0; index < num_headers; ++index) {
517       std::string name;
518       std::string value;
519       if (!builder.ReadString(&iter, &name))
520         return false;
521       if (!builder.ReadString(&iter, &value))
522         return false;
523       if (block->find(name) == block->end()) {
524         (*block)[name] = value;
525       } else {
526         return false;
527       }
528     }
529     return true;
530   }
531   return false;
532 }
533 
CreateSynStream(SpdyStreamId stream_id,SpdyStreamId associated_stream_id,int priority,SpdyControlFlags flags,bool compressed,const SpdyHeaderBlock * headers)534 SpdySynStreamControlFrame* SpdyFramer::CreateSynStream(
535     SpdyStreamId stream_id, SpdyStreamId associated_stream_id, int priority,
536     SpdyControlFlags flags, bool compressed, const SpdyHeaderBlock* headers) {
537   SpdyFrameBuilder frame;
538 
539   DCHECK_GT(stream_id, static_cast<SpdyStreamId>(0));
540   DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
541   DCHECK_EQ(0u, associated_stream_id & ~kStreamIdMask);
542 
543   frame.WriteUInt16(kControlFlagMask | spdy_version_);
544   frame.WriteUInt16(SYN_STREAM);
545   frame.WriteUInt32(0);  // Placeholder for the length and flags
546   frame.WriteUInt32(stream_id);
547   frame.WriteUInt32(associated_stream_id);
548   frame.WriteUInt16(ntohs(priority) << 6);  // Priority.
549 
550   frame.WriteUInt16(headers->size());  // Number of headers.
551   SpdyHeaderBlock::const_iterator it;
552   for (it = headers->begin(); it != headers->end(); ++it) {
553     bool wrote_header;
554     wrote_header = frame.WriteString(it->first);
555     wrote_header &= frame.WriteString(it->second);
556     DCHECK(wrote_header);
557   }
558 
559   // Write the length and flags.
560   size_t length = frame.length() - SpdyFrame::size();
561   DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask));
562   FlagsAndLength flags_length;
563   flags_length.length_ = htonl(static_cast<uint32>(length));
564   DCHECK_EQ(0, flags & ~kControlFlagsMask);
565   flags_length.flags_[0] = flags;
566   frame.WriteBytesToOffset(4, &flags_length, sizeof(flags_length));
567 
568   scoped_ptr<SpdySynStreamControlFrame> syn_frame(
569       reinterpret_cast<SpdySynStreamControlFrame*>(frame.take()));
570   if (compressed) {
571     return reinterpret_cast<SpdySynStreamControlFrame*>(
572         CompressControlFrame(*syn_frame.get()));
573   }
574   return syn_frame.release();
575 }
576 
CreateSynReply(SpdyStreamId stream_id,SpdyControlFlags flags,bool compressed,const SpdyHeaderBlock * headers)577 SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(SpdyStreamId stream_id,
578     SpdyControlFlags flags, bool compressed, const SpdyHeaderBlock* headers) {
579   DCHECK_GT(stream_id, 0u);
580   DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
581 
582   SpdyFrameBuilder frame;
583 
584   frame.WriteUInt16(kControlFlagMask | spdy_version_);
585   frame.WriteUInt16(SYN_REPLY);
586   frame.WriteUInt32(0);  // Placeholder for the length and flags.
587   frame.WriteUInt32(stream_id);
588   frame.WriteUInt16(0);  // Unused
589 
590   frame.WriteUInt16(headers->size());  // Number of headers.
591   SpdyHeaderBlock::const_iterator it;
592   for (it = headers->begin(); it != headers->end(); ++it) {
593     bool wrote_header;
594     wrote_header = frame.WriteString(it->first);
595     wrote_header &= frame.WriteString(it->second);
596     DCHECK(wrote_header);
597   }
598 
599   // Write the length and flags.
600   size_t length = frame.length() - SpdyFrame::size();
601   DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask));
602   FlagsAndLength flags_length;
603   flags_length.length_ = htonl(static_cast<uint32>(length));
604   DCHECK_EQ(0, flags & ~kControlFlagsMask);
605   flags_length.flags_[0] = flags;
606   frame.WriteBytesToOffset(4, &flags_length, sizeof(flags_length));
607 
608   scoped_ptr<SpdySynReplyControlFrame> reply_frame(
609       reinterpret_cast<SpdySynReplyControlFrame*>(frame.take()));
610   if (compressed) {
611     return reinterpret_cast<SpdySynReplyControlFrame*>(
612         CompressControlFrame(*reply_frame.get()));
613   }
614   return reply_frame.release();
615 }
616 
617 /* static */
CreateRstStream(SpdyStreamId stream_id,SpdyStatusCodes status)618 SpdyRstStreamControlFrame* SpdyFramer::CreateRstStream(SpdyStreamId stream_id,
619                                                        SpdyStatusCodes status) {
620   DCHECK_GT(stream_id, 0u);
621   DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
622   DCHECK_NE(status, INVALID);
623   DCHECK_LT(status, NUM_STATUS_CODES);
624 
625   SpdyFrameBuilder frame;
626   frame.WriteUInt16(kControlFlagMask | spdy_version_);
627   frame.WriteUInt16(RST_STREAM);
628   frame.WriteUInt32(8);
629   frame.WriteUInt32(stream_id);
630   frame.WriteUInt32(status);
631   return reinterpret_cast<SpdyRstStreamControlFrame*>(frame.take());
632 }
633 
634 /* static */
CreateSettings(const SpdySettings & values)635 SpdySettingsControlFrame* SpdyFramer::CreateSettings(
636     const SpdySettings& values) {
637   SpdyFrameBuilder frame;
638   frame.WriteUInt16(kControlFlagMask | spdy_version_);
639   frame.WriteUInt16(SETTINGS);
640   size_t settings_size = SpdySettingsControlFrame::size() - SpdyFrame::size() +
641       8 * values.size();
642   frame.WriteUInt32(settings_size);
643   frame.WriteUInt32(values.size());
644   SpdySettings::const_iterator it = values.begin();
645   while (it != values.end()) {
646     frame.WriteUInt32(it->first.id_);
647     frame.WriteUInt32(it->second);
648     ++it;
649   }
650   return reinterpret_cast<SpdySettingsControlFrame*>(frame.take());
651 }
652 
653 /* static */
CreateNopFrame()654 SpdyNoOpControlFrame* SpdyFramer::CreateNopFrame() {
655   SpdyFrameBuilder frame;
656   frame.WriteUInt16(kControlFlagMask | spdy_version_);
657   frame.WriteUInt16(NOOP);
658   frame.WriteUInt32(0);
659   return reinterpret_cast<SpdyNoOpControlFrame*>(frame.take());
660 }
661 
662 /* static */
CreatePingFrame(uint32 unique_id)663 SpdyPingControlFrame* SpdyFramer::CreatePingFrame(uint32 unique_id) {
664   SpdyFrameBuilder frame;
665   frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion);
666   frame.WriteUInt16(PING);
667   size_t ping_size = SpdyPingControlFrame::size() - SpdyFrame::size();
668   frame.WriteUInt32(ping_size);
669   frame.WriteUInt32(unique_id);
670   return reinterpret_cast<SpdyPingControlFrame*>(frame.take());
671 }
672 
673 /* static */
CreateGoAway(SpdyStreamId last_accepted_stream_id)674 SpdyGoAwayControlFrame* SpdyFramer::CreateGoAway(
675     SpdyStreamId last_accepted_stream_id) {
676   DCHECK_EQ(0u, last_accepted_stream_id & ~kStreamIdMask);
677 
678   SpdyFrameBuilder frame;
679   frame.WriteUInt16(kControlFlagMask | spdy_version_);
680   frame.WriteUInt16(GOAWAY);
681   size_t go_away_size = SpdyGoAwayControlFrame::size() - SpdyFrame::size();
682   frame.WriteUInt32(go_away_size);
683   frame.WriteUInt32(last_accepted_stream_id);
684   return reinterpret_cast<SpdyGoAwayControlFrame*>(frame.take());
685 }
686 
CreateHeaders(SpdyStreamId stream_id,SpdyControlFlags flags,bool compressed,const SpdyHeaderBlock * headers)687 SpdyHeadersControlFrame* SpdyFramer::CreateHeaders(SpdyStreamId stream_id,
688     SpdyControlFlags flags, bool compressed, const SpdyHeaderBlock* headers) {
689   // Basically the same as CreateSynReply().
690   DCHECK_GT(stream_id, 0u);
691   DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
692 
693   SpdyFrameBuilder frame;
694   frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion);
695   frame.WriteUInt16(HEADERS);
696   frame.WriteUInt32(0);  // Placeholder for the length and flags.
697   frame.WriteUInt32(stream_id);
698   frame.WriteUInt16(0);  // Unused
699 
700   frame.WriteUInt16(headers->size());  // Number of headers.
701   SpdyHeaderBlock::const_iterator it;
702   for (it = headers->begin(); it != headers->end(); ++it) {
703     bool wrote_header;
704     wrote_header = frame.WriteString(it->first);
705     wrote_header &= frame.WriteString(it->second);
706     DCHECK(wrote_header);
707   }
708 
709   // Write the length and flags.
710   size_t length = frame.length() - SpdyFrame::size();
711   DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask));
712   FlagsAndLength flags_length;
713   flags_length.length_ = htonl(static_cast<uint32>(length));
714   DCHECK_EQ(0, flags & ~kControlFlagsMask);
715   flags_length.flags_[0] = flags;
716   frame.WriteBytesToOffset(4, &flags_length, sizeof(flags_length));
717 
718   scoped_ptr<SpdyHeadersControlFrame> headers_frame(
719       reinterpret_cast<SpdyHeadersControlFrame*>(frame.take()));
720   if (compressed) {
721     return reinterpret_cast<SpdyHeadersControlFrame*>(
722         CompressControlFrame(*headers_frame.get()));
723   }
724   return headers_frame.release();
725 }
726 
727 /* static */
CreateWindowUpdate(SpdyStreamId stream_id,uint32 delta_window_size)728 SpdyWindowUpdateControlFrame* SpdyFramer::CreateWindowUpdate(
729     SpdyStreamId stream_id,
730     uint32 delta_window_size) {
731   DCHECK_GT(stream_id, 0u);
732   DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
733   DCHECK_GT(delta_window_size, 0u);
734   DCHECK_LE(delta_window_size, spdy::kSpdyStreamMaximumWindowSize);
735 
736   SpdyFrameBuilder frame;
737   frame.WriteUInt16(kControlFlagMask | spdy_version_);
738   frame.WriteUInt16(WINDOW_UPDATE);
739   size_t window_update_size = SpdyWindowUpdateControlFrame::size() -
740       SpdyFrame::size();
741   frame.WriteUInt32(window_update_size);
742   frame.WriteUInt32(stream_id);
743   frame.WriteUInt32(delta_window_size);
744   return reinterpret_cast<SpdyWindowUpdateControlFrame*>(frame.take());
745 }
746 
747 /* static */
ParseSettings(const SpdySettingsControlFrame * frame,SpdySettings * settings)748 bool SpdyFramer::ParseSettings(const SpdySettingsControlFrame* frame,
749                                SpdySettings* settings) {
750   DCHECK_EQ(frame->type(), SETTINGS);
751   DCHECK(settings);
752 
753   SpdyFrameBuilder parser(frame->header_block(), frame->header_block_len());
754   void* iter = NULL;
755   for (size_t index = 0; index < frame->num_entries(); ++index) {
756     uint32 id;
757     uint32 value;
758     if (!parser.ReadUInt32(&iter, &id))
759       return false;
760     if (!parser.ReadUInt32(&iter, &value))
761       return false;
762     settings->insert(settings->end(), std::make_pair(id, value));
763   }
764   return true;
765 }
766 
CreateDataFrame(SpdyStreamId stream_id,const char * data,uint32 len,SpdyDataFlags flags)767 SpdyDataFrame* SpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
768                                            const char* data,
769                                            uint32 len, SpdyDataFlags flags) {
770   SpdyFrameBuilder frame;
771 
772   DCHECK_GT(stream_id, 0u);
773   DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
774   frame.WriteUInt32(stream_id);
775 
776   DCHECK_EQ(0u, len & ~static_cast<size_t>(kLengthMask));
777   FlagsAndLength flags_length;
778   flags_length.length_ = htonl(len);
779   DCHECK_EQ(0, flags & ~kDataFlagsMask);
780   flags_length.flags_[0] = flags;
781   frame.WriteBytes(&flags_length, sizeof(flags_length));
782 
783   frame.WriteBytes(data, len);
784   scoped_ptr<SpdyFrame> data_frame(frame.take());
785   SpdyDataFrame* rv;
786   if (flags & DATA_FLAG_COMPRESSED) {
787     rv = reinterpret_cast<SpdyDataFrame*>(CompressFrame(*data_frame.get()));
788   } else {
789     rv = reinterpret_cast<SpdyDataFrame*>(data_frame.release());
790   }
791 
792   if (flags & DATA_FLAG_FIN) {
793     CleanupCompressorForStream(stream_id);
794   }
795 
796   return rv;
797 }
798 
CompressFrame(const SpdyFrame & frame)799 SpdyFrame* SpdyFramer::CompressFrame(const SpdyFrame& frame) {
800   if (frame.is_control_frame()) {
801     return CompressControlFrame(
802         reinterpret_cast<const SpdyControlFrame&>(frame));
803   }
804   return CompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame));
805 }
806 
DecompressFrame(const SpdyFrame & frame)807 SpdyFrame* SpdyFramer::DecompressFrame(const SpdyFrame& frame) {
808   if (frame.is_control_frame()) {
809     return DecompressControlFrame(
810         reinterpret_cast<const SpdyControlFrame&>(frame));
811   }
812   return DecompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame));
813 }
814 
DuplicateFrame(const SpdyFrame & frame)815 SpdyFrame* SpdyFramer::DuplicateFrame(const SpdyFrame& frame) {
816   int size = SpdyFrame::size() + frame.length();
817   SpdyFrame* new_frame = new SpdyFrame(size);
818   memcpy(new_frame->data(), frame.data(), size);
819   return new_frame;
820 }
821 
IsCompressible(const SpdyFrame & frame) const822 bool SpdyFramer::IsCompressible(const SpdyFrame& frame) const {
823   // The important frames to compress are those which contain large
824   // amounts of compressible data - namely the headers in the SYN_STREAM
825   // and SYN_REPLY.
826   // TODO(mbelshe): Reconcile this with the spec when the spec is
827   // explicit about which frames compress and which do not.
828   if (frame.is_control_frame()) {
829     const SpdyControlFrame& control_frame =
830         reinterpret_cast<const SpdyControlFrame&>(frame);
831     return control_frame.type() == SYN_STREAM ||
832            control_frame.type() == SYN_REPLY;
833   }
834 
835   const SpdyDataFrame& data_frame =
836       reinterpret_cast<const SpdyDataFrame&>(frame);
837   return (data_frame.flags() & DATA_FLAG_COMPRESSED) != 0;
838 }
839 
StateToString(int state)840 const char* SpdyFramer::StateToString(int state) {
841   switch (state) {
842     case SPDY_ERROR:
843       return "ERROR";
844     case SPDY_DONE:
845       return "DONE";
846     case SPDY_AUTO_RESET:
847       return "AUTO_RESET";
848     case SPDY_RESET:
849       return "RESET";
850     case SPDY_READING_COMMON_HEADER:
851       return "READING_COMMON_HEADER";
852     case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER:
853       return "INTERPRET_CONTROL_FRAME_COMMON_HEADER";
854     case SPDY_CONTROL_FRAME_PAYLOAD:
855       return "CONTROL_FRAME_PAYLOAD";
856     case SPDY_IGNORE_REMAINING_PAYLOAD:
857       return "IGNORE_REMAINING_PAYLOAD";
858     case SPDY_FORWARD_STREAM_FRAME:
859       return "FORWARD_STREAM_FRAME";
860     case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK:
861       return "SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK";
862     case SPDY_CONTROL_FRAME_HEADER_BLOCK:
863       return "SPDY_CONTROL_FRAME_HEADER_BLOCK";
864   }
865   return "UNKNOWN_STATE";
866 }
867 
ErrorCodeToString(int error_code)868 const char* SpdyFramer::ErrorCodeToString(int error_code) {
869   switch (error_code) {
870     case SPDY_NO_ERROR:
871       return "NO_ERROR";
872     case SPDY_INVALID_CONTROL_FRAME:
873       return "INVALID_CONTROL_FRAME";
874     case SPDY_CONTROL_PAYLOAD_TOO_LARGE:
875       return "CONTROL_PAYLOAD_TOO_LARGE";
876     case SPDY_ZLIB_INIT_FAILURE:
877       return "ZLIB_INIT_FAILURE";
878     case SPDY_UNSUPPORTED_VERSION:
879       return "UNSUPPORTED_VERSION";
880     case SPDY_DECOMPRESS_FAILURE:
881       return "DECOMPRESS_FAILURE";
882     case SPDY_COMPRESS_FAILURE:
883       return "COMPRESS_FAILURE";
884   }
885   return "UNKNOWN_ERROR";
886 }
887 
set_enable_compression(bool value)888 void SpdyFramer::set_enable_compression(bool value) {
889   enable_compression_ = value;
890 }
891 
set_enable_compression_default(bool value)892 void SpdyFramer::set_enable_compression_default(bool value) {
893   compression_default_ = value;
894 }
895 
ProcessCommonHeader(const char * data,size_t len)896 size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
897   // This should only be called when we're in the SPDY_READING_COMMON_HEADER
898   // state.
899   DCHECK_EQ(state_, SPDY_READING_COMMON_HEADER);
900 
901   size_t original_len = len;
902   SpdyFrame current_frame(current_frame_buffer_, false);
903 
904   do {
905     if (current_frame_len_ < SpdyFrame::size()) {
906       size_t bytes_desired = SpdyFrame::size() - current_frame_len_;
907       UpdateCurrentFrameBuffer(&data, &len, bytes_desired);
908       // Check for an empty data frame.
909       if (current_frame_len_ == SpdyFrame::size() &&
910           !current_frame.is_control_frame() &&
911           current_frame.length() == 0) {
912         if (current_frame.flags() & CONTROL_FLAG_FIN) {
913           SpdyDataFrame data_frame(current_frame_buffer_, false);
914           visitor_->OnStreamFrameData(data_frame.stream_id(), NULL, 0);
915         }
916         CHANGE_STATE(SPDY_AUTO_RESET);
917       }
918       break;
919     }
920     remaining_data_ = current_frame.length();
921 
922     // This is just a sanity check for help debugging early frame errors.
923     if (remaining_data_ > 1000000u) {
924       LOG(WARNING) <<
925           "Unexpectedly large frame.  Spdy session is likely corrupt.";
926     }
927 
928     // if we're here, then we have the common header all received.
929     if (!current_frame.is_control_frame())
930       CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
931     else
932       CHANGE_STATE(SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER);
933   } while (false);
934 
935   return original_len - len;
936 }
937 
ProcessControlFrameHeader()938 void SpdyFramer::ProcessControlFrameHeader() {
939   DCHECK_EQ(SPDY_NO_ERROR, error_code_);
940   DCHECK_LE(SpdyFrame::size(), current_frame_len_);
941   SpdyControlFrame current_control_frame(current_frame_buffer_, false);
942 
943   // We check version before we check validity: version can never be 'invalid',
944   // it can only be unsupported.
945   if (current_control_frame.version() != spdy_version_) {
946     set_error(SPDY_UNSUPPORTED_VERSION);
947     return;
948   }
949 
950   // Next up, check to see if we have valid data.  This should be after version
951   // checking (otherwise if the the type were out of bounds due to a version
952   // upgrade we would misclassify the error) and before checking the type
953   // (type can definitely be out of bounds)
954   if (!current_control_frame.AppearsToBeAValidControlFrame()) {
955     set_error(SPDY_INVALID_CONTROL_FRAME);
956     return;
957   }
958 
959   // Do some sanity checking on the control frame sizes.
960   switch (current_control_frame.type()) {
961     case SYN_STREAM:
962       if (current_control_frame.length() <
963           SpdySynStreamControlFrame::size() - SpdyControlFrame::size())
964         set_error(SPDY_INVALID_CONTROL_FRAME);
965       break;
966     case SYN_REPLY:
967       if (current_control_frame.length() <
968           SpdySynReplyControlFrame::size() - SpdyControlFrame::size())
969         set_error(SPDY_INVALID_CONTROL_FRAME);
970       break;
971     case RST_STREAM:
972       if (current_control_frame.length() !=
973           SpdyRstStreamControlFrame::size() - SpdyFrame::size())
974         set_error(SPDY_INVALID_CONTROL_FRAME);
975       break;
976     case SETTINGS:
977       if (current_control_frame.length() <
978           SpdySettingsControlFrame::size() - SpdyControlFrame::size())
979         set_error(SPDY_INVALID_CONTROL_FRAME);
980       break;
981     // TODO(hkhalil): Remove NOOP.
982     case NOOP:
983       // NOOP.  Swallow it.
984       DLOG(INFO) << "Attempted frame size validation for NOOP. Resetting.";
985       CHANGE_STATE(SPDY_AUTO_RESET);
986       return;
987     case GOAWAY:
988       if (current_control_frame.length() !=
989           SpdyGoAwayControlFrame::size() - SpdyFrame::size())
990         set_error(SPDY_INVALID_CONTROL_FRAME);
991       break;
992     case HEADERS:
993       if (current_control_frame.length() <
994           SpdyHeadersControlFrame::size() - SpdyControlFrame::size())
995         set_error(SPDY_INVALID_CONTROL_FRAME);
996       break;
997     case WINDOW_UPDATE:
998       if (current_control_frame.length() !=
999           SpdyWindowUpdateControlFrame::size() - SpdyControlFrame::size())
1000         set_error(SPDY_INVALID_CONTROL_FRAME);
1001       break;
1002     case PING:
1003       if (current_control_frame.length() !=
1004           SpdyPingControlFrame::size() - SpdyControlFrame::size())
1005         set_error(SPDY_INVALID_CONTROL_FRAME);
1006       break;
1007     default:
1008       LOG(WARNING) << "Valid spdy control frame with unhandled type: "
1009                    << current_control_frame.type();
1010       DCHECK(false);
1011       set_error(SPDY_INVALID_CONTROL_FRAME);
1012       break;
1013   }
1014 
1015   remaining_control_payload_ = current_control_frame.length();
1016   if (remaining_control_payload_ > kControlFrameBufferMaxSize) {
1017     set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
1018     return;
1019   }
1020 
1021   ExpandControlFrameBuffer(remaining_control_payload_);
1022   CHANGE_STATE(SPDY_CONTROL_FRAME_PAYLOAD);
1023 }
1024 
ProcessControlFramePayload(const char * data,size_t len)1025 size_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) {
1026   size_t original_len = len;
1027   do {
1028     if (remaining_control_payload_) {
1029       size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len,
1030                                                    remaining_control_payload_);
1031       remaining_control_payload_ -= bytes_read;
1032       remaining_data_ -= bytes_read;
1033       if (remaining_control_payload_)
1034         break;
1035     }
1036     SpdyControlFrame control_frame(current_frame_buffer_, false);
1037     visitor_->OnControl(&control_frame);
1038 
1039     // If this is a FIN, tell the caller.
1040     if (control_frame.type() == SYN_REPLY &&
1041         control_frame.flags() & CONTROL_FLAG_FIN) {
1042       visitor_->OnStreamFrameData(reinterpret_cast<SpdySynReplyControlFrame*>(
1043                                       &control_frame)->stream_id(),
1044                                   NULL, 0);
1045     }
1046 
1047     CHANGE_STATE(SPDY_IGNORE_REMAINING_PAYLOAD);
1048   } while (false);
1049   return original_len - len;
1050 }
1051 
ProcessDataFramePayload(const char * data,size_t len)1052 size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) {
1053   size_t original_len = len;
1054 
1055   SpdyDataFrame current_data_frame(current_frame_buffer_, false);
1056   if (remaining_data_) {
1057     size_t amount_to_forward = std::min(remaining_data_, len);
1058     if (amount_to_forward && state_ != SPDY_IGNORE_REMAINING_PAYLOAD) {
1059       if (current_data_frame.flags() & DATA_FLAG_COMPRESSED) {
1060         z_stream* decompressor =
1061             GetStreamDecompressor(current_data_frame.stream_id());
1062         if (!decompressor)
1063           return 0;
1064 
1065         size_t decompressed_max_size = amount_to_forward * 100;
1066         scoped_array<char> decompressed(new char[decompressed_max_size]);
1067         decompressor->next_in = reinterpret_cast<Bytef*>(
1068             const_cast<char*>(data));
1069         decompressor->avail_in = amount_to_forward;
1070         decompressor->next_out =
1071             reinterpret_cast<Bytef*>(decompressed.get());
1072         decompressor->avail_out = decompressed_max_size;
1073 
1074         int rv = inflate(decompressor, Z_SYNC_FLUSH);
1075         if (rv != Z_OK) {
1076           LOG(WARNING) << "inflate failure: " << rv;
1077           set_error(SPDY_DECOMPRESS_FAILURE);
1078           return 0;
1079         }
1080         size_t decompressed_size = decompressed_max_size -
1081                                    decompressor->avail_out;
1082 
1083         // Only inform the visitor if there is data.
1084         if (decompressed_size)
1085           visitor_->OnStreamFrameData(current_data_frame.stream_id(),
1086                                       decompressed.get(),
1087                                       decompressed_size);
1088         amount_to_forward -= decompressor->avail_in;
1089       } else {
1090         // The data frame was not compressed.
1091         // Only inform the visitor if there is data.
1092         if (amount_to_forward)
1093           visitor_->OnStreamFrameData(current_data_frame.stream_id(),
1094                                       data, amount_to_forward);
1095       }
1096     }
1097     data += amount_to_forward;
1098     len -= amount_to_forward;
1099     remaining_data_ -= amount_to_forward;
1100 
1101     // If the FIN flag is set, and there is no more data in this data
1102     // frame, inform the visitor of EOF via a 0-length data frame.
1103     if (!remaining_data_ &&
1104         current_data_frame.flags() & DATA_FLAG_FIN) {
1105       visitor_->OnStreamFrameData(current_data_frame.stream_id(), NULL, 0);
1106       CleanupDecompressorForStream(current_data_frame.stream_id());
1107     }
1108   } else {
1109     CHANGE_STATE(SPDY_AUTO_RESET);
1110   }
1111   return original_len - len;
1112 }
1113 
GetHeaderCompressor()1114 z_stream* SpdyFramer::GetHeaderCompressor() {
1115   if (header_compressor_.get())
1116     return header_compressor_.get();  // Already initialized.
1117 
1118   header_compressor_.reset(new z_stream);
1119   memset(header_compressor_.get(), 0, sizeof(z_stream));
1120 
1121   int success = deflateInit2(header_compressor_.get(),
1122                              kCompressorLevel,
1123                              Z_DEFLATED,
1124                              kCompressorWindowSizeInBits,
1125                              kCompressorMemLevel,
1126                              Z_DEFAULT_STRATEGY);
1127   if (success == Z_OK)
1128     success = deflateSetDictionary(header_compressor_.get(),
1129                                    reinterpret_cast<const Bytef*>(kDictionary),
1130                                    kDictionarySize);
1131   if (success != Z_OK) {
1132     LOG(WARNING) << "deflateSetDictionary failure: " << success;
1133     header_compressor_.reset(NULL);
1134     return NULL;
1135   }
1136   return header_compressor_.get();
1137 }
1138 
GetHeaderDecompressor()1139 z_stream* SpdyFramer::GetHeaderDecompressor() {
1140   if (header_decompressor_.get())
1141     return header_decompressor_.get();  // Already initialized.
1142 
1143   header_decompressor_.reset(new z_stream);
1144   memset(header_decompressor_.get(), 0, sizeof(z_stream));
1145 
1146   // Compute the id of our dictionary so that we know we're using the
1147   // right one when asked for it.
1148   if (dictionary_id == 0) {
1149     dictionary_id = adler32(0L, Z_NULL, 0);
1150     dictionary_id = adler32(dictionary_id,
1151                             reinterpret_cast<const Bytef*>(kDictionary),
1152                             kDictionarySize);
1153   }
1154 
1155   int success = inflateInit(header_decompressor_.get());
1156   if (success != Z_OK) {
1157     LOG(WARNING) << "inflateInit failure: " << success;
1158     header_decompressor_.reset(NULL);
1159     return NULL;
1160   }
1161   return header_decompressor_.get();
1162 }
1163 
GetStreamCompressor(SpdyStreamId stream_id)1164 z_stream* SpdyFramer::GetStreamCompressor(SpdyStreamId stream_id) {
1165   CompressorMap::iterator it = stream_compressors_.find(stream_id);
1166   if (it != stream_compressors_.end())
1167     return it->second;  // Already initialized.
1168 
1169   scoped_ptr<z_stream> compressor(new z_stream);
1170   memset(compressor.get(), 0, sizeof(z_stream));
1171 
1172   int success = deflateInit2(compressor.get(),
1173                              kCompressorLevel,
1174                              Z_DEFLATED,
1175                              kCompressorWindowSizeInBits,
1176                              kCompressorMemLevel,
1177                              Z_DEFAULT_STRATEGY);
1178   if (success != Z_OK) {
1179     LOG(WARNING) << "deflateInit failure: " << success;
1180     return NULL;
1181   }
1182   return stream_compressors_[stream_id] = compressor.release();
1183 }
1184 
GetStreamDecompressor(SpdyStreamId stream_id)1185 z_stream* SpdyFramer::GetStreamDecompressor(SpdyStreamId stream_id) {
1186   CompressorMap::iterator it = stream_decompressors_.find(stream_id);
1187   if (it != stream_decompressors_.end())
1188     return it->second;  // Already initialized.
1189 
1190   scoped_ptr<z_stream> decompressor(new z_stream);
1191   memset(decompressor.get(), 0, sizeof(z_stream));
1192 
1193   int success = inflateInit(decompressor.get());
1194   if (success != Z_OK) {
1195     LOG(WARNING) << "inflateInit failure: " << success;
1196     return NULL;
1197   }
1198   return stream_decompressors_[stream_id] = decompressor.release();
1199 }
1200 
CompressControlFrame(const SpdyControlFrame & frame)1201 SpdyControlFrame* SpdyFramer::CompressControlFrame(
1202     const SpdyControlFrame& frame) {
1203   z_stream* compressor = GetHeaderCompressor();
1204   if (!compressor)
1205     return NULL;
1206   return reinterpret_cast<SpdyControlFrame*>(
1207       CompressFrameWithZStream(frame, compressor));
1208 }
1209 
CompressDataFrame(const SpdyDataFrame & frame)1210 SpdyDataFrame* SpdyFramer::CompressDataFrame(const SpdyDataFrame& frame) {
1211   z_stream* compressor = GetStreamCompressor(frame.stream_id());
1212   if (!compressor)
1213     return NULL;
1214   return reinterpret_cast<SpdyDataFrame*>(
1215       CompressFrameWithZStream(frame, compressor));
1216 }
1217 
DecompressControlFrame(const SpdyControlFrame & frame)1218 SpdyControlFrame* SpdyFramer::DecompressControlFrame(
1219     const SpdyControlFrame& frame) {
1220   z_stream* decompressor = GetHeaderDecompressor();
1221   if (!decompressor)
1222     return NULL;
1223   return reinterpret_cast<SpdyControlFrame*>(
1224       DecompressFrameWithZStream(frame, decompressor));
1225 }
1226 
1227 // Incrementally decompress the control frame's header block, feeding the
1228 // result to the visitor in chunks. Continue this until the visitor
1229 // indicates that it cannot process any more data, or (more commonly) we
1230 // run out of data to deliver.
IncrementallyDecompressControlFrameHeaderData(const SpdyControlFrame * control_frame)1231 bool SpdyFramer::IncrementallyDecompressControlFrameHeaderData(
1232     const SpdyControlFrame* control_frame) {
1233   z_stream* decomp = GetHeaderDecompressor();
1234   int payload_length;
1235   int header_length;
1236   const char* payload;
1237   bool read_successfully = true;
1238   bool more = true;
1239   char buffer[kHeaderDataChunkMaxSize];
1240 
1241   if (!GetFrameBoundaries(
1242       *control_frame, &payload_length, &header_length, &payload)) {
1243     DLOG(ERROR) << "Control frame of type "
1244                 << SpdyFramer::ControlTypeToString(control_frame->type())
1245                 <<" doesn't have headers";
1246     return false;
1247   }
1248   decomp->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload));
1249   decomp->avail_in = payload_length;
1250   const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame);
1251   DCHECK_LT(0u, stream_id);
1252   while (more && read_successfully) {
1253     decomp->next_out = reinterpret_cast<Bytef*>(buffer);
1254     decomp->avail_out = arraysize(buffer);
1255     int rv = DecompressHeaderBlockInZStream(decomp);
1256     if (rv != Z_OK) {
1257       set_error(SPDY_DECOMPRESS_FAILURE);
1258       DLOG(WARNING) << "inflate failure: " << rv;
1259       more = read_successfully = false;
1260     } else {
1261       DCHECK_GT(arraysize(buffer), decomp->avail_out);
1262       size_t len = arraysize(buffer) - decomp->avail_out;
1263       read_successfully = visitor_->OnControlFrameHeaderData(stream_id, buffer,
1264                                                              len);
1265       if (!read_successfully) {
1266         // Assume that the problem was the header block was too large for the
1267         // visitor.
1268         set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
1269       }
1270       more = decomp->avail_in > 0;
1271     }
1272   }
1273   return read_successfully;
1274 }
1275 
1276 // Incrementally decompress the control frame's header block, feeding the
1277 // result to the visitor in chunks. Continue this until the visitor
1278 // indicates that it cannot process any more data, or (more commonly) we
1279 // run out of data to deliver.
IncrementallyDecompressControlFrameHeaderData(const SpdyControlFrame * control_frame,const char * data,size_t len)1280 bool SpdyFramer::IncrementallyDecompressControlFrameHeaderData(
1281     const SpdyControlFrame* control_frame,
1282     const char* data,
1283     size_t len) {
1284   // Get a decompressor or set error.
1285   z_stream* decomp = GetHeaderDecompressor();
1286   if (decomp == NULL) {
1287     LOG(DFATAL) << "Couldn't get decompressor for handling compressed headers.";
1288     set_error(SPDY_DECOMPRESS_FAILURE);
1289     return false;
1290   }
1291 
1292   bool processed_successfully = true;
1293   char buffer[kHeaderDataChunkMaxSize];
1294 
1295   decomp->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data));
1296   decomp->avail_in = len;
1297   const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame);
1298   DCHECK_LT(0u, stream_id);
1299   while (decomp->avail_in > 0 && processed_successfully) {
1300     decomp->next_out = reinterpret_cast<Bytef*>(buffer);
1301     decomp->avail_out = arraysize(buffer);
1302     int rv = DecompressHeaderBlockInZStream(decomp);
1303     if (rv != Z_OK) {
1304       set_error(SPDY_DECOMPRESS_FAILURE);
1305       DLOG(WARNING) << "inflate failure: " << rv;
1306       processed_successfully = false;
1307     } else {
1308       size_t decompressed_len = arraysize(buffer) - decomp->avail_out;
1309       if (decompressed_len > 0) {
1310         processed_successfully = visitor_->OnControlFrameHeaderData(
1311             stream_id, buffer, decompressed_len);
1312       }
1313       if (!processed_successfully) {
1314         // Assume that the problem was the header block was too large for the
1315         // visitor.
1316         set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
1317       }
1318     }
1319   }
1320   return processed_successfully;
1321 }
1322 
IncrementallyDeliverControlFrameHeaderData(const SpdyControlFrame * control_frame,const char * data,size_t len)1323 bool SpdyFramer::IncrementallyDeliverControlFrameHeaderData(
1324     const SpdyControlFrame* control_frame, const char* data, size_t len) {
1325   bool read_successfully = true;
1326   const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame);
1327   DCHECK_LT(0u, stream_id);
1328   while (read_successfully && len > 0) {
1329     size_t bytes_to_deliver = std::min(len, kHeaderDataChunkMaxSize);
1330     read_successfully = visitor_->OnControlFrameHeaderData(stream_id, data,
1331                                                            bytes_to_deliver);
1332     data += bytes_to_deliver;
1333     len -= bytes_to_deliver;
1334     if (!read_successfully) {
1335       // Assume that the problem was the header block was too large for the
1336       // visitor.
1337       set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
1338     }
1339   }
1340   return read_successfully;
1341 }
1342 
GetMinimumControlFrameSize(SpdyControlType type)1343 size_t SpdyFramer::GetMinimumControlFrameSize(SpdyControlType type) {
1344   switch (type) {
1345     case SYN_STREAM:
1346       return SpdySynStreamControlFrame::size();
1347     case SYN_REPLY:
1348       return SpdySynReplyControlFrame::size();
1349     case RST_STREAM:
1350       return SpdyRstStreamControlFrame::size();
1351     case SETTINGS:
1352       return SpdySettingsControlFrame::size();
1353     case NOOP:
1354       return SpdyNoOpControlFrame::size();
1355     case PING:
1356       return SpdyPingControlFrame::size();
1357     case GOAWAY:
1358       return SpdyGoAwayControlFrame::size();
1359     case HEADERS:
1360       return SpdyHeadersControlFrame::size();
1361     case WINDOW_UPDATE:
1362       return SpdyWindowUpdateControlFrame::size();
1363     case NUM_CONTROL_FRAME_TYPES:
1364       break;
1365   }
1366   LOG(ERROR) << "Unknown SPDY control frame type " << type;
1367   return 0x7FFFFFFF;  // Max signed 32bit int
1368 }
1369 
1370 /* static */
GetControlFrameStreamId(const SpdyControlFrame * control_frame)1371 SpdyStreamId SpdyFramer::GetControlFrameStreamId(
1372     const SpdyControlFrame* control_frame) {
1373   SpdyStreamId stream_id = kInvalidStream;
1374   if (control_frame != NULL) {
1375     switch (control_frame->type()) {
1376       case SYN_STREAM:
1377         stream_id = reinterpret_cast<const SpdySynStreamControlFrame*>(
1378             control_frame)->stream_id();
1379         break;
1380       case SYN_REPLY:
1381         stream_id = reinterpret_cast<const SpdySynReplyControlFrame*>(
1382             control_frame)->stream_id();
1383         break;
1384       case HEADERS:
1385         stream_id = reinterpret_cast<const SpdyHeadersControlFrame*>(
1386             control_frame)->stream_id();
1387         break;
1388       case RST_STREAM:
1389         stream_id = reinterpret_cast<const SpdyRstStreamControlFrame*>(
1390             control_frame)->stream_id();
1391         break;
1392       case WINDOW_UPDATE:
1393         stream_id = reinterpret_cast<const SpdyWindowUpdateControlFrame*>(
1394             control_frame)->stream_id();
1395         break;
1396       // All of the following types are not part of a particular stream.
1397       // They all fall through to the invalid control frame type case.
1398       // (The default case isn't used so that the compile will break if a new
1399       // control frame type is added but not included here.)
1400       case SETTINGS:
1401       case NOOP:
1402       case PING:
1403       case GOAWAY:
1404       case NUM_CONTROL_FRAME_TYPES:  // makes compiler happy
1405         break;
1406     }
1407   }
1408   return stream_id;
1409 }
1410 
set_validate_control_frame_sizes(bool value)1411 void SpdyFramer::set_validate_control_frame_sizes(bool value) {
1412   validate_control_frame_sizes_ = value;
1413 }
1414 
DecompressDataFrame(const SpdyDataFrame & frame)1415 SpdyDataFrame* SpdyFramer::DecompressDataFrame(const SpdyDataFrame& frame) {
1416   z_stream* decompressor = GetStreamDecompressor(frame.stream_id());
1417   if (!decompressor)
1418     return NULL;
1419   return reinterpret_cast<SpdyDataFrame*>(
1420       DecompressFrameWithZStream(frame, decompressor));
1421 }
1422 
CompressFrameWithZStream(const SpdyFrame & frame,z_stream * compressor)1423 SpdyFrame* SpdyFramer::CompressFrameWithZStream(const SpdyFrame& frame,
1424                                                 z_stream* compressor) {
1425   int payload_length;
1426   int header_length;
1427   const char* payload;
1428 
1429   base::StatsCounter compressed_frames("spdy.CompressedFrames");
1430   base::StatsCounter pre_compress_bytes("spdy.PreCompressSize");
1431   base::StatsCounter post_compress_bytes("spdy.PostCompressSize");
1432 
1433   if (!enable_compression_)
1434     return DuplicateFrame(frame);
1435 
1436   if (!GetFrameBoundaries(frame, &payload_length, &header_length, &payload))
1437     return NULL;
1438 
1439   // Create an output frame.
1440   int compressed_max_size = deflateBound(compressor, payload_length);
1441   int new_frame_size = header_length + compressed_max_size;
1442   scoped_ptr<SpdyFrame> new_frame(new SpdyFrame(new_frame_size));
1443   memcpy(new_frame->data(), frame.data(), frame.length() + SpdyFrame::size());
1444 
1445   compressor->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload));
1446   compressor->avail_in = payload_length;
1447   compressor->next_out = reinterpret_cast<Bytef*>(new_frame->data()) +
1448                           header_length;
1449   compressor->avail_out = compressed_max_size;
1450 
1451   // Data packets have a 'compressed' flag.
1452   if (!new_frame->is_control_frame()) {
1453     SpdyDataFrame* data_frame =
1454         reinterpret_cast<SpdyDataFrame*>(new_frame.get());
1455     data_frame->set_flags(data_frame->flags() | DATA_FLAG_COMPRESSED);
1456   }
1457 
1458 #ifndef ANDROID
1459   // Make sure that all the data we pass to zlib is defined.
1460   // This way, all Valgrind reports on the compressed data are zlib's fault.
1461   (void)VALGRIND_CHECK_MEM_IS_DEFINED(compressor->next_in,
1462                                       compressor->avail_in);
1463 #endif
1464 
1465   int rv = deflate(compressor, Z_SYNC_FLUSH);
1466   if (rv != Z_OK) {  // How can we know that it compressed everything?
1467     // This shouldn't happen, right?
1468     LOG(WARNING) << "deflate failure: " << rv;
1469     return NULL;
1470   }
1471 
1472   int compressed_size = compressed_max_size - compressor->avail_out;
1473 
1474 #ifndef ANDROID
1475   // We trust zlib. Also, we can't do anything about it.
1476   // See http://www.zlib.net/zlib_faq.html#faq36
1477   (void)VALGRIND_MAKE_MEM_DEFINED(new_frame->data() + header_length,
1478                                   compressed_size);
1479 #endif
1480 
1481   new_frame->set_length(header_length + compressed_size - SpdyFrame::size());
1482 
1483   pre_compress_bytes.Add(payload_length);
1484   post_compress_bytes.Add(new_frame->length());
1485 
1486   compressed_frames.Increment();
1487 
1488   return new_frame.release();
1489 }
1490 
DecompressFrameWithZStream(const SpdyFrame & frame,z_stream * decompressor)1491 SpdyFrame* SpdyFramer::DecompressFrameWithZStream(const SpdyFrame& frame,
1492                                                   z_stream* decompressor) {
1493   int payload_length;
1494   int header_length;
1495   const char* payload;
1496 
1497   base::StatsCounter decompressed_frames("spdy.DecompressedFrames");
1498   base::StatsCounter pre_decompress_bytes("spdy.PreDeCompressSize");
1499   base::StatsCounter post_decompress_bytes("spdy.PostDeCompressSize");
1500 
1501   if (!enable_compression_)
1502     return DuplicateFrame(frame);
1503 
1504   if (!GetFrameBoundaries(frame, &payload_length, &header_length, &payload))
1505     return NULL;
1506 
1507   if (!frame.is_control_frame()) {
1508     const SpdyDataFrame& data_frame =
1509         reinterpret_cast<const SpdyDataFrame&>(frame);
1510     if ((data_frame.flags() & DATA_FLAG_COMPRESSED) == 0)
1511       return DuplicateFrame(frame);
1512   }
1513 
1514   // Create an output frame.  Assume it does not need to be longer than
1515   // the input data.
1516   size_t decompressed_max_size = kControlFrameBufferInitialSize;
1517   int new_frame_size = header_length + decompressed_max_size;
1518   if (frame.length() > decompressed_max_size)
1519     return NULL;
1520   scoped_ptr<SpdyFrame> new_frame(new SpdyFrame(new_frame_size));
1521   memcpy(new_frame->data(), frame.data(), frame.length() + SpdyFrame::size());
1522 
1523   decompressor->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload));
1524   decompressor->avail_in = payload_length;
1525   decompressor->next_out = reinterpret_cast<Bytef*>(new_frame->data()) +
1526       header_length;
1527   decompressor->avail_out = decompressed_max_size;
1528 
1529   int rv = inflate(decompressor, Z_SYNC_FLUSH);
1530   if (rv == Z_NEED_DICT) {
1531     // Need to try again with the right dictionary.
1532     if (decompressor->adler == dictionary_id) {
1533       rv = inflateSetDictionary(decompressor, (const Bytef*)kDictionary,
1534                                 kDictionarySize);
1535       if (rv == Z_OK)
1536         rv = inflate(decompressor, Z_SYNC_FLUSH);
1537     }
1538   }
1539   if (rv != Z_OK) {  // How can we know that it decompressed everything?
1540     LOG(WARNING) << "inflate failure: " << rv;
1541     return NULL;
1542   }
1543 
1544   // Unset the compressed flag for data frames.
1545   if (!new_frame->is_control_frame()) {
1546     SpdyDataFrame* data_frame =
1547         reinterpret_cast<SpdyDataFrame*>(new_frame.get());
1548     data_frame->set_flags(data_frame->flags() & ~DATA_FLAG_COMPRESSED);
1549   }
1550 
1551   int decompressed_size = decompressed_max_size - decompressor->avail_out;
1552   new_frame->set_length(header_length + decompressed_size - SpdyFrame::size());
1553 
1554   // If there is data left, then the frame didn't fully decompress.  This
1555   // means that there is stranded data at the end of this frame buffer which
1556   // will be ignored.
1557   DCHECK_EQ(decompressor->avail_in, 0u);
1558 
1559   pre_decompress_bytes.Add(frame.length());
1560   post_decompress_bytes.Add(new_frame->length());
1561 
1562   decompressed_frames.Increment();
1563 
1564   return new_frame.release();
1565 }
1566 
CleanupCompressorForStream(SpdyStreamId id)1567 void SpdyFramer::CleanupCompressorForStream(SpdyStreamId id) {
1568   CompressorMap::iterator it = stream_compressors_.find(id);
1569   if (it != stream_compressors_.end()) {
1570     z_stream* compressor = it->second;
1571     deflateEnd(compressor);
1572     delete compressor;
1573     stream_compressors_.erase(it);
1574   }
1575 }
1576 
CleanupDecompressorForStream(SpdyStreamId id)1577 void SpdyFramer::CleanupDecompressorForStream(SpdyStreamId id) {
1578   CompressorMap::iterator it = stream_decompressors_.find(id);
1579   if (it != stream_decompressors_.end()) {
1580     z_stream* decompressor = it->second;
1581     inflateEnd(decompressor);
1582     delete decompressor;
1583     stream_decompressors_.erase(it);
1584   }
1585 }
1586 
CleanupStreamCompressorsAndDecompressors()1587 void SpdyFramer::CleanupStreamCompressorsAndDecompressors() {
1588   CompressorMap::iterator it;
1589 
1590   it = stream_compressors_.begin();
1591   while (it != stream_compressors_.end()) {
1592     z_stream* compressor = it->second;
1593     deflateEnd(compressor);
1594     delete compressor;
1595     ++it;
1596   }
1597   stream_compressors_.clear();
1598 
1599   it = stream_decompressors_.begin();
1600   while (it != stream_decompressors_.end()) {
1601     z_stream* decompressor = it->second;
1602     inflateEnd(decompressor);
1603     delete decompressor;
1604     ++it;
1605   }
1606   stream_decompressors_.clear();
1607 }
1608 
BytesSafeToRead() const1609 size_t SpdyFramer::BytesSafeToRead() const {
1610   switch (state_) {
1611     case SPDY_ERROR:
1612     case SPDY_DONE:
1613     case SPDY_AUTO_RESET:
1614     case SPDY_RESET:
1615       return 0;
1616     case SPDY_READING_COMMON_HEADER:
1617       DCHECK_LT(current_frame_len_, SpdyFrame::size());
1618       return SpdyFrame::size() - current_frame_len_;
1619     case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER:
1620       return 0;
1621     // TODO(rtenneti): Add support for SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK
1622     // and SPDY_CONTROL_FRAME_HEADER_BLOCK.
1623     case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK:
1624     case SPDY_CONTROL_FRAME_HEADER_BLOCK:
1625       return 0;
1626     case SPDY_CONTROL_FRAME_PAYLOAD:
1627     case SPDY_IGNORE_REMAINING_PAYLOAD:
1628     case SPDY_FORWARD_STREAM_FRAME:
1629       return remaining_data_;
1630   }
1631   // We should never get to here.
1632   return 0;
1633 }
1634 
set_error(SpdyError error)1635 void SpdyFramer::set_error(SpdyError error) {
1636   DCHECK(visitor_);
1637   error_code_ = error;
1638   CHANGE_STATE(SPDY_ERROR);
1639   visitor_->OnError(this);
1640 }
1641 
ExpandControlFrameBuffer(size_t size)1642 void SpdyFramer::ExpandControlFrameBuffer(size_t size) {
1643   size_t alloc_size = size + SpdyFrame::size();
1644   DCHECK_LE(alloc_size, kControlFrameBufferMaxSize);
1645   if (alloc_size <= current_frame_capacity_)
1646     return;
1647   char* new_buffer = new char[alloc_size];
1648   memcpy(new_buffer, current_frame_buffer_, current_frame_len_);
1649   delete [] current_frame_buffer_;
1650   current_frame_capacity_ = alloc_size;
1651   current_frame_buffer_ = new_buffer;
1652 }
1653 
GetFrameBoundaries(const SpdyFrame & frame,int * payload_length,int * header_length,const char ** payload) const1654 bool SpdyFramer::GetFrameBoundaries(const SpdyFrame& frame,
1655                                     int* payload_length,
1656                                     int* header_length,
1657                                     const char** payload) const {
1658   size_t frame_size;
1659   if (frame.is_control_frame()) {
1660     const SpdyControlFrame& control_frame =
1661         reinterpret_cast<const SpdyControlFrame&>(frame);
1662     switch (control_frame.type()) {
1663       case SYN_STREAM:
1664         {
1665           const SpdySynStreamControlFrame& syn_frame =
1666               reinterpret_cast<const SpdySynStreamControlFrame&>(frame);
1667           frame_size = SpdySynStreamControlFrame::size();
1668           *payload_length = syn_frame.header_block_len();
1669           *header_length = frame_size;
1670           *payload = frame.data() + *header_length;
1671         }
1672         break;
1673       case SYN_REPLY:
1674         {
1675           const SpdySynReplyControlFrame& syn_frame =
1676               reinterpret_cast<const SpdySynReplyControlFrame&>(frame);
1677           frame_size = SpdySynReplyControlFrame::size();
1678           *payload_length = syn_frame.header_block_len();
1679           *header_length = frame_size;
1680           *payload = frame.data() + *header_length;
1681         }
1682         break;
1683       case HEADERS:
1684         {
1685           const SpdyHeadersControlFrame& headers_frame =
1686               reinterpret_cast<const SpdyHeadersControlFrame&>(frame);
1687           frame_size = SpdyHeadersControlFrame::size();
1688           *payload_length = headers_frame.header_block_len();
1689           *header_length = frame_size;
1690           *payload = frame.data() + *header_length;
1691         }
1692         break;
1693       default:
1694         // TODO(mbelshe): set an error?
1695         return false;  // We can't compress this frame!
1696     }
1697   } else {
1698     frame_size = SpdyFrame::size();
1699     *header_length = frame_size;
1700     *payload_length = frame.length();
1701     *payload = frame.data() + SpdyFrame::size();
1702   }
1703   return true;
1704 }
1705 
1706 }  // namespace spdy
1707