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