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 uLong dictionary_id = 0;
35
36 } // namespace
37
38 namespace spdy {
39
40 // This is just a hacked dictionary to use for shrinking HTTP-like headers.
41 // TODO(mbelshe): Use a scientific methodology for computing the dictionary.
42 const char SpdyFramer::kDictionary[] =
43 "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
44 "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
45 "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
46 "-agent10010120020120220320420520630030130230330430530630740040140240340440"
47 "5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
48 "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
49 "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
50 "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
51 "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
52 "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
53 "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
54 "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
55 ".1statusversionurl";
56 const int SpdyFramer::kDictionarySize = arraysize(kDictionary);
57
58 // By default is compression on or off.
59 bool SpdyFramer::compression_default_ = true;
60 int SpdyFramer::spdy_version_ = kSpdyProtocolVersion;
61
62 // The initial size of the control frame buffer; this is used internally
63 // as we parse through control frames. (It is exposed here for unit test
64 // purposes.)
65 size_t SpdyFramer::kControlFrameBufferInitialSize = 8 * 1024;
66
67 // The maximum size of the control frame buffer that we support.
68 // TODO(mbelshe): We should make this stream-based so there are no limits.
69 size_t SpdyFramer::kControlFrameBufferMaxSize = 16 * 1024;
70
71 #ifdef DEBUG_SPDY_STATE_CHANGES
72 #define CHANGE_STATE(newstate) \
73 { \
74 do { \
75 LOG(INFO) << "Changing state from: " \
76 << StateToString(state_) \
77 << " to " << StateToString(newstate) << "\n"; \
78 state_ = newstate; \
79 } while (false); \
80 }
81 #else
82 #define CHANGE_STATE(newstate) (state_ = newstate)
83 #endif
84
SpdyFramer()85 SpdyFramer::SpdyFramer()
86 : state_(SPDY_RESET),
87 error_code_(SPDY_NO_ERROR),
88 remaining_payload_(0),
89 remaining_control_payload_(0),
90 current_frame_buffer_(NULL),
91 current_frame_len_(0),
92 current_frame_capacity_(0),
93 enable_compression_(compression_default_),
94 visitor_(NULL) {
95 }
96
~SpdyFramer()97 SpdyFramer::~SpdyFramer() {
98 if (header_compressor_.get()) {
99 deflateEnd(header_compressor_.get());
100 }
101 if (header_decompressor_.get()) {
102 inflateEnd(header_decompressor_.get());
103 }
104 CleanupStreamCompressorsAndDecompressors();
105 delete [] current_frame_buffer_;
106 }
107
ProcessInput(const char * data,size_t len)108 size_t SpdyFramer::ProcessInput(const char* data, size_t len) {
109 DCHECK(visitor_);
110 DCHECK(data);
111
112 size_t original_len = len;
113 while (len != 0) {
114 switch (state_) {
115 case SPDY_ERROR:
116 case SPDY_DONE:
117 goto bottom;
118
119 case SPDY_AUTO_RESET:
120 case SPDY_RESET:
121 Reset();
122 CHANGE_STATE(SPDY_READING_COMMON_HEADER);
123 continue;
124
125 case SPDY_READING_COMMON_HEADER: {
126 size_t bytes_read = ProcessCommonHeader(data, len);
127 len -= bytes_read;
128 data += bytes_read;
129 continue;
130 }
131
132 // Arguably, this case is not necessary, as no bytes are consumed here.
133 // I felt it was a nice partitioning, however (which probably indicates
134 // that it should be refactored into its own function!)
135 case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER:
136 ProcessControlFrameHeader();
137 continue;
138
139 case SPDY_CONTROL_FRAME_PAYLOAD: {
140 size_t bytes_read = ProcessControlFramePayload(data, len);
141 len -= bytes_read;
142 data += bytes_read;
143 }
144 // intentional fallthrough
145 case SPDY_IGNORE_REMAINING_PAYLOAD:
146 // control frame has too-large payload
147 // intentional fallthrough
148 case SPDY_FORWARD_STREAM_FRAME: {
149 size_t bytes_read = ProcessDataFramePayload(data, len);
150 len -= bytes_read;
151 data += bytes_read;
152 continue;
153 }
154 default:
155 break;
156 }
157 }
158 bottom:
159 return original_len - len;
160 }
161
Reset()162 void SpdyFramer::Reset() {
163 state_ = SPDY_RESET;
164 error_code_ = SPDY_NO_ERROR;
165 remaining_payload_ = 0;
166 remaining_control_payload_ = 0;
167 current_frame_len_ = 0;
168 if (current_frame_capacity_ != kControlFrameBufferInitialSize) {
169 delete [] current_frame_buffer_;
170 current_frame_buffer_ = 0;
171 current_frame_capacity_ = 0;
172 ExpandControlFrameBuffer(kControlFrameBufferInitialSize);
173 }
174 }
175
ParseHeaderBlock(const SpdyFrame * frame,SpdyHeaderBlock * block)176 bool SpdyFramer::ParseHeaderBlock(const SpdyFrame* frame,
177 SpdyHeaderBlock* block) {
178 SpdyControlFrame control_frame(frame->data(), false);
179 uint32 type = control_frame.type();
180 if (type != SYN_STREAM && type != SYN_REPLY && type != HEADERS)
181 return false;
182
183 // Find the header data within the control frame.
184 scoped_ptr<SpdyFrame> decompressed_frame(DecompressFrame(*frame));
185 if (!decompressed_frame.get())
186 return false;
187
188 const char *header_data = NULL;
189 int header_length = 0;
190
191 switch (type) {
192 case SYN_STREAM:
193 {
194 SpdySynStreamControlFrame syn_frame(decompressed_frame->data(), false);
195 header_data = syn_frame.header_block();
196 header_length = syn_frame.header_block_len();
197 }
198 break;
199 case SYN_REPLY:
200 {
201 SpdySynReplyControlFrame syn_frame(decompressed_frame->data(), false);
202 header_data = syn_frame.header_block();
203 header_length = syn_frame.header_block_len();
204 }
205 break;
206 case HEADERS:
207 {
208 SpdyHeadersControlFrame header_frame(decompressed_frame->data(), false);
209 header_data = header_frame.header_block();
210 header_length = header_frame.header_block_len();
211 }
212 break;
213 }
214
215 SpdyFrameBuilder builder(header_data, header_length);
216 void* iter = NULL;
217 uint16 num_headers;
218 if (builder.ReadUInt16(&iter, &num_headers)) {
219 int index;
220 for (index = 0; index < num_headers; ++index) {
221 std::string name;
222 std::string value;
223 if (!builder.ReadString(&iter, &name))
224 break;
225 if (!builder.ReadString(&iter, &value))
226 break;
227 if (!name.size() || !value.size())
228 return false;
229 if (block->find(name) == block->end()) {
230 (*block)[name] = value;
231 } else {
232 return false;
233 }
234 }
235 return index == num_headers &&
236 iter == header_data + header_length;
237 }
238 return false;
239 }
240
CreateSynStream(SpdyStreamId stream_id,SpdyStreamId associated_stream_id,int priority,SpdyControlFlags flags,bool compressed,SpdyHeaderBlock * headers)241 SpdySynStreamControlFrame* SpdyFramer::CreateSynStream(
242 SpdyStreamId stream_id, SpdyStreamId associated_stream_id, int priority,
243 SpdyControlFlags flags, bool compressed, SpdyHeaderBlock* headers) {
244 SpdyFrameBuilder frame;
245
246 DCHECK_GT(stream_id, static_cast<SpdyStreamId>(0));
247 DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
248 DCHECK_EQ(0u, associated_stream_id & ~kStreamIdMask);
249
250 frame.WriteUInt16(kControlFlagMask | spdy_version_);
251 frame.WriteUInt16(SYN_STREAM);
252 frame.WriteUInt32(0); // Placeholder for the length and flags
253 frame.WriteUInt32(stream_id);
254 frame.WriteUInt32(associated_stream_id);
255 frame.WriteUInt16(ntohs(priority) << 6); // Priority.
256
257 frame.WriteUInt16(headers->size()); // Number of headers.
258 SpdyHeaderBlock::iterator it;
259 for (it = headers->begin(); it != headers->end(); ++it) {
260 bool wrote_header;
261 wrote_header = frame.WriteString(it->first);
262 wrote_header &= frame.WriteString(it->second);
263 DCHECK(wrote_header);
264 }
265
266 // Write the length and flags.
267 size_t length = frame.length() - SpdyFrame::size();
268 DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask));
269 FlagsAndLength flags_length;
270 flags_length.length_ = htonl(static_cast<uint32>(length));
271 DCHECK_EQ(0, flags & ~kControlFlagsMask);
272 flags_length.flags_[0] = flags;
273 frame.WriteBytesToOffset(4, &flags_length, sizeof(flags_length));
274
275 scoped_ptr<SpdyFrame> syn_frame(frame.take());
276 if (compressed) {
277 return reinterpret_cast<SpdySynStreamControlFrame*>(
278 CompressFrame(*syn_frame.get()));
279 }
280 return reinterpret_cast<SpdySynStreamControlFrame*>(syn_frame.release());
281 }
282
CreateSynReply(SpdyStreamId stream_id,SpdyControlFlags flags,bool compressed,SpdyHeaderBlock * headers)283 SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(SpdyStreamId stream_id,
284 SpdyControlFlags flags, bool compressed, SpdyHeaderBlock* headers) {
285 DCHECK_GT(stream_id, 0u);
286 DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
287
288 SpdyFrameBuilder frame;
289
290 frame.WriteUInt16(kControlFlagMask | spdy_version_);
291 frame.WriteUInt16(SYN_REPLY);
292 frame.WriteUInt32(0); // Placeholder for the length and flags.
293 frame.WriteUInt32(stream_id);
294 frame.WriteUInt16(0); // Unused
295
296 frame.WriteUInt16(headers->size()); // Number of headers.
297 SpdyHeaderBlock::iterator it;
298 for (it = headers->begin(); it != headers->end(); ++it) {
299 bool wrote_header;
300 wrote_header = frame.WriteString(it->first);
301 wrote_header &= frame.WriteString(it->second);
302 DCHECK(wrote_header);
303 }
304
305 // Write the length and flags.
306 size_t length = frame.length() - SpdyFrame::size();
307 DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask));
308 FlagsAndLength flags_length;
309 flags_length.length_ = htonl(static_cast<uint32>(length));
310 DCHECK_EQ(0, flags & ~kControlFlagsMask);
311 flags_length.flags_[0] = flags;
312 frame.WriteBytesToOffset(4, &flags_length, sizeof(flags_length));
313
314 scoped_ptr<SpdyFrame> reply_frame(frame.take());
315 if (compressed) {
316 return reinterpret_cast<SpdySynReplyControlFrame*>(
317 CompressFrame(*reply_frame.get()));
318 }
319 return reinterpret_cast<SpdySynReplyControlFrame*>(reply_frame.release());
320 }
321
322 /* static */
CreateRstStream(SpdyStreamId stream_id,SpdyStatusCodes status)323 SpdyRstStreamControlFrame* SpdyFramer::CreateRstStream(SpdyStreamId stream_id,
324 SpdyStatusCodes status) {
325 DCHECK_GT(stream_id, 0u);
326 DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
327 DCHECK_NE(status, INVALID);
328 DCHECK_LT(status, NUM_STATUS_CODES);
329
330 SpdyFrameBuilder frame;
331 frame.WriteUInt16(kControlFlagMask | spdy_version_);
332 frame.WriteUInt16(RST_STREAM);
333 frame.WriteUInt32(8);
334 frame.WriteUInt32(stream_id);
335 frame.WriteUInt32(status);
336 return reinterpret_cast<SpdyRstStreamControlFrame*>(frame.take());
337 }
338
339 /* static */
CreateSettings(const SpdySettings & values)340 SpdySettingsControlFrame* SpdyFramer::CreateSettings(
341 const SpdySettings& values) {
342 SpdyFrameBuilder frame;
343 frame.WriteUInt16(kControlFlagMask | spdy_version_);
344 frame.WriteUInt16(SETTINGS);
345 size_t settings_size = SpdySettingsControlFrame::size() - SpdyFrame::size() +
346 8 * values.size();
347 frame.WriteUInt32(settings_size);
348 frame.WriteUInt32(values.size());
349 SpdySettings::const_iterator it = values.begin();
350 while (it != values.end()) {
351 frame.WriteUInt32(it->first.id_);
352 frame.WriteUInt32(it->second);
353 ++it;
354 }
355 return reinterpret_cast<SpdySettingsControlFrame*>(frame.take());
356 }
357
358 /* static */
CreateNopFrame()359 SpdyControlFrame* SpdyFramer::CreateNopFrame() {
360 SpdyFrameBuilder frame;
361 frame.WriteUInt16(kControlFlagMask | spdy_version_);
362 frame.WriteUInt16(NOOP);
363 frame.WriteUInt32(0);
364 return reinterpret_cast<SpdyControlFrame*>(frame.take());
365 }
366
367 /* static */
CreateGoAway(SpdyStreamId last_accepted_stream_id)368 SpdyGoAwayControlFrame* SpdyFramer::CreateGoAway(
369 SpdyStreamId last_accepted_stream_id) {
370 DCHECK_EQ(0u, last_accepted_stream_id & ~kStreamIdMask);
371
372 SpdyFrameBuilder frame;
373 frame.WriteUInt16(kControlFlagMask | spdy_version_);
374 frame.WriteUInt16(GOAWAY);
375 size_t go_away_size = SpdyGoAwayControlFrame::size() - SpdyFrame::size();
376 frame.WriteUInt32(go_away_size);
377 frame.WriteUInt32(last_accepted_stream_id);
378 return reinterpret_cast<SpdyGoAwayControlFrame*>(frame.take());
379 }
380
CreateHeaders(SpdyStreamId stream_id,SpdyControlFlags flags,bool compressed,SpdyHeaderBlock * headers)381 SpdyHeadersControlFrame* SpdyFramer::CreateHeaders(SpdyStreamId stream_id,
382 SpdyControlFlags flags, bool compressed, SpdyHeaderBlock* headers) {
383 // Basically the same as CreateSynReply().
384 DCHECK_GT(stream_id, 0u);
385 DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
386
387 SpdyFrameBuilder frame;
388 frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion);
389 frame.WriteUInt16(HEADERS);
390 frame.WriteUInt32(0); // Placeholder for the length and flags.
391 frame.WriteUInt32(stream_id);
392 frame.WriteUInt16(0); // Unused
393
394 frame.WriteUInt16(headers->size()); // Number of headers.
395 SpdyHeaderBlock::iterator it;
396 for (it = headers->begin(); it != headers->end(); ++it) {
397 bool wrote_header;
398 wrote_header = frame.WriteString(it->first);
399 wrote_header &= frame.WriteString(it->second);
400 DCHECK(wrote_header);
401 }
402
403 // Write the length and flags.
404 size_t length = frame.length() - SpdyFrame::size();
405 DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask));
406 FlagsAndLength flags_length;
407 flags_length.length_ = htonl(static_cast<uint32>(length));
408 DCHECK_EQ(0, flags & ~kControlFlagsMask);
409 flags_length.flags_[0] = flags;
410 frame.WriteBytesToOffset(4, &flags_length, sizeof(flags_length));
411
412 scoped_ptr<SpdyFrame> headers_frame(frame.take());
413 if (compressed) {
414 return reinterpret_cast<SpdyHeadersControlFrame*>(
415 CompressFrame(*headers_frame.get()));
416 }
417 return reinterpret_cast<SpdyHeadersControlFrame*>(headers_frame.release());
418 }
419
420 /* static */
CreateWindowUpdate(SpdyStreamId stream_id,uint32 delta_window_size)421 SpdyWindowUpdateControlFrame* SpdyFramer::CreateWindowUpdate(
422 SpdyStreamId stream_id,
423 uint32 delta_window_size) {
424 DCHECK_GT(stream_id, 0u);
425 DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
426 DCHECK_GT(delta_window_size, 0u);
427 DCHECK_LE(delta_window_size, spdy::kSpdyStreamMaximumWindowSize);
428
429 SpdyFrameBuilder frame;
430 frame.WriteUInt16(kControlFlagMask | spdy_version_);
431 frame.WriteUInt16(WINDOW_UPDATE);
432 size_t window_update_size = SpdyWindowUpdateControlFrame::size() -
433 SpdyFrame::size();
434 frame.WriteUInt32(window_update_size);
435 frame.WriteUInt32(stream_id);
436 frame.WriteUInt32(delta_window_size);
437 return reinterpret_cast<SpdyWindowUpdateControlFrame*>(frame.take());
438 }
439
440 /* static */
ParseSettings(const SpdySettingsControlFrame * frame,SpdySettings * settings)441 bool SpdyFramer::ParseSettings(const SpdySettingsControlFrame* frame,
442 SpdySettings* settings) {
443 DCHECK_EQ(frame->type(), SETTINGS);
444 DCHECK(settings);
445
446 SpdyFrameBuilder parser(frame->header_block(), frame->header_block_len());
447 void* iter = NULL;
448 for (size_t index = 0; index < frame->num_entries(); ++index) {
449 uint32 id;
450 uint32 value;
451 if (!parser.ReadUInt32(&iter, &id))
452 return false;
453 if (!parser.ReadUInt32(&iter, &value))
454 return false;
455 settings->insert(settings->end(), std::make_pair(id, value));
456 }
457 return true;
458 }
459
CreateDataFrame(SpdyStreamId stream_id,const char * data,uint32 len,SpdyDataFlags flags)460 SpdyDataFrame* SpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
461 const char* data,
462 uint32 len, SpdyDataFlags flags) {
463 SpdyFrameBuilder frame;
464
465 DCHECK_GT(stream_id, 0u);
466 DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
467 frame.WriteUInt32(stream_id);
468
469 DCHECK_EQ(0u, len & ~static_cast<size_t>(kLengthMask));
470 FlagsAndLength flags_length;
471 flags_length.length_ = htonl(len);
472 DCHECK_EQ(0, flags & ~kDataFlagsMask);
473 flags_length.flags_[0] = flags;
474 frame.WriteBytes(&flags_length, sizeof(flags_length));
475
476 frame.WriteBytes(data, len);
477 scoped_ptr<SpdyFrame> data_frame(frame.take());
478 SpdyDataFrame* rv;
479 if (flags & DATA_FLAG_COMPRESSED) {
480 rv = reinterpret_cast<SpdyDataFrame*>(CompressFrame(*data_frame.get()));
481 } else {
482 rv = reinterpret_cast<SpdyDataFrame*>(data_frame.release());
483 }
484
485 if (flags & DATA_FLAG_FIN) {
486 CleanupCompressorForStream(stream_id);
487 }
488
489 return rv;
490 }
491
CompressFrame(const SpdyFrame & frame)492 SpdyFrame* SpdyFramer::CompressFrame(const SpdyFrame& frame) {
493 if (frame.is_control_frame()) {
494 return CompressControlFrame(
495 reinterpret_cast<const SpdyControlFrame&>(frame));
496 }
497 return CompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame));
498 }
499
DecompressFrame(const SpdyFrame & frame)500 SpdyFrame* SpdyFramer::DecompressFrame(const SpdyFrame& frame) {
501 if (frame.is_control_frame()) {
502 return DecompressControlFrame(
503 reinterpret_cast<const SpdyControlFrame&>(frame));
504 }
505 return DecompressDataFrame(reinterpret_cast<const SpdyDataFrame&>(frame));
506 }
507
DuplicateFrame(const SpdyFrame & frame)508 SpdyFrame* SpdyFramer::DuplicateFrame(const SpdyFrame& frame) {
509 int size = SpdyFrame::size() + frame.length();
510 SpdyFrame* new_frame = new SpdyFrame(size);
511 memcpy(new_frame->data(), frame.data(), size);
512 return new_frame;
513 }
514
IsCompressible(const SpdyFrame & frame) const515 bool SpdyFramer::IsCompressible(const SpdyFrame& frame) const {
516 // The important frames to compress are those which contain large
517 // amounts of compressible data - namely the headers in the SYN_STREAM
518 // and SYN_REPLY.
519 // TODO(mbelshe): Reconcile this with the spec when the spec is
520 // explicit about which frames compress and which do not.
521 if (frame.is_control_frame()) {
522 const SpdyControlFrame& control_frame =
523 reinterpret_cast<const SpdyControlFrame&>(frame);
524 return control_frame.type() == SYN_STREAM ||
525 control_frame.type() == SYN_REPLY;
526 }
527
528 const SpdyDataFrame& data_frame =
529 reinterpret_cast<const SpdyDataFrame&>(frame);
530 return (data_frame.flags() & DATA_FLAG_COMPRESSED) != 0;
531 }
532
StateToString(int state)533 const char* SpdyFramer::StateToString(int state) {
534 switch (state) {
535 case SPDY_ERROR:
536 return "ERROR";
537 case SPDY_DONE:
538 return "DONE";
539 case SPDY_AUTO_RESET:
540 return "AUTO_RESET";
541 case SPDY_RESET:
542 return "RESET";
543 case SPDY_READING_COMMON_HEADER:
544 return "READING_COMMON_HEADER";
545 case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER:
546 return "INTERPRET_CONTROL_FRAME_COMMON_HEADER";
547 case SPDY_CONTROL_FRAME_PAYLOAD:
548 return "CONTROL_FRAME_PAYLOAD";
549 case SPDY_IGNORE_REMAINING_PAYLOAD:
550 return "IGNORE_REMAINING_PAYLOAD";
551 case SPDY_FORWARD_STREAM_FRAME:
552 return "FORWARD_STREAM_FRAME";
553 }
554 return "UNKNOWN_STATE";
555 }
556
ErrorCodeToString(int error_code)557 const char* SpdyFramer::ErrorCodeToString(int error_code) {
558 switch (error_code) {
559 case SPDY_NO_ERROR:
560 return "NO_ERROR";
561 case SPDY_INVALID_CONTROL_FRAME:
562 return "INVALID_CONTROL_FRAME";
563 case SPDY_CONTROL_PAYLOAD_TOO_LARGE:
564 return "CONTROL_PAYLOAD_TOO_LARGE";
565 case SPDY_ZLIB_INIT_FAILURE:
566 return "ZLIB_INIT_FAILURE";
567 case SPDY_UNSUPPORTED_VERSION:
568 return "UNSUPPORTED_VERSION";
569 case SPDY_DECOMPRESS_FAILURE:
570 return "DECOMPRESS_FAILURE";
571 case SPDY_COMPRESS_FAILURE:
572 return "COMPRESS_FAILURE";
573 }
574 return "UNKNOWN_ERROR";
575 }
576
set_enable_compression(bool value)577 void SpdyFramer::set_enable_compression(bool value) {
578 enable_compression_ = value;
579 }
580
set_enable_compression_default(bool value)581 void SpdyFramer::set_enable_compression_default(bool value) {
582 compression_default_ = value;
583 }
584
ProcessCommonHeader(const char * data,size_t len)585 size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
586 // This should only be called when we're in the SPDY_READING_COMMON_HEADER
587 // state.
588 DCHECK_EQ(state_, SPDY_READING_COMMON_HEADER);
589
590 size_t original_len = len;
591 SpdyFrame current_frame(current_frame_buffer_, false);
592
593 do {
594 if (current_frame_len_ < SpdyFrame::size()) {
595 size_t bytes_desired = SpdyFrame::size() - current_frame_len_;
596 size_t bytes_to_append = std::min(bytes_desired, len);
597 char* header_buffer = current_frame_buffer_;
598 memcpy(&header_buffer[current_frame_len_], data, bytes_to_append);
599 current_frame_len_ += bytes_to_append;
600 data += bytes_to_append;
601 len -= bytes_to_append;
602 // Check for an empty data frame.
603 if (current_frame_len_ == SpdyFrame::size() &&
604 !current_frame.is_control_frame() &&
605 current_frame.length() == 0) {
606 if (current_frame.flags() & CONTROL_FLAG_FIN) {
607 SpdyDataFrame data_frame(current_frame_buffer_, false);
608 visitor_->OnStreamFrameData(data_frame.stream_id(), NULL, 0);
609 }
610 CHANGE_STATE(SPDY_AUTO_RESET);
611 }
612 break;
613 }
614 remaining_payload_ = current_frame.length();
615
616 // This is just a sanity check for help debugging early frame errors.
617 if (remaining_payload_ > 1000000u) {
618 LOG(WARNING) <<
619 "Unexpectedly large frame. Spdy session is likely corrupt.";
620 }
621
622 // if we're here, then we have the common header all received.
623 if (!current_frame.is_control_frame())
624 CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
625 else
626 CHANGE_STATE(SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER);
627 } while (false);
628
629 return original_len - len;
630 }
631
ProcessControlFrameHeader()632 void SpdyFramer::ProcessControlFrameHeader() {
633 DCHECK_EQ(SPDY_NO_ERROR, error_code_);
634 DCHECK_LE(SpdyFrame::size(), current_frame_len_);
635 SpdyControlFrame current_control_frame(current_frame_buffer_, false);
636
637 // We check version before we check validity: version can never be 'invalid',
638 // it can only be unsupported.
639 if (current_control_frame.version() != spdy_version_) {
640 set_error(SPDY_UNSUPPORTED_VERSION);
641 return;
642 }
643
644 // Next up, check to see if we have valid data. This should be after version
645 // checking (otherwise if the the type were out of bounds due to a version
646 // upgrade we would misclassify the error) and before checking the type
647 // (type can definitely be out of bounds)
648 if (!current_control_frame.AppearsToBeAValidControlFrame()) {
649 set_error(SPDY_INVALID_CONTROL_FRAME);
650 return;
651 }
652
653 // Do some sanity checking on the control frame sizes.
654 switch (current_control_frame.type()) {
655 case SYN_STREAM:
656 if (current_control_frame.length() <
657 SpdySynStreamControlFrame::size() - SpdyControlFrame::size())
658 set_error(SPDY_INVALID_CONTROL_FRAME);
659 break;
660 case SYN_REPLY:
661 if (current_control_frame.length() <
662 SpdySynReplyControlFrame::size() - SpdyControlFrame::size())
663 set_error(SPDY_INVALID_CONTROL_FRAME);
664 break;
665 case RST_STREAM:
666 if (current_control_frame.length() !=
667 SpdyRstStreamControlFrame::size() - SpdyFrame::size())
668 set_error(SPDY_INVALID_CONTROL_FRAME);
669 break;
670 case SETTINGS:
671 if (current_control_frame.length() <
672 SpdySettingsControlFrame::size() - SpdyControlFrame::size())
673 set_error(SPDY_INVALID_CONTROL_FRAME);
674 break;
675 case NOOP:
676 // NOOP. Swallow it.
677 CHANGE_STATE(SPDY_AUTO_RESET);
678 return;
679 case GOAWAY:
680 if (current_control_frame.length() !=
681 SpdyGoAwayControlFrame::size() - SpdyFrame::size())
682 set_error(SPDY_INVALID_CONTROL_FRAME);
683 break;
684 case HEADERS:
685 if (current_control_frame.length() <
686 SpdyHeadersControlFrame::size() - SpdyControlFrame::size())
687 set_error(SPDY_INVALID_CONTROL_FRAME);
688 break;
689 case WINDOW_UPDATE:
690 if (current_control_frame.length() !=
691 SpdyWindowUpdateControlFrame::size() - SpdyControlFrame::size())
692 set_error(SPDY_INVALID_CONTROL_FRAME);
693 break;
694 default:
695 LOG(WARNING) << "Valid spdy control frame with unknown type: "
696 << current_control_frame.type();
697 DCHECK(false);
698 set_error(SPDY_INVALID_CONTROL_FRAME);
699 break;
700 }
701
702 remaining_control_payload_ = current_control_frame.length();
703 if (remaining_control_payload_ > kControlFrameBufferMaxSize) {
704 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
705 return;
706 }
707
708 ExpandControlFrameBuffer(remaining_control_payload_);
709 CHANGE_STATE(SPDY_CONTROL_FRAME_PAYLOAD);
710 }
711
ProcessControlFramePayload(const char * data,size_t len)712 size_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) {
713 size_t original_len = len;
714 do {
715 if (remaining_control_payload_) {
716 size_t amount_to_consume = std::min(remaining_control_payload_, len);
717 memcpy(¤t_frame_buffer_[current_frame_len_], data,
718 amount_to_consume);
719 current_frame_len_ += amount_to_consume;
720 data += amount_to_consume;
721 len -= amount_to_consume;
722 remaining_control_payload_ -= amount_to_consume;
723 remaining_payload_ -= amount_to_consume;
724 if (remaining_control_payload_)
725 break;
726 }
727 SpdyControlFrame control_frame(current_frame_buffer_, false);
728 visitor_->OnControl(&control_frame);
729
730 // If this is a FIN, tell the caller.
731 if (control_frame.type() == SYN_REPLY &&
732 control_frame.flags() & CONTROL_FLAG_FIN) {
733 visitor_->OnStreamFrameData(reinterpret_cast<SpdySynReplyControlFrame*>(
734 &control_frame)->stream_id(),
735 NULL, 0);
736 }
737
738 CHANGE_STATE(SPDY_IGNORE_REMAINING_PAYLOAD);
739 } while (false);
740 return original_len - len;
741 }
742
ProcessDataFramePayload(const char * data,size_t len)743 size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) {
744 size_t original_len = len;
745
746 SpdyDataFrame current_data_frame(current_frame_buffer_, false);
747 if (remaining_payload_) {
748 size_t amount_to_forward = std::min(remaining_payload_, len);
749 if (amount_to_forward && state_ != SPDY_IGNORE_REMAINING_PAYLOAD) {
750 if (current_data_frame.flags() & DATA_FLAG_COMPRESSED) {
751 z_stream* decompressor =
752 GetStreamDecompressor(current_data_frame.stream_id());
753 if (!decompressor)
754 return 0;
755
756 size_t decompressed_max_size = amount_to_forward * 100;
757 scoped_array<char> decompressed(new char[decompressed_max_size]);
758 decompressor->next_in = reinterpret_cast<Bytef*>(
759 const_cast<char*>(data));
760 decompressor->avail_in = amount_to_forward;
761 decompressor->next_out =
762 reinterpret_cast<Bytef*>(decompressed.get());
763 decompressor->avail_out = decompressed_max_size;
764
765 int rv = inflate(decompressor, Z_SYNC_FLUSH);
766 if (rv != Z_OK) {
767 LOG(WARNING) << "inflate failure: " << rv;
768 set_error(SPDY_DECOMPRESS_FAILURE);
769 return 0;
770 }
771 size_t decompressed_size = decompressed_max_size -
772 decompressor->avail_out;
773
774 // Only inform the visitor if there is data.
775 if (decompressed_size)
776 visitor_->OnStreamFrameData(current_data_frame.stream_id(),
777 decompressed.get(),
778 decompressed_size);
779 amount_to_forward -= decompressor->avail_in;
780 } else {
781 // The data frame was not compressed.
782 // Only inform the visitor if there is data.
783 if (amount_to_forward)
784 visitor_->OnStreamFrameData(current_data_frame.stream_id(),
785 data, amount_to_forward);
786 }
787 }
788 data += amount_to_forward;
789 len -= amount_to_forward;
790 remaining_payload_ -= amount_to_forward;
791
792 // If the FIN flag is set, and there is no more data in this data
793 // frame, inform the visitor of EOF via a 0-length data frame.
794 if (!remaining_payload_ &&
795 current_data_frame.flags() & DATA_FLAG_FIN) {
796 visitor_->OnStreamFrameData(current_data_frame.stream_id(), NULL, 0);
797 CleanupDecompressorForStream(current_data_frame.stream_id());
798 }
799 } else {
800 CHANGE_STATE(SPDY_AUTO_RESET);
801 }
802 return original_len - len;
803 }
804
GetHeaderCompressor()805 z_stream* SpdyFramer::GetHeaderCompressor() {
806 if (header_compressor_.get())
807 return header_compressor_.get(); // Already initialized.
808
809 header_compressor_.reset(new z_stream);
810 memset(header_compressor_.get(), 0, sizeof(z_stream));
811
812 int success = deflateInit2(header_compressor_.get(),
813 kCompressorLevel,
814 Z_DEFLATED,
815 kCompressorWindowSizeInBits,
816 kCompressorMemLevel,
817 Z_DEFAULT_STRATEGY);
818 if (success == Z_OK)
819 success = deflateSetDictionary(header_compressor_.get(),
820 reinterpret_cast<const Bytef*>(kDictionary),
821 kDictionarySize);
822 if (success != Z_OK) {
823 LOG(WARNING) << "deflateSetDictionary failure: " << success;
824 header_compressor_.reset(NULL);
825 return NULL;
826 }
827 return header_compressor_.get();
828 }
829
GetHeaderDecompressor()830 z_stream* SpdyFramer::GetHeaderDecompressor() {
831 if (header_decompressor_.get())
832 return header_decompressor_.get(); // Already initialized.
833
834 header_decompressor_.reset(new z_stream);
835 memset(header_decompressor_.get(), 0, sizeof(z_stream));
836
837 // Compute the id of our dictionary so that we know we're using the
838 // right one when asked for it.
839 if (dictionary_id == 0) {
840 dictionary_id = adler32(0L, Z_NULL, 0);
841 dictionary_id = adler32(dictionary_id,
842 reinterpret_cast<const Bytef*>(kDictionary),
843 kDictionarySize);
844 }
845
846 int success = inflateInit(header_decompressor_.get());
847 if (success != Z_OK) {
848 LOG(WARNING) << "inflateInit failure: " << success;
849 header_decompressor_.reset(NULL);
850 return NULL;
851 }
852 return header_decompressor_.get();
853 }
854
GetStreamCompressor(SpdyStreamId stream_id)855 z_stream* SpdyFramer::GetStreamCompressor(SpdyStreamId stream_id) {
856 CompressorMap::iterator it = stream_compressors_.find(stream_id);
857 if (it != stream_compressors_.end())
858 return it->second; // Already initialized.
859
860 scoped_ptr<z_stream> compressor(new z_stream);
861 memset(compressor.get(), 0, sizeof(z_stream));
862
863 int success = deflateInit2(compressor.get(),
864 kCompressorLevel,
865 Z_DEFLATED,
866 kCompressorWindowSizeInBits,
867 kCompressorMemLevel,
868 Z_DEFAULT_STRATEGY);
869 if (success != Z_OK) {
870 LOG(WARNING) << "deflateInit failure: " << success;
871 return NULL;
872 }
873 return stream_compressors_[stream_id] = compressor.release();
874 }
875
GetStreamDecompressor(SpdyStreamId stream_id)876 z_stream* SpdyFramer::GetStreamDecompressor(SpdyStreamId stream_id) {
877 CompressorMap::iterator it = stream_decompressors_.find(stream_id);
878 if (it != stream_decompressors_.end())
879 return it->second; // Already initialized.
880
881 scoped_ptr<z_stream> decompressor(new z_stream);
882 memset(decompressor.get(), 0, sizeof(z_stream));
883
884 int success = inflateInit(decompressor.get());
885 if (success != Z_OK) {
886 LOG(WARNING) << "inflateInit failure: " << success;
887 return NULL;
888 }
889 return stream_decompressors_[stream_id] = decompressor.release();
890 }
891
CompressControlFrame(const SpdyControlFrame & frame)892 SpdyControlFrame* SpdyFramer::CompressControlFrame(
893 const SpdyControlFrame& frame) {
894 z_stream* compressor = GetHeaderCompressor();
895 if (!compressor)
896 return NULL;
897 return reinterpret_cast<SpdyControlFrame*>(
898 CompressFrameWithZStream(frame, compressor));
899 }
900
CompressDataFrame(const SpdyDataFrame & frame)901 SpdyDataFrame* SpdyFramer::CompressDataFrame(const SpdyDataFrame& frame) {
902 z_stream* compressor = GetStreamCompressor(frame.stream_id());
903 if (!compressor)
904 return NULL;
905 return reinterpret_cast<SpdyDataFrame*>(
906 CompressFrameWithZStream(frame, compressor));
907 }
908
DecompressControlFrame(const SpdyControlFrame & frame)909 SpdyControlFrame* SpdyFramer::DecompressControlFrame(
910 const SpdyControlFrame& frame) {
911 z_stream* decompressor = GetHeaderDecompressor();
912 if (!decompressor)
913 return NULL;
914 return reinterpret_cast<SpdyControlFrame*>(
915 DecompressFrameWithZStream(frame, decompressor));
916 }
917
DecompressDataFrame(const SpdyDataFrame & frame)918 SpdyDataFrame* SpdyFramer::DecompressDataFrame(const SpdyDataFrame& frame) {
919 z_stream* decompressor = GetStreamDecompressor(frame.stream_id());
920 if (!decompressor)
921 return NULL;
922 return reinterpret_cast<SpdyDataFrame*>(
923 DecompressFrameWithZStream(frame, decompressor));
924 }
925
CompressFrameWithZStream(const SpdyFrame & frame,z_stream * compressor)926 SpdyFrame* SpdyFramer::CompressFrameWithZStream(const SpdyFrame& frame,
927 z_stream* compressor) {
928 int payload_length;
929 int header_length;
930 const char* payload;
931
932 base::StatsCounter compressed_frames("spdy.CompressedFrames");
933 base::StatsCounter pre_compress_bytes("spdy.PreCompressSize");
934 base::StatsCounter post_compress_bytes("spdy.PostCompressSize");
935
936 if (!enable_compression_)
937 return DuplicateFrame(frame);
938
939 if (!GetFrameBoundaries(frame, &payload_length, &header_length, &payload))
940 return NULL;
941
942 // Create an output frame.
943 int compressed_max_size = deflateBound(compressor, payload_length);
944 int new_frame_size = header_length + compressed_max_size;
945 scoped_ptr<SpdyFrame> new_frame(new SpdyFrame(new_frame_size));
946 memcpy(new_frame->data(), frame.data(), frame.length() + SpdyFrame::size());
947
948 compressor->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload));
949 compressor->avail_in = payload_length;
950 compressor->next_out = reinterpret_cast<Bytef*>(new_frame->data()) +
951 header_length;
952 compressor->avail_out = compressed_max_size;
953
954 // Data packets have a 'compressed' flag.
955 if (!new_frame->is_control_frame()) {
956 SpdyDataFrame* data_frame =
957 reinterpret_cast<SpdyDataFrame*>(new_frame.get());
958 data_frame->set_flags(data_frame->flags() | DATA_FLAG_COMPRESSED);
959 }
960
961 #ifndef ANDROID
962 // Make sure that all the data we pass to zlib is defined.
963 // This way, all Valgrind reports on the compressed data are zlib's fault.
964 (void)VALGRIND_CHECK_MEM_IS_DEFINED(compressor->next_in,
965 compressor->avail_in);
966 #endif
967
968 int rv = deflate(compressor, Z_SYNC_FLUSH);
969 if (rv != Z_OK) { // How can we know that it compressed everything?
970 // This shouldn't happen, right?
971 LOG(WARNING) << "deflate failure: " << rv;
972 return NULL;
973 }
974
975 int compressed_size = compressed_max_size - compressor->avail_out;
976
977 #ifndef ANDROID
978 // We trust zlib. Also, we can't do anything about it.
979 // See http://www.zlib.net/zlib_faq.html#faq36
980 (void)VALGRIND_MAKE_MEM_DEFINED(new_frame->data() + header_length,
981 compressed_size);
982 #endif
983
984 new_frame->set_length(header_length + compressed_size - SpdyFrame::size());
985
986 pre_compress_bytes.Add(payload_length);
987 post_compress_bytes.Add(new_frame->length());
988
989 compressed_frames.Increment();
990
991 return new_frame.release();
992 }
993
DecompressFrameWithZStream(const SpdyFrame & frame,z_stream * decompressor)994 SpdyFrame* SpdyFramer::DecompressFrameWithZStream(const SpdyFrame& frame,
995 z_stream* decompressor) {
996 int payload_length;
997 int header_length;
998 const char* payload;
999
1000 base::StatsCounter decompressed_frames("spdy.DecompressedFrames");
1001 base::StatsCounter pre_decompress_bytes("spdy.PreDeCompressSize");
1002 base::StatsCounter post_decompress_bytes("spdy.PostDeCompressSize");
1003
1004 if (!enable_compression_)
1005 return DuplicateFrame(frame);
1006
1007 if (!GetFrameBoundaries(frame, &payload_length, &header_length, &payload))
1008 return NULL;
1009
1010 if (!frame.is_control_frame()) {
1011 const SpdyDataFrame& data_frame =
1012 reinterpret_cast<const SpdyDataFrame&>(frame);
1013 if ((data_frame.flags() & DATA_FLAG_COMPRESSED) == 0)
1014 return DuplicateFrame(frame);
1015 }
1016
1017 // Create an output frame. Assume it does not need to be longer than
1018 // the input data.
1019 size_t decompressed_max_size = kControlFrameBufferInitialSize;
1020 int new_frame_size = header_length + decompressed_max_size;
1021 if (frame.length() > decompressed_max_size)
1022 return NULL;
1023 scoped_ptr<SpdyFrame> new_frame(new SpdyFrame(new_frame_size));
1024 memcpy(new_frame->data(), frame.data(), frame.length() + SpdyFrame::size());
1025
1026 decompressor->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload));
1027 decompressor->avail_in = payload_length;
1028 decompressor->next_out = reinterpret_cast<Bytef*>(new_frame->data()) +
1029 header_length;
1030 decompressor->avail_out = decompressed_max_size;
1031
1032 int rv = inflate(decompressor, Z_SYNC_FLUSH);
1033 if (rv == Z_NEED_DICT) {
1034 // Need to try again with the right dictionary.
1035 if (decompressor->adler == dictionary_id) {
1036 rv = inflateSetDictionary(decompressor, (const Bytef*)kDictionary,
1037 kDictionarySize);
1038 if (rv == Z_OK)
1039 rv = inflate(decompressor, Z_SYNC_FLUSH);
1040 }
1041 }
1042 if (rv != Z_OK) { // How can we know that it decompressed everything?
1043 LOG(WARNING) << "inflate failure: " << rv;
1044 return NULL;
1045 }
1046
1047 // Unset the compressed flag for data frames.
1048 if (!new_frame->is_control_frame()) {
1049 SpdyDataFrame* data_frame =
1050 reinterpret_cast<SpdyDataFrame*>(new_frame.get());
1051 data_frame->set_flags(data_frame->flags() & ~DATA_FLAG_COMPRESSED);
1052 }
1053
1054 int decompressed_size = decompressed_max_size - decompressor->avail_out;
1055 new_frame->set_length(header_length + decompressed_size - SpdyFrame::size());
1056
1057 // If there is data left, then the frame didn't fully decompress. This
1058 // means that there is stranded data at the end of this frame buffer which
1059 // will be ignored.
1060 DCHECK_EQ(decompressor->avail_in, 0u);
1061
1062 pre_decompress_bytes.Add(frame.length());
1063 post_decompress_bytes.Add(new_frame->length());
1064
1065 decompressed_frames.Increment();
1066
1067 return new_frame.release();
1068 }
1069
CleanupCompressorForStream(SpdyStreamId id)1070 void SpdyFramer::CleanupCompressorForStream(SpdyStreamId id) {
1071 CompressorMap::iterator it = stream_compressors_.find(id);
1072 if (it != stream_compressors_.end()) {
1073 z_stream* compressor = it->second;
1074 deflateEnd(compressor);
1075 delete compressor;
1076 stream_compressors_.erase(it);
1077 }
1078 }
1079
CleanupDecompressorForStream(SpdyStreamId id)1080 void SpdyFramer::CleanupDecompressorForStream(SpdyStreamId id) {
1081 CompressorMap::iterator it = stream_decompressors_.find(id);
1082 if (it != stream_decompressors_.end()) {
1083 z_stream* decompressor = it->second;
1084 inflateEnd(decompressor);
1085 delete decompressor;
1086 stream_decompressors_.erase(it);
1087 }
1088 }
1089
CleanupStreamCompressorsAndDecompressors()1090 void SpdyFramer::CleanupStreamCompressorsAndDecompressors() {
1091 CompressorMap::iterator it;
1092
1093 it = stream_compressors_.begin();
1094 while (it != stream_compressors_.end()) {
1095 z_stream* compressor = it->second;
1096 deflateEnd(compressor);
1097 delete compressor;
1098 ++it;
1099 }
1100 stream_compressors_.clear();
1101
1102 it = stream_decompressors_.begin();
1103 while (it != stream_decompressors_.end()) {
1104 z_stream* decompressor = it->second;
1105 inflateEnd(decompressor);
1106 delete decompressor;
1107 ++it;
1108 }
1109 stream_decompressors_.clear();
1110 }
1111
BytesSafeToRead() const1112 size_t SpdyFramer::BytesSafeToRead() const {
1113 switch (state_) {
1114 case SPDY_ERROR:
1115 case SPDY_DONE:
1116 case SPDY_AUTO_RESET:
1117 case SPDY_RESET:
1118 return 0;
1119 case SPDY_READING_COMMON_HEADER:
1120 DCHECK_LT(current_frame_len_, SpdyFrame::size());
1121 return SpdyFrame::size() - current_frame_len_;
1122 case SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER:
1123 return 0;
1124 case SPDY_CONTROL_FRAME_PAYLOAD:
1125 case SPDY_IGNORE_REMAINING_PAYLOAD:
1126 case SPDY_FORWARD_STREAM_FRAME:
1127 return remaining_payload_;
1128 }
1129 // We should never get to here.
1130 return 0;
1131 }
1132
set_error(SpdyError error)1133 void SpdyFramer::set_error(SpdyError error) {
1134 DCHECK(visitor_);
1135 error_code_ = error;
1136 CHANGE_STATE(SPDY_ERROR);
1137 visitor_->OnError(this);
1138 }
1139
ExpandControlFrameBuffer(size_t size)1140 void SpdyFramer::ExpandControlFrameBuffer(size_t size) {
1141 size_t alloc_size = size + SpdyFrame::size();
1142 DCHECK_LT(alloc_size, kControlFrameBufferMaxSize);
1143 if (alloc_size <= current_frame_capacity_)
1144 return;
1145 char* new_buffer = new char[alloc_size];
1146 memcpy(new_buffer, current_frame_buffer_, current_frame_len_);
1147 delete [] current_frame_buffer_;
1148 current_frame_capacity_ = alloc_size;
1149 current_frame_buffer_ = new_buffer;
1150 }
1151
GetFrameBoundaries(const SpdyFrame & frame,int * payload_length,int * header_length,const char ** payload) const1152 bool SpdyFramer::GetFrameBoundaries(const SpdyFrame& frame,
1153 int* payload_length,
1154 int* header_length,
1155 const char** payload) const {
1156 size_t frame_size;
1157 if (frame.is_control_frame()) {
1158 const SpdyControlFrame& control_frame =
1159 reinterpret_cast<const SpdyControlFrame&>(frame);
1160 switch (control_frame.type()) {
1161 case SYN_STREAM:
1162 {
1163 const SpdySynStreamControlFrame& syn_frame =
1164 reinterpret_cast<const SpdySynStreamControlFrame&>(frame);
1165 frame_size = SpdySynStreamControlFrame::size();
1166 *payload_length = syn_frame.header_block_len();
1167 *header_length = frame_size;
1168 *payload = frame.data() + *header_length;
1169 }
1170 break;
1171 case SYN_REPLY:
1172 {
1173 const SpdySynReplyControlFrame& syn_frame =
1174 reinterpret_cast<const SpdySynReplyControlFrame&>(frame);
1175 frame_size = SpdySynReplyControlFrame::size();
1176 *payload_length = syn_frame.header_block_len();
1177 *header_length = frame_size;
1178 *payload = frame.data() + *header_length;
1179 }
1180 break;
1181 case HEADERS:
1182 {
1183 const SpdyHeadersControlFrame& headers_frame =
1184 reinterpret_cast<const SpdyHeadersControlFrame&>(frame);
1185 frame_size = SpdyHeadersControlFrame::size();
1186 *payload_length = headers_frame.header_block_len();
1187 *header_length = frame_size;
1188 *payload = frame.data() + *header_length;
1189 }
1190 break;
1191 default:
1192 // TODO(mbelshe): set an error?
1193 return false; // We can't compress this frame!
1194 }
1195 } else {
1196 frame_size = SpdyFrame::size();
1197 *header_length = frame_size;
1198 *payload_length = frame.length();
1199 *payload = frame.data() + SpdyFrame::size();
1200 }
1201 return true;
1202 }
1203
1204 } // namespace spdy
1205