Enables compositing support for webview.
[chromium-blink-merge.git] / net / spdy / spdy_framer.cc
blob87d061423f3794ccf48d057e142896d3a2d37658
1 // Copyright (c) 2012 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.
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.
9 #include "net/spdy/spdy_framer.h"
11 #include "base/lazy_instance.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/metrics/stats_counters.h"
14 #include "base/third_party/valgrind/memcheck.h"
15 #include "net/spdy/spdy_frame_builder.h"
16 #include "net/spdy/spdy_frame_reader.h"
17 #include "net/spdy/spdy_bitmasks.h"
18 #include "third_party/zlib/zlib.h"
20 using std::vector;
22 namespace net {
24 namespace {
26 // Compute the id of our dictionary so that we know we're using the
27 // right one when asked for it.
28 uLong CalculateDictionaryId(const char* dictionary,
29 const size_t dictionary_size) {
30 uLong initial_value = adler32(0L, Z_NULL, 0);
31 return adler32(initial_value,
32 reinterpret_cast<const Bytef*>(dictionary),
33 dictionary_size);
36 struct DictionaryIds {
37 DictionaryIds()
38 : v2_dictionary_id(CalculateDictionaryId(kV2Dictionary, kV2DictionarySize)),
39 v3_dictionary_id(CalculateDictionaryId(kV3Dictionary, kV3DictionarySize))
41 const uLong v2_dictionary_id;
42 const uLong v3_dictionary_id;
45 // Adler ID for the SPDY header compressor dictionaries. Note that they are
46 // initialized lazily to avoid static initializers.
47 base::LazyInstance<DictionaryIds>::Leaky g_dictionary_ids;
49 } // namespace
51 const int SpdyFramer::kMinSpdyVersion = 2;
52 const int SpdyFramer::kMaxSpdyVersion = 3;
53 const SpdyStreamId SpdyFramer::kInvalidStream = -1;
54 const size_t SpdyFramer::kHeaderDataChunkMaxSize = 1024;
55 const size_t SpdyFramer::kControlFrameBufferSize =
56 sizeof(SpdySynStreamControlFrameBlock);
57 const size_t SpdyFramer::kMaxControlFrameSize = 16 * 1024;
59 #ifdef DEBUG_SPDY_STATE_CHANGES
60 #define CHANGE_STATE(newstate) \
61 do { \
62 LOG(INFO) << "Changing state from: " \
63 << StateToString(state_) \
64 << " to " << StateToString(newstate) << "\n"; \
65 DCHECK(state_ != SPDY_ERROR); \
66 DCHECK_EQ(previous_state_, state_); \
67 previous_state_ = state_; \
68 state_ = newstate; \
69 } while (false)
70 #else
71 #define CHANGE_STATE(newstate) \
72 do { \
73 DCHECK(state_ != SPDY_ERROR); \
74 DCHECK_EQ(previous_state_, state_); \
75 previous_state_ = state_; \
76 state_ = newstate; \
77 } while (false)
78 #endif
80 SettingsFlagsAndId SettingsFlagsAndId::FromWireFormat(int version,
81 uint32 wire) {
82 if (version < 3) {
83 ConvertFlagsAndIdForSpdy2(&wire);
85 return SettingsFlagsAndId(ntohl(wire) >> 24, ntohl(wire) & 0x00ffffff);
88 SettingsFlagsAndId::SettingsFlagsAndId(uint8 flags, uint32 id)
89 : flags_(flags), id_(id & 0x00ffffff) {
90 DCHECK_GT(1u << 24, id) << "SPDY setting ID too large.";
93 uint32 SettingsFlagsAndId::GetWireFormat(int version) const {
94 uint32 wire = htonl(id_ & 0x00ffffff) | htonl(flags_ << 24);
95 if (version < 3) {
96 ConvertFlagsAndIdForSpdy2(&wire);
98 return wire;
101 // SPDY 2 had a bug in it with respect to byte ordering of id/flags field.
102 // This method is used to preserve buggy behavior and works on both
103 // little-endian and big-endian hosts.
104 // This method is also bidirectional (can be used to translate SPDY 2 to SPDY 3
105 // as well as vice versa).
106 void SettingsFlagsAndId::ConvertFlagsAndIdForSpdy2(uint32* val) {
107 uint8* wire_array = reinterpret_cast<uint8*>(val);
108 std::swap(wire_array[0], wire_array[3]);
109 std::swap(wire_array[1], wire_array[2]);
112 SpdyCredential::SpdyCredential() : slot(0) {}
113 SpdyCredential::~SpdyCredential() {}
115 SpdyFramer::SpdyFramer(int version)
116 : state_(SPDY_RESET),
117 previous_state_(SPDY_RESET),
118 error_code_(SPDY_NO_ERROR),
119 remaining_data_(0),
120 remaining_control_payload_(0),
121 remaining_control_header_(0),
122 current_frame_buffer_(new char[kControlFrameBufferSize]),
123 current_frame_len_(0),
124 enable_compression_(true),
125 visitor_(NULL),
126 display_protocol_("SPDY"),
127 spdy_version_(version),
128 syn_frame_processed_(false),
129 probable_http_response_(false) {
130 DCHECK_GE(kMaxSpdyVersion, version);
131 DCHECK_LE(kMinSpdyVersion, version);
134 SpdyFramer::~SpdyFramer() {
135 if (header_compressor_.get()) {
136 deflateEnd(header_compressor_.get());
138 if (header_decompressor_.get()) {
139 inflateEnd(header_decompressor_.get());
143 void SpdyFramer::Reset() {
144 state_ = SPDY_RESET;
145 previous_state_ = SPDY_RESET;
146 error_code_ = SPDY_NO_ERROR;
147 remaining_data_ = 0;
148 remaining_control_payload_ = 0;
149 remaining_control_header_ = 0;
150 current_frame_len_ = 0;
151 settings_scratch_.Reset();
154 const char* SpdyFramer::StateToString(int state) {
155 switch (state) {
156 case SPDY_ERROR:
157 return "ERROR";
158 case SPDY_DONE:
159 return "DONE";
160 case SPDY_AUTO_RESET:
161 return "AUTO_RESET";
162 case SPDY_RESET:
163 return "RESET";
164 case SPDY_READING_COMMON_HEADER:
165 return "READING_COMMON_HEADER";
166 case SPDY_CONTROL_FRAME_PAYLOAD:
167 return "CONTROL_FRAME_PAYLOAD";
168 case SPDY_IGNORE_REMAINING_PAYLOAD:
169 return "IGNORE_REMAINING_PAYLOAD";
170 case SPDY_FORWARD_STREAM_FRAME:
171 return "FORWARD_STREAM_FRAME";
172 case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK:
173 return "SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK";
174 case SPDY_CONTROL_FRAME_HEADER_BLOCK:
175 return "SPDY_CONTROL_FRAME_HEADER_BLOCK";
176 case SPDY_CREDENTIAL_FRAME_PAYLOAD:
177 return "SPDY_CREDENTIAL_FRAME_PAYLOAD";
178 case SPDY_SETTINGS_FRAME_PAYLOAD:
179 return "SPDY_SETTINGS_FRAME_PAYLOAD";
181 return "UNKNOWN_STATE";
184 void SpdyFramer::set_error(SpdyError error) {
185 DCHECK(visitor_);
186 error_code_ = error;
187 CHANGE_STATE(SPDY_ERROR);
188 visitor_->OnError(this);
191 const char* SpdyFramer::ErrorCodeToString(int error_code) {
192 switch (error_code) {
193 case SPDY_NO_ERROR:
194 return "NO_ERROR";
195 case SPDY_INVALID_CONTROL_FRAME:
196 return "INVALID_CONTROL_FRAME";
197 case SPDY_CONTROL_PAYLOAD_TOO_LARGE:
198 return "CONTROL_PAYLOAD_TOO_LARGE";
199 case SPDY_ZLIB_INIT_FAILURE:
200 return "ZLIB_INIT_FAILURE";
201 case SPDY_UNSUPPORTED_VERSION:
202 return "UNSUPPORTED_VERSION";
203 case SPDY_DECOMPRESS_FAILURE:
204 return "DECOMPRESS_FAILURE";
205 case SPDY_COMPRESS_FAILURE:
206 return "COMPRESS_FAILURE";
207 case SPDY_INVALID_DATA_FRAME_FLAGS:
208 return "SPDY_INVALID_DATA_FRAME_FLAGS";
210 return "UNKNOWN_ERROR";
213 const char* SpdyFramer::StatusCodeToString(int status_code) {
214 switch (status_code) {
215 case INVALID:
216 return "INVALID";
217 case PROTOCOL_ERROR:
218 return "PROTOCOL_ERROR";
219 case INVALID_STREAM:
220 return "INVALID_STREAM";
221 case REFUSED_STREAM:
222 return "REFUSED_STREAM";
223 case UNSUPPORTED_VERSION:
224 return "UNSUPPORTED_VERSION";
225 case CANCEL:
226 return "CANCEL";
227 case INTERNAL_ERROR:
228 return "INTERNAL_ERROR";
229 case FLOW_CONTROL_ERROR:
230 return "FLOW_CONTROL_ERROR";
231 case STREAM_IN_USE:
232 return "STREAM_IN_USE";
233 case STREAM_ALREADY_CLOSED:
234 return "STREAM_ALREADY_CLOSED";
235 case INVALID_CREDENTIALS:
236 return "INVALID_CREDENTIALS";
237 case FRAME_TOO_LARGE:
238 return "FRAME_TOO_LARGE";
240 return "UNKNOWN_STATUS";
243 const char* SpdyFramer::ControlTypeToString(SpdyControlType type) {
244 switch (type) {
245 case SYN_STREAM:
246 return "SYN_STREAM";
247 case SYN_REPLY:
248 return "SYN_REPLY";
249 case RST_STREAM:
250 return "RST_STREAM";
251 case SETTINGS:
252 return "SETTINGS";
253 case NOOP:
254 return "NOOP";
255 case PING:
256 return "PING";
257 case GOAWAY:
258 return "GOAWAY";
259 case HEADERS:
260 return "HEADERS";
261 case WINDOW_UPDATE:
262 return "WINDOW_UPDATE";
263 case CREDENTIAL:
264 return "CREDENTIAL";
265 case NUM_CONTROL_FRAME_TYPES:
266 break;
268 return "UNKNOWN_CONTROL_TYPE";
271 size_t SpdyFramer::ProcessInput(const char* data, size_t len) {
272 DCHECK(visitor_);
273 DCHECK(data);
275 size_t original_len = len;
276 do {
277 previous_state_ = state_;
278 switch (state_) {
279 case SPDY_ERROR:
280 case SPDY_DONE:
281 goto bottom;
283 case SPDY_AUTO_RESET:
284 case SPDY_RESET:
285 Reset();
286 if (len > 0) {
287 CHANGE_STATE(SPDY_READING_COMMON_HEADER);
289 break;
291 case SPDY_READING_COMMON_HEADER: {
292 size_t bytes_read = ProcessCommonHeader(data, len);
293 len -= bytes_read;
294 data += bytes_read;
295 break;
298 case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK: {
299 // Control frames that contain header blocks (SYN_STREAM, SYN_REPLY,
300 // HEADERS) take a different path through the state machine - they
301 // will go:
302 // 1. SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK
303 // 2. SPDY_CONTROL_FRAME_HEADER_BLOCK
305 // SETTINGS frames take a slightly modified route:
306 // 1. SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK
307 // 2. SPDY_SETTINGS_FRAME_PAYLOAD
309 // All other control frames will use the alternate route directly to
310 // SPDY_CONTROL_FRAME_PAYLOAD
311 int bytes_read = ProcessControlFrameBeforeHeaderBlock(data, len);
312 len -= bytes_read;
313 data += bytes_read;
314 break;
317 case SPDY_SETTINGS_FRAME_PAYLOAD: {
318 int bytes_read = ProcessSettingsFramePayload(data, len);
319 len -= bytes_read;
320 data += bytes_read;
321 break;
324 case SPDY_CONTROL_FRAME_HEADER_BLOCK: {
325 int bytes_read = ProcessControlFrameHeaderBlock(data, len);
326 len -= bytes_read;
327 data += bytes_read;
328 break;
331 case SPDY_CREDENTIAL_FRAME_PAYLOAD: {
332 size_t bytes_read = ProcessCredentialFramePayload(data, len);
333 len -= bytes_read;
334 data += bytes_read;
335 break;
338 case SPDY_CONTROL_FRAME_PAYLOAD: {
339 size_t bytes_read = ProcessControlFramePayload(data, len);
340 len -= bytes_read;
341 data += bytes_read;
342 break;
345 case SPDY_IGNORE_REMAINING_PAYLOAD:
346 // control frame has too-large payload
347 // intentional fallthrough
348 case SPDY_FORWARD_STREAM_FRAME: {
349 size_t bytes_read = ProcessDataFramePayload(data, len);
350 len -= bytes_read;
351 data += bytes_read;
352 break;
354 default:
355 LOG(DFATAL) << "Invalid value for " << display_protocol_
356 << " framer state: " << state_;
357 // This ensures that we don't infinite-loop if state_ gets an
358 // invalid value somehow, such as due to a SpdyFramer getting deleted
359 // from a callback it calls.
360 goto bottom;
362 } while (state_ != previous_state_);
363 bottom:
364 DCHECK(len == 0 || state_ == SPDY_ERROR);
365 if (current_frame_len_ == 0 &&
366 remaining_data_ == 0 &&
367 remaining_control_payload_ == 0 &&
368 remaining_control_header_ == 0) {
369 DCHECK(state_ == SPDY_RESET || state_ == SPDY_ERROR)
370 << "State: " << StateToString(state_);
373 return original_len - len;
376 size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
377 // This should only be called when we're in the SPDY_READING_COMMON_HEADER
378 // state.
379 DCHECK_EQ(state_, SPDY_READING_COMMON_HEADER);
381 size_t original_len = len;
382 SpdyFrame current_frame(current_frame_buffer_.get(), false);
384 // Update current frame buffer as needed.
385 if (current_frame_len_ < SpdyFrame::kHeaderSize) {
386 size_t bytes_desired = SpdyFrame::kHeaderSize - current_frame_len_;
387 UpdateCurrentFrameBuffer(&data, &len, bytes_desired);
390 if (current_frame_len_ < SpdyFrame::kHeaderSize) {
391 // TODO(rch): remove this empty block
392 // Do nothing.
393 } else {
394 remaining_data_ = current_frame.length();
396 // This is just a sanity check for help debugging early frame errors.
397 if (remaining_data_ > 1000000u) {
398 // The strncmp for 5 is safe because we only hit this point if we
399 // have SpdyFrame::kHeaderSize (8) bytes
400 if (!syn_frame_processed_ &&
401 strncmp(current_frame_buffer_.get(), "HTTP/", 5) == 0) {
402 LOG(WARNING) << "Unexpected HTTP response to spdy request";
403 probable_http_response_ = true;
404 } else {
405 LOG(WARNING) << "Unexpectedly large frame. " << display_protocol_
406 << " session is likely corrupt.";
410 // if we're here, then we have the common header all received.
411 if (!current_frame.is_control_frame()) {
412 SpdyDataFrame data_frame(current_frame_buffer_.get(), false);
413 visitor_->OnDataFrameHeader(&data_frame);
415 if (current_frame.length() > 0) {
416 CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
417 } else {
418 // Empty data frame.
419 if (current_frame.flags() & DATA_FLAG_FIN) {
420 visitor_->OnStreamFrameData(data_frame.stream_id(),
421 NULL, 0, DATA_FLAG_FIN);
423 CHANGE_STATE(SPDY_AUTO_RESET);
425 } else {
426 ProcessControlFrameHeader();
429 return original_len - len;
432 void SpdyFramer::ProcessControlFrameHeader() {
433 DCHECK_EQ(SPDY_NO_ERROR, error_code_);
434 DCHECK_LE(static_cast<size_t>(SpdyFrame::kHeaderSize), current_frame_len_);
435 SpdyControlFrame current_control_frame(current_frame_buffer_.get(), false);
437 // We check version before we check validity: version can never be 'invalid',
438 // it can only be unsupported.
439 if (current_control_frame.version() != spdy_version_) {
440 DLOG(INFO) << "Unsupported SPDY version " << current_control_frame.version()
441 << " (expected " << spdy_version_ << ")";
442 set_error(SPDY_UNSUPPORTED_VERSION);
443 return;
446 // Next up, check to see if we have valid data. This should be after version
447 // checking (otherwise if the the type were out of bounds due to a version
448 // upgrade we would misclassify the error) and before checking the type
449 // (type can definitely be out of bounds)
450 if (!current_control_frame.AppearsToBeAValidControlFrame()) {
451 set_error(SPDY_INVALID_CONTROL_FRAME);
452 return;
455 if (current_control_frame.type() == NOOP) {
456 DLOG(INFO) << "NOOP control frame found. Ignoring.";
457 CHANGE_STATE(SPDY_AUTO_RESET);
458 return;
461 // Do some sanity checking on the control frame sizes.
462 switch (current_control_frame.type()) {
463 case SYN_STREAM:
464 if (current_control_frame.length() <
465 SpdySynStreamControlFrame::size() - SpdyControlFrame::kHeaderSize)
466 set_error(SPDY_INVALID_CONTROL_FRAME);
467 break;
468 case SYN_REPLY:
469 if (current_control_frame.length() <
470 SpdySynReplyControlFrame::size() - SpdyControlFrame::kHeaderSize)
471 set_error(SPDY_INVALID_CONTROL_FRAME);
472 break;
473 case RST_STREAM:
474 if (current_control_frame.length() !=
475 SpdyRstStreamControlFrame::size() - SpdyFrame::kHeaderSize)
476 set_error(SPDY_INVALID_CONTROL_FRAME);
477 break;
478 case SETTINGS:
479 // Make sure that we have an integral number of 8-byte key/value pairs,
480 // plus a 4-byte length field.
481 if (current_control_frame.length() <
482 SpdySettingsControlFrame::size() - SpdyControlFrame::kHeaderSize ||
483 (current_control_frame.length() % 8 != 4)) {
484 DLOG(WARNING) << "Invalid length for SETTINGS frame: "
485 << current_control_frame.length();
486 set_error(SPDY_INVALID_CONTROL_FRAME);
488 break;
489 case GOAWAY:
491 // SPDY 2 GOAWAY frames are 4 bytes smaller than in SPDY 3. We account
492 // for this difference via a separate offset variable, since
493 // SpdyGoAwayControlFrame::size() returns the SPDY 3 size.
494 const size_t goaway_offset = (protocol_version() < 3) ? 4 : 0;
495 if (current_control_frame.length() + goaway_offset !=
496 SpdyGoAwayControlFrame::size() - SpdyFrame::kHeaderSize)
497 set_error(SPDY_INVALID_CONTROL_FRAME);
498 break;
500 case HEADERS:
501 if (current_control_frame.length() <
502 SpdyHeadersControlFrame::size() - SpdyControlFrame::kHeaderSize)
503 set_error(SPDY_INVALID_CONTROL_FRAME);
504 break;
505 case WINDOW_UPDATE:
506 if (current_control_frame.length() !=
507 SpdyWindowUpdateControlFrame::size() -
508 SpdyControlFrame::kHeaderSize)
509 set_error(SPDY_INVALID_CONTROL_FRAME);
510 break;
511 case PING:
512 if (current_control_frame.length() !=
513 SpdyPingControlFrame::size() - SpdyControlFrame::kHeaderSize)
514 set_error(SPDY_INVALID_CONTROL_FRAME);
515 break;
516 case CREDENTIAL:
517 if (current_control_frame.length() <
518 SpdyCredentialControlFrame::size() - SpdyControlFrame::kHeaderSize)
519 set_error(SPDY_INVALID_CONTROL_FRAME);
520 break;
521 default:
522 LOG(WARNING) << "Valid " << display_protocol_
523 << " control frame with unhandled type: "
524 << current_control_frame.type();
525 DLOG(FATAL);
526 set_error(SPDY_INVALID_CONTROL_FRAME);
527 break;
530 if (state_ == SPDY_ERROR) {
531 return;
534 remaining_control_payload_ = current_control_frame.length();
535 const size_t total_frame_size =
536 remaining_control_payload_ + SpdyFrame::kHeaderSize;
537 if (total_frame_size > kMaxControlFrameSize) {
538 DLOG(WARNING) << "Received control frame with way too big of a payload: "
539 << total_frame_size;
540 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
541 return;
544 if (current_control_frame.type() == CREDENTIAL) {
545 CHANGE_STATE(SPDY_CREDENTIAL_FRAME_PAYLOAD);
546 return;
549 // Determine the frame size without variable-length data.
550 int32 frame_size_without_variable_data;
551 switch (current_control_frame.type()) {
552 case SYN_STREAM:
553 syn_frame_processed_ = true;
554 frame_size_without_variable_data = SpdySynStreamControlFrame::size();
555 break;
556 case SYN_REPLY:
557 syn_frame_processed_ = true;
558 frame_size_without_variable_data = SpdySynReplyControlFrame::size();
559 // SPDY 2 had two bytes of unused space preceeding payload.
560 if (spdy_version_ < 3) {
561 frame_size_without_variable_data += 2;
563 break;
564 case HEADERS:
565 frame_size_without_variable_data = SpdyHeadersControlFrame::size();
566 // SPDY 2 had two bytes of unused space preceeding payload.
567 if (spdy_version_ < 3) {
568 frame_size_without_variable_data += 2;
570 break;
571 case SETTINGS:
572 frame_size_without_variable_data = SpdySettingsControlFrame::size();
573 break;
574 default:
575 frame_size_without_variable_data = -1;
576 break;
579 if ((frame_size_without_variable_data == -1) &&
580 (total_frame_size > kControlFrameBufferSize)) {
581 // We should already be in an error state. Double-check.
582 DCHECK_EQ(SPDY_ERROR, state_);
583 if (state_ != SPDY_ERROR) {
584 LOG(DFATAL) << display_protocol_
585 << " control frame buffer too small for fixed-length frame.";
586 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
588 return;
590 if (frame_size_without_variable_data > 0) {
591 // We have a control frame with a header block. We need to parse the
592 // remainder of the control frame's header before we can parse the header
593 // block. The start of the header block varies with the control type.
594 DCHECK_GE(frame_size_without_variable_data,
595 static_cast<int32>(current_frame_len_));
596 remaining_control_header_ = frame_size_without_variable_data -
597 current_frame_len_;
598 remaining_control_payload_ += SpdyFrame::kHeaderSize -
599 frame_size_without_variable_data;
600 CHANGE_STATE(SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK);
601 return;
604 CHANGE_STATE(SPDY_CONTROL_FRAME_PAYLOAD);
607 size_t SpdyFramer::UpdateCurrentFrameBuffer(const char** data, size_t* len,
608 size_t max_bytes) {
609 size_t bytes_to_read = std::min(*len, max_bytes);
610 DCHECK_GE(kControlFrameBufferSize, current_frame_len_ + bytes_to_read);
611 memcpy(current_frame_buffer_.get() + current_frame_len_,
612 *data,
613 bytes_to_read);
614 current_frame_len_ += bytes_to_read;
615 *data += bytes_to_read;
616 *len -= bytes_to_read;
617 return bytes_to_read;
620 size_t SpdyFramer::GetSerializedLength(const int spdy_version,
621 const SpdyHeaderBlock* headers) {
622 const size_t num_name_value_pairs_size
623 = (spdy_version < 3) ? sizeof(uint16) : sizeof(uint32);
624 const size_t length_of_name_size = num_name_value_pairs_size;
625 const size_t length_of_value_size = num_name_value_pairs_size;
627 size_t total_length = num_name_value_pairs_size;
628 for (SpdyHeaderBlock::const_iterator it = headers->begin();
629 it != headers->end();
630 ++it) {
631 // We add space for the length of the name and the length of the value as
632 // well as the length of the name and the length of the value.
633 total_length += length_of_name_size + it->first.size() +
634 length_of_value_size + it->second.size();
636 return total_length;
639 void SpdyFramer::WriteHeaderBlock(SpdyFrameBuilder* frame,
640 const int spdy_version,
641 const SpdyHeaderBlock* headers) {
642 if (spdy_version < 3) {
643 frame->WriteUInt16(headers->size()); // Number of headers.
644 } else {
645 frame->WriteUInt32(headers->size()); // Number of headers.
647 SpdyHeaderBlock::const_iterator it;
648 for (it = headers->begin(); it != headers->end(); ++it) {
649 bool wrote_header;
650 if (spdy_version < 3) {
651 wrote_header = frame->WriteString(it->first);
652 wrote_header &= frame->WriteString(it->second);
653 } else {
654 wrote_header = frame->WriteStringPiece32(it->first);
655 wrote_header &= frame->WriteStringPiece32(it->second);
657 DCHECK(wrote_header);
661 // TODO(phajdan.jr): Clean up after we no longer need
662 // to workaround http://crbug.com/139744.
663 #if !defined(USE_SYSTEM_ZLIB)
665 // These constants are used by zlib to differentiate between normal data and
666 // cookie data. Cookie data is handled specially by zlib when compressing.
667 enum ZDataClass {
668 // kZStandardData is compressed normally, save that it will never match
669 // against any other class of data in the window.
670 kZStandardData = Z_CLASS_STANDARD,
671 // kZCookieData is compressed in its own Huffman blocks and only matches in
672 // its entirety and only against other kZCookieData blocks. Any matches must
673 // be preceeded by a kZStandardData byte, or a semicolon to prevent matching
674 // a suffix. It's assumed that kZCookieData ends in a semicolon to prevent
675 // prefix matches.
676 kZCookieData = Z_CLASS_COOKIE,
677 // kZHuffmanOnlyData is only Huffman compressed - no matches are performed
678 // against the window.
679 kZHuffmanOnlyData = Z_CLASS_HUFFMAN_ONLY,
682 // WriteZ writes |data| to the deflate context |out|. WriteZ will flush as
683 // needed when switching between classes of data.
684 static void WriteZ(const base::StringPiece& data,
685 ZDataClass clas,
686 z_stream* out) {
687 int rv;
689 // If we are switching from standard to non-standard data then we need to end
690 // the current Huffman context to avoid it leaking between them.
691 if (out->clas == kZStandardData &&
692 clas != kZStandardData) {
693 out->avail_in = 0;
694 rv = deflate(out, Z_PARTIAL_FLUSH);
695 DCHECK_EQ(Z_OK, rv);
696 DCHECK_EQ(0u, out->avail_in);
697 DCHECK_LT(0u, out->avail_out);
700 out->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data.data()));
701 out->avail_in = data.size();
702 out->clas = clas;
703 if (clas == kZStandardData) {
704 rv = deflate(out, Z_NO_FLUSH);
705 } else {
706 rv = deflate(out, Z_PARTIAL_FLUSH);
708 DCHECK_EQ(Z_OK, rv);
709 DCHECK_EQ(0u, out->avail_in);
710 DCHECK_LT(0u, out->avail_out);
713 // WriteLengthZ writes |n| as a |length|-byte, big-endian number to |out|.
714 static void WriteLengthZ(size_t n,
715 unsigned length,
716 ZDataClass clas,
717 z_stream* out) {
718 char buf[4];
719 DCHECK_LE(length, sizeof(buf));
720 for (unsigned i = 1; i <= length; i++) {
721 buf[length - i] = n;
722 n >>= 8;
724 WriteZ(base::StringPiece(buf, length), clas, out);
727 // WriteHeaderBlockToZ serialises |headers| to the deflate context |z| in a
728 // manner that resists the length of the compressed data from compromising
729 // cookie data.
730 void SpdyFramer::WriteHeaderBlockToZ(const SpdyHeaderBlock* headers,
731 z_stream* z) const {
732 unsigned length_length = 4;
733 if (spdy_version_ < 3)
734 length_length = 2;
736 WriteLengthZ(headers->size(), length_length, kZStandardData, z);
738 std::map<std::string, std::string>::const_iterator it;
739 for (it = headers->begin(); it != headers->end(); ++it) {
740 WriteLengthZ(it->first.size(), length_length, kZStandardData, z);
741 WriteZ(it->first, kZStandardData, z);
743 if (it->first == "cookie") {
744 // We require the cookie values (save for the last) to end with a
745 // semicolon and (save for the first) to start with a space. This is
746 // typically the format that we are given them in but we reserialize them
747 // to be sure.
749 std::vector<base::StringPiece> cookie_values;
750 size_t cookie_length = 0;
751 base::StringPiece cookie_data(it->second);
753 for (;;) {
754 while (!cookie_data.empty() &&
755 (cookie_data[0] == ' ' || cookie_data[0] == '\t')) {
756 cookie_data.remove_prefix(1);
758 if (cookie_data.empty())
759 break;
761 size_t i;
762 for (i = 0; i < cookie_data.size(); i++) {
763 if (cookie_data[i] == ';')
764 break;
766 if (i < cookie_data.size()) {
767 cookie_values.push_back(cookie_data.substr(0, i));
768 cookie_length += i + 2 /* semicolon and space */;
769 cookie_data.remove_prefix(i + 1);
770 } else {
771 cookie_values.push_back(cookie_data);
772 cookie_length += cookie_data.size();
773 cookie_data.remove_prefix(i);
777 WriteLengthZ(cookie_length, length_length, kZStandardData, z);
778 for (size_t i = 0; i < cookie_values.size(); i++) {
779 std::string cookie;
780 // Since zlib will only back-reference complete cookies, a cookie that
781 // is currently last (and so doesn't have a trailing semicolon) won't
782 // match if it's later in a non-final position. The same is true of
783 // the first cookie.
784 if (i == 0 && cookie_values.size() == 1) {
785 cookie = cookie_values[i].as_string();
786 } else if (i == 0) {
787 cookie = cookie_values[i].as_string() + ";";
788 } else if (i < cookie_values.size() - 1) {
789 cookie = " " + cookie_values[i].as_string() + ";";
790 } else {
791 cookie = " " + cookie_values[i].as_string();
793 WriteZ(cookie, kZCookieData, z);
795 } else if (it->first == "accept" ||
796 it->first == "accept-charset" ||
797 it->first == "accept-encoding" ||
798 it->first == "accept-language" ||
799 it->first == "host" ||
800 it->first == "version" ||
801 it->first == "method" ||
802 it->first == "scheme" ||
803 it->first == ":host" ||
804 it->first == ":version" ||
805 it->first == ":method" ||
806 it->first == ":scheme" ||
807 it->first == "user-agent") {
808 WriteLengthZ(it->second.size(), length_length, kZStandardData, z);
809 WriteZ(it->second, kZStandardData, z);
810 } else {
811 // Non-whitelisted headers are Huffman compressed in their own block, but
812 // don't match against the window.
813 WriteLengthZ(it->second.size(), length_length, kZStandardData, z);
814 WriteZ(it->second, kZHuffmanOnlyData, z);
818 z->avail_in = 0;
819 int rv = deflate(z, Z_SYNC_FLUSH);
820 DCHECK_EQ(Z_OK, rv);
821 z->clas = kZStandardData;
823 #endif // !defined(USE_SYSTEM_ZLIB)
825 size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
826 size_t len) {
827 DCHECK_EQ(SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK, state_);
828 size_t original_len = len;
830 if (remaining_control_header_ > 0) {
831 size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len,
832 remaining_control_header_);
833 remaining_control_header_ -= bytes_read;
836 if (remaining_control_header_ == 0) {
837 SpdyControlFrame control_frame(current_frame_buffer_.get(), false);
838 switch (control_frame.type()) {
839 case SYN_STREAM:
841 SpdySynStreamControlFrame* syn_stream_frame =
842 reinterpret_cast<SpdySynStreamControlFrame*>(&control_frame);
843 // TODO(hkhalil): Check that invalid flag bits are unset?
844 visitor_->OnSynStream(
845 syn_stream_frame->stream_id(),
846 syn_stream_frame->associated_stream_id(),
847 syn_stream_frame->priority(),
848 syn_stream_frame->credential_slot(),
849 (syn_stream_frame->flags() & CONTROL_FLAG_FIN) != 0,
850 (syn_stream_frame->flags() & CONTROL_FLAG_UNIDIRECTIONAL) != 0);
852 CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
853 break;
854 case SYN_REPLY:
856 SpdySynReplyControlFrame* syn_reply_frame =
857 reinterpret_cast<SpdySynReplyControlFrame*>(&control_frame);
858 visitor_->OnSynReply(
859 syn_reply_frame->stream_id(),
860 (syn_reply_frame->flags() & CONTROL_FLAG_FIN) != 0);
862 CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
863 break;
864 case HEADERS:
866 SpdyHeadersControlFrame* headers_frame =
867 reinterpret_cast<SpdyHeadersControlFrame*>(&control_frame);
868 visitor_->OnHeaders(
869 headers_frame->stream_id(),
870 (headers_frame->flags() & CONTROL_FLAG_FIN) != 0);
872 CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
873 break;
874 case SETTINGS:
875 CHANGE_STATE(SPDY_SETTINGS_FRAME_PAYLOAD);
876 break;
877 default:
878 DCHECK(false);
881 return original_len - len;
884 // Does not buffer the control payload. Instead, either passes directly to the
885 // visitor or decompresses and then passes directly to the visitor, via
886 // IncrementallyDeliverControlFrameHeaderData() or
887 // IncrementallyDecompressControlFrameHeaderData() respectively.
888 size_t SpdyFramer::ProcessControlFrameHeaderBlock(const char* data,
889 size_t data_len) {
890 DCHECK_EQ(SPDY_CONTROL_FRAME_HEADER_BLOCK, state_);
891 SpdyControlFrame control_frame(current_frame_buffer_.get(), false);
893 bool processed_successfully = true;
894 DCHECK(control_frame.type() == SYN_STREAM ||
895 control_frame.type() == SYN_REPLY ||
896 control_frame.type() == HEADERS);
897 size_t process_bytes = std::min(data_len, remaining_control_payload_);
898 if (process_bytes > 0) {
899 if (enable_compression_) {
900 processed_successfully = IncrementallyDecompressControlFrameHeaderData(
901 &control_frame, data, process_bytes);
902 } else {
903 processed_successfully = IncrementallyDeliverControlFrameHeaderData(
904 &control_frame, data, process_bytes);
907 remaining_control_payload_ -= process_bytes;
908 remaining_data_ -= process_bytes;
911 // Handle the case that there is no futher data in this frame.
912 if (remaining_control_payload_ == 0 && processed_successfully) {
913 // The complete header block has been delivered. We send a zero-length
914 // OnControlFrameHeaderData() to indicate this.
915 visitor_->OnControlFrameHeaderData(
916 GetControlFrameStreamId(&control_frame), NULL, 0);
918 // If this is a FIN, tell the caller.
919 if (control_frame.flags() & CONTROL_FLAG_FIN) {
920 visitor_->OnStreamFrameData(GetControlFrameStreamId(&control_frame),
921 NULL, 0, DATA_FLAG_FIN);
924 CHANGE_STATE(SPDY_AUTO_RESET);
927 // Handle error.
928 if (!processed_successfully) {
929 return data_len;
932 // Return amount processed.
933 return process_bytes;
936 size_t SpdyFramer::ProcessSettingsFramePayload(const char* data,
937 size_t data_len) {
938 DCHECK_EQ(SPDY_SETTINGS_FRAME_PAYLOAD, state_);
939 SpdyControlFrame control_frame(current_frame_buffer_.get(), false);
940 DCHECK_EQ(SETTINGS, control_frame.type());
941 size_t unprocessed_bytes = std::min(data_len, remaining_control_payload_);
942 size_t processed_bytes = 0;
944 // Loop over our incoming data.
945 while (unprocessed_bytes > 0) {
946 // Process up to one setting at a time.
947 size_t processing = std::min(
948 unprocessed_bytes,
949 static_cast<size_t>(8 - settings_scratch_.setting_buf_len));
951 // Check if we have a complete setting in our input.
952 if (processing == 8) {
953 // Parse the setting directly out of the input without buffering.
954 if (!ProcessSetting(data + processed_bytes)) {
955 set_error(SPDY_INVALID_CONTROL_FRAME);
956 return processed_bytes;
958 } else {
959 // Continue updating settings_scratch_.setting_buf.
960 memcpy(settings_scratch_.setting_buf + settings_scratch_.setting_buf_len,
961 data + processed_bytes,
962 processing);
963 settings_scratch_.setting_buf_len += processing;
965 // Check if we have a complete setting buffered.
966 if (settings_scratch_.setting_buf_len == 8) {
967 if (!ProcessSetting(settings_scratch_.setting_buf)) {
968 set_error(SPDY_INVALID_CONTROL_FRAME);
969 return processed_bytes;
971 // Reset settings_scratch_.setting_buf for our next setting.
972 settings_scratch_.setting_buf_len = 0;
976 // Iterate.
977 unprocessed_bytes -= processing;
978 processed_bytes += processing;
981 // Check if we're done handling this SETTINGS frame.
982 remaining_control_payload_ -= processed_bytes;
983 if (remaining_control_payload_ == 0) {
984 CHANGE_STATE(SPDY_AUTO_RESET);
987 return processed_bytes;
990 bool SpdyFramer::ProcessSetting(const char* data) {
991 // Extract fields.
992 // Maintain behavior of old SPDY 2 bug with byte ordering of flags/id.
993 const uint32 id_and_flags_wire = *(reinterpret_cast<const uint32*>(data));
994 SettingsFlagsAndId id_and_flags =
995 SettingsFlagsAndId::FromWireFormat(spdy_version_, id_and_flags_wire);
996 uint8 flags = id_and_flags.flags();
997 uint32 value = ntohl(*(reinterpret_cast<const uint32*>(data + 4)));
999 // Validate id.
1000 switch (id_and_flags.id()) {
1001 case SETTINGS_UPLOAD_BANDWIDTH:
1002 case SETTINGS_DOWNLOAD_BANDWIDTH:
1003 case SETTINGS_ROUND_TRIP_TIME:
1004 case SETTINGS_MAX_CONCURRENT_STREAMS:
1005 case SETTINGS_CURRENT_CWND:
1006 case SETTINGS_DOWNLOAD_RETRANS_RATE:
1007 case SETTINGS_INITIAL_WINDOW_SIZE:
1008 // Valid values.
1009 break;
1010 default:
1011 DLOG(WARNING) << "Unknown SETTINGS ID: " << id_and_flags.id();
1012 return false;
1014 SpdySettingsIds id = static_cast<SpdySettingsIds>(id_and_flags.id());
1016 // Detect duplciates.
1017 if (static_cast<uint32>(id) <= settings_scratch_.last_setting_id) {
1018 DLOG(WARNING) << "Duplicate entry or invalid ordering for id " << id
1019 << " in " << display_protocol_ << " SETTINGS frame "
1020 << "(last settikng id was "
1021 << settings_scratch_.last_setting_id << ").";
1022 return false;
1024 settings_scratch_.last_setting_id = id;
1026 // Validate flags.
1027 uint8 kFlagsMask = SETTINGS_FLAG_PLEASE_PERSIST | SETTINGS_FLAG_PERSISTED;
1028 if ((flags & ~(kFlagsMask)) != 0) {
1029 DLOG(WARNING) << "Unknown SETTINGS flags provided for id " << id << ": "
1030 << flags;
1031 return false;
1034 // Validation succeeded. Pass on to visitor.
1035 visitor_->OnSetting(id, flags, value);
1036 return true;
1039 size_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) {
1040 size_t original_len = len;
1041 if (remaining_control_payload_) {
1042 size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len,
1043 remaining_control_payload_);
1044 remaining_control_payload_ -= bytes_read;
1045 remaining_data_ -= bytes_read;
1046 if (remaining_control_payload_ == 0) {
1047 SpdyControlFrame control_frame(current_frame_buffer_.get(), false);
1048 DCHECK(!control_frame.has_header_block());
1049 // Use frame-specific handlers.
1050 switch (control_frame.type()) {
1051 case PING: {
1052 SpdyPingControlFrame* ping_frame =
1053 reinterpret_cast<SpdyPingControlFrame*>(&control_frame);
1054 visitor_->OnPing(ping_frame->unique_id());
1056 break;
1057 case WINDOW_UPDATE: {
1058 SpdyWindowUpdateControlFrame *window_update_frame =
1059 reinterpret_cast<SpdyWindowUpdateControlFrame*>(&control_frame);
1060 visitor_->OnWindowUpdate(window_update_frame->stream_id(),
1061 window_update_frame->delta_window_size());
1063 break;
1064 case RST_STREAM: {
1065 SpdyRstStreamControlFrame* rst_stream_frame =
1066 reinterpret_cast<SpdyRstStreamControlFrame*>(&control_frame);
1067 visitor_->OnRstStream(rst_stream_frame->stream_id(),
1068 rst_stream_frame->status());
1070 break;
1071 case GOAWAY: {
1072 SpdyGoAwayControlFrame* go_away_frame =
1073 reinterpret_cast<SpdyGoAwayControlFrame*>(&control_frame);
1074 if (spdy_version_ < 3) {
1075 visitor_->OnGoAway(go_away_frame->last_accepted_stream_id(),
1076 GOAWAY_OK);
1077 } else {
1078 visitor_->OnGoAway(go_away_frame->last_accepted_stream_id(),
1079 go_away_frame->status());
1082 break;
1083 default:
1084 // Unreachable.
1085 LOG(FATAL) << "Unhandled control frame " << control_frame.type();
1088 CHANGE_STATE(SPDY_IGNORE_REMAINING_PAYLOAD);
1091 return original_len - len;
1094 size_t SpdyFramer::ProcessCredentialFramePayload(const char* data, size_t len) {
1095 if (len > 0) {
1096 // Process only up to the end of this CREDENTIAL frame.
1097 len = std::min(len, remaining_control_payload_);
1098 bool processed_succesfully = visitor_->OnCredentialFrameData(data, len);
1099 remaining_control_payload_ -= len;
1100 remaining_data_ -= len;
1101 if (!processed_succesfully) {
1102 set_error(SPDY_CREDENTIAL_FRAME_CORRUPT);
1103 } else if (remaining_control_payload_ == 0) {
1104 visitor_->OnCredentialFrameData(NULL, 0);
1105 CHANGE_STATE(SPDY_AUTO_RESET);
1108 return len;
1111 size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) {
1112 size_t original_len = len;
1114 SpdyDataFrame current_data_frame(current_frame_buffer_.get(), false);
1115 if (remaining_data_ > 0) {
1116 size_t amount_to_forward = std::min(remaining_data_, len);
1117 if (amount_to_forward && state_ != SPDY_IGNORE_REMAINING_PAYLOAD) {
1118 // Only inform the visitor if there is data.
1119 if (amount_to_forward) {
1120 visitor_->OnStreamFrameData(current_data_frame.stream_id(),
1121 data, amount_to_forward, SpdyDataFlags());
1124 data += amount_to_forward;
1125 len -= amount_to_forward;
1126 remaining_data_ -= amount_to_forward;
1128 // If the FIN flag is set, and there is no more data in this data
1129 // frame, inform the visitor of EOF via a 0-length data frame.
1130 if (!remaining_data_ &&
1131 current_data_frame.flags() & DATA_FLAG_FIN) {
1132 visitor_->OnStreamFrameData(current_data_frame.stream_id(),
1133 NULL, 0, DATA_FLAG_FIN);
1137 if (remaining_data_ == 0) {
1138 CHANGE_STATE(SPDY_AUTO_RESET);
1140 return original_len - len;
1143 bool SpdyFramer::ParseHeaderBlockInBuffer(const char* header_data,
1144 size_t header_length,
1145 SpdyHeaderBlock* block) const {
1146 SpdyFrameReader reader(header_data, header_length);
1148 // Read number of headers.
1149 uint32 num_headers;
1150 if (spdy_version_ < 3) {
1151 uint16 temp;
1152 if (!reader.ReadUInt16(&temp)) {
1153 DLOG(INFO) << "Unable to read number of headers.";
1154 return false;
1156 num_headers = temp;
1157 } else {
1158 if (!reader.ReadUInt32(&num_headers)) {
1159 DLOG(INFO) << "Unable to read number of headers.";
1160 return false;
1164 // Read each header.
1165 for (uint32 index = 0; index < num_headers; ++index) {
1166 base::StringPiece temp;
1168 // Read header name.
1169 if ((spdy_version_ < 3) ? !reader.ReadStringPiece16(&temp)
1170 : !reader.ReadStringPiece32(&temp)) {
1171 DLOG(INFO) << "Unable to read header name (" << index + 1 << " of "
1172 << num_headers << ").";
1173 return false;
1175 std::string name = temp.as_string();
1177 // Read header value.
1178 if ((spdy_version_ < 3) ? !reader.ReadStringPiece16(&temp)
1179 : !reader.ReadStringPiece32(&temp)) {
1180 DLOG(INFO) << "Unable to read header value (" << index + 1 << " of "
1181 << num_headers << ").";
1182 return false;
1184 std::string value = temp.as_string();
1186 // Ensure no duplicates.
1187 if (block->find(name) != block->end()) {
1188 DLOG(INFO) << "Duplicate header '" << name << "' (" << index + 1 << " of "
1189 << num_headers << ").";
1190 return false;
1193 // Store header.
1194 (*block)[name] = value;
1196 return true;
1199 // TODO(hkhalil): Remove, or move to test utils kit.
1200 /* static */
1201 bool SpdyFramer::ParseSettings(const SpdySettingsControlFrame* frame,
1202 SettingsMap* settings) {
1203 DCHECK_EQ(frame->type(), SETTINGS);
1204 DCHECK(settings);
1206 SpdyFrameReader parser(frame->header_block(), frame->header_block_len());
1207 for (size_t index = 0; index < frame->num_entries(); ++index) {
1208 uint32 id_and_flags_wire;
1209 uint32 value;
1210 // SettingsFlagsAndId accepts off-the-wire (network byte order) data, so we
1211 // use ReadBytes() instead of ReadUInt32() as the latter calls ntohl().
1212 if (!parser.ReadBytes(&id_and_flags_wire, 4)) {
1213 return false;
1215 if (!parser.ReadUInt32(&value))
1216 return false;
1217 SettingsFlagsAndId flags_and_id =
1218 SettingsFlagsAndId::FromWireFormat(frame->version(), id_and_flags_wire);
1219 SpdySettingsIds id = static_cast<SpdySettingsIds>(flags_and_id.id());
1220 SpdySettingsFlags flags =
1221 static_cast<SpdySettingsFlags>(flags_and_id.flags());
1222 (*settings)[id] = SettingsFlagsAndValue(flags, value);
1224 return true;
1227 /* static */
1228 bool SpdyFramer::ParseCredentialData(const char* data, size_t len,
1229 SpdyCredential* credential) {
1230 DCHECK(credential);
1232 SpdyFrameReader parser(data, len);
1233 base::StringPiece temp;
1234 if (!parser.ReadUInt16(&credential->slot)) {
1235 return false;
1238 if (!parser.ReadStringPiece32(&temp)) {
1239 return false;
1241 credential->proof = temp.as_string();
1243 while (!parser.IsDoneReading()) {
1244 if (!parser.ReadStringPiece32(&temp)) {
1245 return false;
1247 credential->certs.push_back(temp.as_string());
1249 return true;
1252 SpdySynStreamControlFrame* SpdyFramer::CreateSynStream(
1253 SpdyStreamId stream_id,
1254 SpdyStreamId associated_stream_id,
1255 SpdyPriority priority,
1256 uint8 credential_slot,
1257 SpdyControlFlags flags,
1258 bool compressed,
1259 const SpdyHeaderBlock* headers) {
1260 DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
1261 DCHECK_EQ(0u, associated_stream_id & ~kStreamIdMask);
1263 // Find our length.
1264 size_t frame_size = SpdySynStreamControlFrame::size() +
1265 GetSerializedLength(spdy_version_, headers);
1267 SpdyFrameBuilder frame(SYN_STREAM, flags, spdy_version_, frame_size);
1268 frame.WriteUInt32(stream_id);
1269 frame.WriteUInt32(associated_stream_id);
1270 // Cap as appropriate.
1271 if (priority > GetLowestPriority()) {
1272 DLOG(DFATAL) << "Priority out-of-bounds.";
1273 priority = GetLowestPriority();
1275 // Priority is 2 bits for <spdy3, 3 bits otherwise.
1276 frame.WriteUInt8(priority << ((spdy_version_ < 3) ? 6 : 5));
1277 frame.WriteUInt8((spdy_version_ < 3) ? 0 : credential_slot);
1278 WriteHeaderBlock(&frame, spdy_version_, headers);
1279 DCHECK_EQ(frame.length(), frame_size);
1281 scoped_ptr<SpdySynStreamControlFrame> syn_frame(
1282 reinterpret_cast<SpdySynStreamControlFrame*>(frame.take()));
1283 if (compressed) {
1284 return reinterpret_cast<SpdySynStreamControlFrame*>(
1285 CompressControlFrame(*syn_frame.get(), headers));
1287 return syn_frame.release();
1290 SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(
1291 SpdyStreamId stream_id,
1292 SpdyControlFlags flags,
1293 bool compressed,
1294 const SpdyHeaderBlock* headers) {
1295 DCHECK_GT(stream_id, 0u);
1296 DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
1298 // Find our length.
1299 size_t frame_size = SpdySynReplyControlFrame::size() +
1300 GetSerializedLength(spdy_version_, headers);
1301 // In SPDY 2, there were 2 unused bytes before payload.
1302 if (spdy_version_ < 3) {
1303 frame_size += 2;
1306 SpdyFrameBuilder frame(SYN_REPLY, flags, spdy_version_, frame_size);
1307 frame.WriteUInt32(stream_id);
1308 if (spdy_version_ < 3) {
1309 frame.WriteUInt16(0); // Unused
1311 WriteHeaderBlock(&frame, spdy_version_, headers);
1312 DCHECK_EQ(frame.length(), frame_size);
1314 scoped_ptr<SpdySynReplyControlFrame> reply_frame(
1315 reinterpret_cast<SpdySynReplyControlFrame*>(frame.take()));
1316 if (compressed) {
1317 return reinterpret_cast<SpdySynReplyControlFrame*>(
1318 CompressControlFrame(*reply_frame.get(), headers));
1320 return reply_frame.release();
1323 SpdyRstStreamControlFrame* SpdyFramer::CreateRstStream(
1324 SpdyStreamId stream_id,
1325 SpdyStatusCodes status) const {
1326 DCHECK_GT(stream_id, 0u);
1327 DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
1328 DCHECK_NE(status, INVALID);
1329 DCHECK_LT(status, NUM_STATUS_CODES);
1331 size_t frame_size = SpdyRstStreamControlFrame::size();
1332 SpdyFrameBuilder frame(RST_STREAM, CONTROL_FLAG_NONE, spdy_version_,
1333 frame_size);
1334 frame.WriteUInt32(stream_id);
1335 frame.WriteUInt32(status);
1336 DCHECK_EQ(frame.length(), frame_size);
1337 return reinterpret_cast<SpdyRstStreamControlFrame*>(frame.take());
1340 SpdySettingsControlFrame* SpdyFramer::CreateSettings(
1341 const SettingsMap& values) const {
1342 size_t frame_size = SpdySettingsControlFrame::size() + 8 * values.size();
1343 SpdyFrameBuilder frame(SETTINGS, CONTROL_FLAG_NONE, spdy_version_,
1344 frame_size);
1345 frame.WriteUInt32(values.size());
1346 for (SettingsMap::const_iterator it = values.begin();
1347 it != values.end();
1348 it++) {
1349 SettingsFlagsAndId flags_and_id(it->second.first, it->first);
1350 uint32 id_and_flags_wire = flags_and_id.GetWireFormat(spdy_version_);
1351 frame.WriteBytes(&id_and_flags_wire, 4);
1352 frame.WriteUInt32(it->second.second);
1354 DCHECK_EQ(frame.length(), frame_size);
1355 return reinterpret_cast<SpdySettingsControlFrame*>(frame.take());
1358 SpdyPingControlFrame* SpdyFramer::CreatePingFrame(uint32 unique_id) const {
1359 size_t frame_size = SpdyPingControlFrame::size();
1360 SpdyFrameBuilder frame(PING, CONTROL_FLAG_NONE, spdy_version_, frame_size);
1361 frame.WriteUInt32(unique_id);
1362 DCHECK_EQ(frame.length(), frame_size);
1363 return reinterpret_cast<SpdyPingControlFrame*>(frame.take());
1366 SpdyGoAwayControlFrame* SpdyFramer::CreateGoAway(
1367 SpdyStreamId last_accepted_stream_id,
1368 SpdyGoAwayStatus status) const {
1369 DCHECK_EQ(0u, last_accepted_stream_id & ~kStreamIdMask);
1371 // SPDY 2 GOAWAY frames are 4 bytes smaller than in SPDY 3. We account for
1372 // this difference via a separate offset variable, since
1373 // SpdyGoAwayControlFrame::size() returns the SPDY 3 size.
1374 const size_t goaway_offset = (protocol_version() < 3) ? 4 : 0;
1375 size_t frame_size = SpdyGoAwayControlFrame::size() - goaway_offset;
1376 SpdyFrameBuilder frame(GOAWAY, CONTROL_FLAG_NONE, spdy_version_, frame_size);
1377 frame.WriteUInt32(last_accepted_stream_id);
1378 if (protocol_version() >= 3) {
1379 frame.WriteUInt32(status);
1381 DCHECK_EQ(frame.length(), frame_size);
1382 return reinterpret_cast<SpdyGoAwayControlFrame*>(frame.take());
1385 SpdyHeadersControlFrame* SpdyFramer::CreateHeaders(
1386 SpdyStreamId stream_id,
1387 SpdyControlFlags flags,
1388 bool compressed,
1389 const SpdyHeaderBlock* headers) {
1390 // Basically the same as CreateSynReply().
1391 DCHECK_GT(stream_id, 0u);
1392 DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
1394 // Find our length.
1395 size_t frame_size = SpdyHeadersControlFrame::size() +
1396 GetSerializedLength(spdy_version_, headers);
1397 // In SPDY 2, there were 2 unused bytes before payload.
1398 if (spdy_version_ < 3) {
1399 frame_size += 2;
1402 SpdyFrameBuilder frame(HEADERS, flags, spdy_version_, frame_size);
1403 frame.WriteUInt32(stream_id);
1404 if (spdy_version_ < 3) {
1405 frame.WriteUInt16(0); // Unused
1407 WriteHeaderBlock(&frame, spdy_version_, headers);
1408 DCHECK_EQ(frame.length(), frame_size);
1410 scoped_ptr<SpdyHeadersControlFrame> headers_frame(
1411 reinterpret_cast<SpdyHeadersControlFrame*>(frame.take()));
1412 if (compressed) {
1413 return reinterpret_cast<SpdyHeadersControlFrame*>(
1414 CompressControlFrame(*headers_frame.get(), headers));
1416 return headers_frame.release();
1419 SpdyWindowUpdateControlFrame* SpdyFramer::CreateWindowUpdate(
1420 SpdyStreamId stream_id,
1421 uint32 delta_window_size) const {
1422 DCHECK_GT(stream_id, 0u);
1423 DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
1424 DCHECK_GT(delta_window_size, 0u);
1425 DCHECK_LE(delta_window_size,
1426 static_cast<uint32>(kSpdyStreamMaximumWindowSize));
1428 size_t frame_size = SpdyWindowUpdateControlFrame::size();
1429 SpdyFrameBuilder frame(WINDOW_UPDATE, CONTROL_FLAG_NONE, spdy_version_,
1430 frame_size);
1431 frame.WriteUInt32(stream_id);
1432 frame.WriteUInt32(delta_window_size);
1433 DCHECK_EQ(frame.length(), frame_size);
1434 return reinterpret_cast<SpdyWindowUpdateControlFrame*>(frame.take());
1437 SpdyCredentialControlFrame* SpdyFramer::CreateCredentialFrame(
1438 const SpdyCredential& credential) const {
1439 // Calculate the size of the frame by adding the size of the
1440 // variable length data to the size of the fixed length data.
1441 size_t frame_size = SpdyCredentialControlFrame::size() +
1442 credential.proof.length();
1443 DCHECK_EQ(SpdyCredentialControlFrame::size(), 14u);
1444 for (std::vector<std::string>::const_iterator cert = credential.certs.begin();
1445 cert != credential.certs.end();
1446 ++cert) {
1447 frame_size += sizeof(uint32); // size of the cert_length field
1448 frame_size += cert->length(); // size of the cert_data field
1451 SpdyFrameBuilder frame(CREDENTIAL, CONTROL_FLAG_NONE, spdy_version_,
1452 frame_size);
1453 frame.WriteUInt16(credential.slot);
1454 frame.WriteUInt32(credential.proof.size());
1455 frame.WriteBytes(credential.proof.c_str(), credential.proof.size());
1456 for (std::vector<std::string>::const_iterator cert = credential.certs.begin();
1457 cert != credential.certs.end();
1458 ++cert) {
1459 frame.WriteUInt32(cert->length());
1460 frame.WriteBytes(cert->c_str(), cert->length());
1462 DCHECK_EQ(frame.length(), frame_size);
1463 return reinterpret_cast<SpdyCredentialControlFrame*>(frame.take());
1466 SpdyDataFrame* SpdyFramer::CreateDataFrame(
1467 SpdyStreamId stream_id,
1468 const char* data,
1469 uint32 len, SpdyDataFlags flags) const {
1470 DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
1471 size_t frame_size = SpdyDataFrame::size() + len;
1472 SpdyFrameBuilder frame(stream_id, flags, frame_size);
1473 frame.WriteBytes(data, len);
1474 DCHECK_EQ(frame.length(), frame_size);
1475 return reinterpret_cast<SpdyDataFrame*>(frame.take());
1478 // The following compression setting are based on Brian Olson's analysis. See
1479 // https://groups.google.com/group/spdy-dev/browse_thread/thread/dfaf498542fac792
1480 // for more details.
1481 #if defined(USE_SYSTEM_ZLIB)
1482 // System zlib is not expected to have workaround for http://crbug.com/139744,
1483 // so disable compression in that case.
1484 // TODO(phajdan.jr): Remove the special case when it's no longer necessary.
1485 static const int kCompressorLevel = 0;
1486 #else // !defined(USE_SYSTEM_ZLIB)
1487 static const int kCompressorLevel = 9;
1488 #endif // !defined(USE_SYSTEM_ZLIB)
1489 static const int kCompressorWindowSizeInBits = 11;
1490 static const int kCompressorMemLevel = 1;
1492 z_stream* SpdyFramer::GetHeaderCompressor() {
1493 if (header_compressor_.get())
1494 return header_compressor_.get(); // Already initialized.
1496 header_compressor_.reset(new z_stream);
1497 memset(header_compressor_.get(), 0, sizeof(z_stream));
1499 int success = deflateInit2(header_compressor_.get(),
1500 kCompressorLevel,
1501 Z_DEFLATED,
1502 kCompressorWindowSizeInBits,
1503 kCompressorMemLevel,
1504 Z_DEFAULT_STRATEGY);
1505 if (success == Z_OK) {
1506 const char* dictionary = (spdy_version_ < 3) ? kV2Dictionary
1507 : kV3Dictionary;
1508 const int dictionary_size = (spdy_version_ < 3) ? kV2DictionarySize
1509 : kV3DictionarySize;
1510 success = deflateSetDictionary(header_compressor_.get(),
1511 reinterpret_cast<const Bytef*>(dictionary),
1512 dictionary_size);
1514 if (success != Z_OK) {
1515 LOG(WARNING) << "deflateSetDictionary failure: " << success;
1516 header_compressor_.reset(NULL);
1517 return NULL;
1519 return header_compressor_.get();
1522 z_stream* SpdyFramer::GetHeaderDecompressor() {
1523 if (header_decompressor_.get())
1524 return header_decompressor_.get(); // Already initialized.
1526 header_decompressor_.reset(new z_stream);
1527 memset(header_decompressor_.get(), 0, sizeof(z_stream));
1529 int success = inflateInit(header_decompressor_.get());
1530 if (success != Z_OK) {
1531 LOG(WARNING) << "inflateInit failure: " << success;
1532 header_decompressor_.reset(NULL);
1533 return NULL;
1535 return header_decompressor_.get();
1538 bool SpdyFramer::GetFrameBoundaries(const SpdyFrame& frame,
1539 int* payload_length,
1540 int* header_length,
1541 const char** payload) const {
1542 size_t frame_size;
1543 if (frame.is_control_frame()) {
1544 const SpdyControlFrame& control_frame =
1545 reinterpret_cast<const SpdyControlFrame&>(frame);
1546 switch (control_frame.type()) {
1547 case SYN_STREAM:
1549 const SpdySynStreamControlFrame& syn_frame =
1550 reinterpret_cast<const SpdySynStreamControlFrame&>(frame);
1551 frame_size = SpdySynStreamControlFrame::size();
1552 *payload_length = syn_frame.header_block_len();
1553 *header_length = frame_size;
1554 *payload = frame.data() + *header_length;
1556 break;
1557 case SYN_REPLY:
1559 const SpdySynReplyControlFrame& syn_frame =
1560 reinterpret_cast<const SpdySynReplyControlFrame&>(frame);
1561 frame_size = SpdySynReplyControlFrame::size();
1562 *payload_length = syn_frame.header_block_len();
1563 *header_length = frame_size;
1564 *payload = frame.data() + *header_length;
1565 // SPDY 2 had two bytes of unused space preceeding payload.
1566 if (spdy_version_ < 3) {
1567 *header_length += 2;
1568 *payload += 2;
1571 break;
1572 case HEADERS:
1574 const SpdyHeadersControlFrame& headers_frame =
1575 reinterpret_cast<const SpdyHeadersControlFrame&>(frame);
1576 frame_size = SpdyHeadersControlFrame::size();
1577 *payload_length = headers_frame.header_block_len();
1578 *header_length = frame_size;
1579 *payload = frame.data() + *header_length;
1580 // SPDY 2 had two bytes of unused space preceeding payload.
1581 if (spdy_version_ < 3) {
1582 *header_length += 2;
1583 *payload += 2;
1586 break;
1587 default:
1588 // TODO(mbelshe): set an error?
1589 return false; // We can't compress this frame!
1591 } else {
1592 frame_size = SpdyFrame::kHeaderSize;
1593 *header_length = frame_size;
1594 *payload_length = frame.length();
1595 *payload = frame.data() + SpdyFrame::kHeaderSize;
1597 return true;
1600 SpdyControlFrame* SpdyFramer::CompressControlFrame(
1601 const SpdyControlFrame& frame,
1602 const SpdyHeaderBlock* headers) {
1603 z_stream* compressor = GetHeaderCompressor();
1604 if (!compressor)
1605 return NULL;
1607 int payload_length;
1608 int header_length;
1609 const char* payload;
1611 base::StatsCounter compressed_frames("spdy.CompressedFrames");
1612 base::StatsCounter pre_compress_bytes("spdy.PreCompressSize");
1613 base::StatsCounter post_compress_bytes("spdy.PostCompressSize");
1615 if (!enable_compression_)
1616 return reinterpret_cast<SpdyControlFrame*>(DuplicateFrame(frame));
1618 if (!GetFrameBoundaries(frame, &payload_length, &header_length, &payload))
1619 return NULL;
1621 // Create an output frame.
1622 int compressed_max_size = deflateBound(compressor, payload_length);
1623 // Since we'll be performing lots of flushes when compressing the data,
1624 // zlib's lower bounds may be insufficient.
1625 compressed_max_size *= 2;
1627 size_t new_frame_size = header_length + compressed_max_size;
1628 if ((frame.type() == SYN_REPLY || frame.type() == HEADERS) &&
1629 spdy_version_ < 3) {
1630 new_frame_size += 2;
1632 DCHECK_GE(new_frame_size, frame.length() + SpdyFrame::kHeaderSize);
1633 scoped_ptr<SpdyControlFrame> new_frame(new SpdyControlFrame(new_frame_size));
1634 memcpy(new_frame->data(), frame.data(),
1635 frame.length() + SpdyFrame::kHeaderSize);
1637 // TODO(phajdan.jr): Clean up after we no longer need
1638 // to workaround http://crbug.com/139744.
1639 #if defined(USE_SYSTEM_ZLIB)
1640 compressor->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload));
1641 compressor->avail_in = payload_length;
1642 #endif // defined(USE_SYSTEM_ZLIB)
1643 compressor->next_out = reinterpret_cast<Bytef*>(new_frame->data()) +
1644 header_length;
1645 compressor->avail_out = compressed_max_size;
1646 // TODO(phajdan.jr): Clean up after we no longer need
1647 // to workaround http://crbug.com/139744.
1648 #if defined(USE_SYSTEM_ZLIB)
1649 int rv = deflate(compressor, Z_SYNC_FLUSH);
1650 if (rv != Z_OK) { // How can we know that it compressed everything?
1651 // This shouldn't happen, right?
1652 LOG(WARNING) << "deflate failure: " << rv;
1653 return NULL;
1655 #else // !defined(USE_SYSTEM_ZLIB)
1656 WriteHeaderBlockToZ(headers, compressor);
1657 #endif // !defined(USE_SYSTEM_ZLIB)
1658 int compressed_size = compressed_max_size - compressor->avail_out;
1660 // We trust zlib. Also, we can't do anything about it.
1661 // See http://www.zlib.net/zlib_faq.html#faq36
1662 (void)VALGRIND_MAKE_MEM_DEFINED(new_frame->data() + header_length,
1663 compressed_size);
1665 new_frame->set_length(
1666 header_length + compressed_size - SpdyFrame::kHeaderSize);
1668 pre_compress_bytes.Add(payload_length);
1669 post_compress_bytes.Add(new_frame->length());
1671 compressed_frames.Increment();
1673 if (visitor_)
1674 visitor_->OnControlFrameCompressed(frame, *new_frame);
1676 return new_frame.release();
1679 // Incrementally decompress the control frame's header block, feeding the
1680 // result to the visitor in chunks. Continue this until the visitor
1681 // indicates that it cannot process any more data, or (more commonly) we
1682 // run out of data to deliver.
1683 bool SpdyFramer::IncrementallyDecompressControlFrameHeaderData(
1684 const SpdyControlFrame* control_frame,
1685 const char* data,
1686 size_t len) {
1687 // Get a decompressor or set error.
1688 z_stream* decomp = GetHeaderDecompressor();
1689 if (decomp == NULL) {
1690 LOG(DFATAL) << "Couldn't get decompressor for handling compressed headers.";
1691 set_error(SPDY_DECOMPRESS_FAILURE);
1692 return false;
1695 bool processed_successfully = true;
1696 char buffer[kHeaderDataChunkMaxSize];
1698 decomp->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data));
1699 decomp->avail_in = len;
1700 const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame);
1701 DCHECK_LT(0u, stream_id);
1702 while (decomp->avail_in > 0 && processed_successfully) {
1703 decomp->next_out = reinterpret_cast<Bytef*>(buffer);
1704 decomp->avail_out = arraysize(buffer);
1706 int rv = inflate(decomp, Z_SYNC_FLUSH);
1707 if (rv == Z_NEED_DICT) {
1708 const char* dictionary = (spdy_version_ < 3) ? kV2Dictionary
1709 : kV3Dictionary;
1710 const int dictionary_size = (spdy_version_ < 3) ? kV2DictionarySize
1711 : kV3DictionarySize;
1712 const DictionaryIds& ids = g_dictionary_ids.Get();
1713 const uLong dictionary_id = (spdy_version_ < 3) ? ids.v2_dictionary_id
1714 : ids.v3_dictionary_id;
1715 // Need to try again with the right dictionary.
1716 if (decomp->adler == dictionary_id) {
1717 rv = inflateSetDictionary(decomp,
1718 reinterpret_cast<const Bytef*>(dictionary),
1719 dictionary_size);
1720 if (rv == Z_OK)
1721 rv = inflate(decomp, Z_SYNC_FLUSH);
1725 // Inflate will generate a Z_BUF_ERROR if it runs out of input
1726 // without producing any output. The input is consumed and
1727 // buffered internally by zlib so we can detect this condition by
1728 // checking if avail_in is 0 after the call to inflate.
1729 bool input_exhausted = ((rv == Z_BUF_ERROR) && (decomp->avail_in == 0));
1730 if ((rv == Z_OK) || input_exhausted) {
1731 size_t decompressed_len = arraysize(buffer) - decomp->avail_out;
1732 if (decompressed_len > 0) {
1733 processed_successfully = visitor_->OnControlFrameHeaderData(
1734 stream_id, buffer, decompressed_len);
1736 if (!processed_successfully) {
1737 // Assume that the problem was the header block was too large for the
1738 // visitor.
1739 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
1741 } else {
1742 DLOG(WARNING) << "inflate failure: " << rv << " " << len;
1743 set_error(SPDY_DECOMPRESS_FAILURE);
1744 processed_successfully = false;
1747 return processed_successfully;
1750 bool SpdyFramer::IncrementallyDeliverControlFrameHeaderData(
1751 const SpdyControlFrame* control_frame, const char* data, size_t len) {
1752 bool read_successfully = true;
1753 const SpdyStreamId stream_id = GetControlFrameStreamId(control_frame);
1754 while (read_successfully && len > 0) {
1755 size_t bytes_to_deliver = std::min(len, kHeaderDataChunkMaxSize);
1756 read_successfully = visitor_->OnControlFrameHeaderData(stream_id, data,
1757 bytes_to_deliver);
1758 data += bytes_to_deliver;
1759 len -= bytes_to_deliver;
1760 if (!read_successfully) {
1761 // Assume that the problem was the header block was too large for the
1762 // visitor.
1763 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE);
1766 return read_successfully;
1769 SpdyFrame* SpdyFramer::DuplicateFrame(const SpdyFrame& frame) {
1770 int size = SpdyFrame::kHeaderSize + frame.length();
1771 SpdyFrame* new_frame = new SpdyFrame(size);
1772 memcpy(new_frame->data(), frame.data(), size);
1773 return new_frame;
1776 bool SpdyFramer::IsCompressible(const SpdyFrame& frame) const {
1777 // The important frames to compress are those which contain large
1778 // amounts of compressible data - namely the headers in the SYN_STREAM
1779 // and SYN_REPLY.
1780 if (frame.is_control_frame()) {
1781 const SpdyControlFrame& control_frame =
1782 reinterpret_cast<const SpdyControlFrame&>(frame);
1783 return control_frame.type() == SYN_STREAM ||
1784 control_frame.type() == SYN_REPLY ||
1785 control_frame.type() == HEADERS;
1788 // We don't compress Data frames.
1789 return false;
1792 size_t SpdyFramer::GetMinimumControlFrameSize(int version,
1793 SpdyControlType type) {
1794 switch (type) {
1795 case SYN_STREAM:
1796 return SpdySynStreamControlFrame::size();
1797 case SYN_REPLY:
1798 return SpdySynReplyControlFrame::size();
1799 case RST_STREAM:
1800 return SpdyRstStreamControlFrame::size();
1801 case SETTINGS:
1802 return SpdySettingsControlFrame::size();
1803 case NOOP:
1804 // Even though NOOP is no longer supported, we still correctly report its
1805 // size so that it can be handled correctly as incoming data if
1806 // implementations so desire.
1807 return SpdyFrame::kHeaderSize;
1808 case PING:
1809 return SpdyPingControlFrame::size();
1810 case GOAWAY:
1811 if (version < 3) {
1812 // SPDY 2 GOAWAY is smaller by 32 bits. Since
1813 // SpdyGoAwayControlFrame::size() returns the size for SPDY 3, we adjust
1814 // before returning here.
1815 return SpdyGoAwayControlFrame::size() - 4;
1816 } else {
1817 return SpdyGoAwayControlFrame::size();
1819 case HEADERS:
1820 return SpdyHeadersControlFrame::size();
1821 case WINDOW_UPDATE:
1822 return SpdyWindowUpdateControlFrame::size();
1823 case CREDENTIAL:
1824 return SpdyCredentialControlFrame::size();
1825 case NUM_CONTROL_FRAME_TYPES:
1826 break;
1828 LOG(ERROR) << "Unknown control frame type " << type;
1829 return std::numeric_limits<size_t>::max();
1832 /* static */
1833 SpdyStreamId SpdyFramer::GetControlFrameStreamId(
1834 const SpdyControlFrame* control_frame) {
1835 SpdyStreamId stream_id = kInvalidStream;
1836 if (control_frame != NULL) {
1837 switch (control_frame->type()) {
1838 case SYN_STREAM:
1839 stream_id = reinterpret_cast<const SpdySynStreamControlFrame*>(
1840 control_frame)->stream_id();
1841 break;
1842 case SYN_REPLY:
1843 stream_id = reinterpret_cast<const SpdySynReplyControlFrame*>(
1844 control_frame)->stream_id();
1845 break;
1846 case HEADERS:
1847 stream_id = reinterpret_cast<const SpdyHeadersControlFrame*>(
1848 control_frame)->stream_id();
1849 break;
1850 case RST_STREAM:
1851 stream_id = reinterpret_cast<const SpdyRstStreamControlFrame*>(
1852 control_frame)->stream_id();
1853 break;
1854 case WINDOW_UPDATE:
1855 stream_id = reinterpret_cast<const SpdyWindowUpdateControlFrame*>(
1856 control_frame)->stream_id();
1857 break;
1858 // All of the following types are not part of a particular stream.
1859 // They all fall through to the invalid control frame type case.
1860 // (The default case isn't used so that the compile will break if a new
1861 // control frame type is added but not included here.)
1862 case SETTINGS:
1863 case NOOP:
1864 case PING:
1865 case GOAWAY:
1866 case CREDENTIAL:
1867 case NUM_CONTROL_FRAME_TYPES: // makes compiler happy
1868 break;
1871 return stream_id;
1874 void SpdyFramer::set_enable_compression(bool value) {
1875 enable_compression_ = value;
1878 } // namespace net