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(¤t_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