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 #include "net/spdy/spdy_protocol.h"
9 SpdyFrameWithNameValueBlockIR::SpdyFrameWithNameValueBlockIR(
10 SpdyStreamId stream_id) : SpdyFrameWithFinIR(stream_id) {}
12 SpdyFrameWithNameValueBlockIR::~SpdyFrameWithNameValueBlockIR() {}
14 SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, const base::StringPiece& data)
15 : SpdyFrameWithFinIR(stream_id),
17 padding_payload_len_(0) {
21 SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id)
22 : SpdyFrameWithFinIR(stream_id),
24 padding_payload_len_(0) {}
26 SpdyDataIR::~SpdyDataIR() {}
28 bool SpdyConstants::IsValidFrameType(SpdyMajorVersion version,
29 int frame_type_field) {
33 // SYN_STREAM is the first valid frame.
34 if (frame_type_field < SerializeFrameType(version, SYN_STREAM)) {
38 // WINDOW_UPDATE is the last valid frame.
39 if (frame_type_field > SerializeFrameType(version, WINDOW_UPDATE)) {
46 // Check for recognized extensions.
47 if (frame_type_field == SerializeFrameType(version, ALTSVC) ||
48 frame_type_field == SerializeFrameType(version, BLOCKED)) {
52 // DATA is the first valid frame.
53 if (frame_type_field < SerializeFrameType(version, DATA)) {
57 // CONTINUATION is the last valid frame.
58 if (frame_type_field > SerializeFrameType(version, CONTINUATION)) {
65 LOG(DFATAL) << "Unhandled SPDY version " << version;
69 SpdyFrameType SpdyConstants::ParseFrameType(SpdyMajorVersion version,
70 int frame_type_field) {
74 switch (frame_type_field) {
95 switch (frame_type_field) {
113 return WINDOW_UPDATE;
124 LOG(DFATAL) << "Unhandled frame type " << frame_type_field;
128 int SpdyConstants::SerializeFrameType(SpdyMajorVersion version,
129 SpdyFrameType frame_type) {
133 switch (frame_type) {
151 LOG(DFATAL) << "Serializing unhandled frame type " << frame_type;
156 switch (frame_type) {
177 // ALTSVC and BLOCKED are extensions.
183 LOG(DFATAL) << "Serializing unhandled frame type " << frame_type;
188 LOG(DFATAL) << "Unhandled SPDY version " << version;
192 int SpdyConstants::DataFrameType(SpdyMajorVersion version) {
199 return SerializeFrameType(version, DATA);
202 LOG(DFATAL) << "Unhandled SPDY version " << version;
206 bool SpdyConstants::IsValidSettingId(SpdyMajorVersion version,
207 int setting_id_field) {
211 // UPLOAD_BANDWIDTH is the first valid setting id.
212 if (setting_id_field <
213 SerializeSettingId(version, SETTINGS_UPLOAD_BANDWIDTH)) {
217 // INITIAL_WINDOW_SIZE is the last valid setting id.
218 if (setting_id_field >
219 SerializeSettingId(version, SETTINGS_INITIAL_WINDOW_SIZE)) {
226 // HEADER_TABLE_SIZE is the first valid setting id.
227 if (setting_id_field <
228 SerializeSettingId(version, SETTINGS_HEADER_TABLE_SIZE)) {
232 // MAX_HEADER_LIST_SIZE is the last valid setting id.
233 if (setting_id_field >
234 SerializeSettingId(version, SETTINGS_MAX_HEADER_LIST_SIZE)) {
241 LOG(DFATAL) << "Unhandled SPDY version " << version;
245 SpdySettingsIds SpdyConstants::ParseSettingId(SpdyMajorVersion version,
246 int setting_id_field) {
250 switch (setting_id_field) {
252 return SETTINGS_UPLOAD_BANDWIDTH;
254 return SETTINGS_DOWNLOAD_BANDWIDTH;
256 return SETTINGS_ROUND_TRIP_TIME;
258 return SETTINGS_MAX_CONCURRENT_STREAMS;
260 return SETTINGS_CURRENT_CWND;
262 return SETTINGS_DOWNLOAD_RETRANS_RATE;
264 return SETTINGS_INITIAL_WINDOW_SIZE;
269 switch (setting_id_field) {
271 return SETTINGS_HEADER_TABLE_SIZE;
273 return SETTINGS_ENABLE_PUSH;
275 return SETTINGS_MAX_CONCURRENT_STREAMS;
277 return SETTINGS_INITIAL_WINDOW_SIZE;
279 return SETTINGS_MAX_FRAME_SIZE;
281 return SETTINGS_MAX_HEADER_LIST_SIZE;
286 LOG(DFATAL) << "Unhandled setting ID " << setting_id_field;
287 return SETTINGS_UPLOAD_BANDWIDTH;
290 int SpdyConstants::SerializeSettingId(SpdyMajorVersion version,
291 SpdySettingsIds id) {
296 case SETTINGS_UPLOAD_BANDWIDTH:
298 case SETTINGS_DOWNLOAD_BANDWIDTH:
300 case SETTINGS_ROUND_TRIP_TIME:
302 case SETTINGS_MAX_CONCURRENT_STREAMS:
304 case SETTINGS_CURRENT_CWND:
306 case SETTINGS_DOWNLOAD_RETRANS_RATE:
308 case SETTINGS_INITIAL_WINDOW_SIZE:
311 LOG(DFATAL) << "Serializing unhandled setting id " << id;
317 case SETTINGS_HEADER_TABLE_SIZE:
319 case SETTINGS_ENABLE_PUSH:
321 case SETTINGS_MAX_CONCURRENT_STREAMS:
323 case SETTINGS_INITIAL_WINDOW_SIZE:
325 case SETTINGS_MAX_FRAME_SIZE:
327 case SETTINGS_MAX_HEADER_LIST_SIZE:
330 LOG(DFATAL) << "Serializing unhandled setting id " << id;
334 LOG(DFATAL) << "Unhandled SPDY version " << version;
338 bool SpdyConstants::IsValidRstStreamStatus(SpdyMajorVersion version,
339 int rst_stream_status_field) {
343 // PROTOCOL_ERROR is the valid first status code.
344 if (rst_stream_status_field <
345 SerializeRstStreamStatus(version, RST_STREAM_PROTOCOL_ERROR)) {
349 // FRAME_TOO_LARGE is the valid last status code.
350 if (rst_stream_status_field >
351 SerializeRstStreamStatus(version, RST_STREAM_FRAME_TOO_LARGE)) {
358 // NO_ERROR is the first valid status code.
359 if (rst_stream_status_field <
360 SerializeRstStreamStatus(version, RST_STREAM_PROTOCOL_ERROR)) {
364 // TODO(hkhalil): Omit COMPRESSION_ERROR and SETTINGS_TIMEOUT
366 // This works because GOAWAY and RST_STREAM share a namespace.
367 if (rst_stream_status_field ==
368 SerializeGoAwayStatus(version, GOAWAY_COMPRESSION_ERROR) ||
369 rst_stream_status_field ==
370 SerializeGoAwayStatus(version, GOAWAY_SETTINGS_TIMEOUT)) {
375 // ENHANCE_YOUR_CALM is the last valid status code.
376 if (rst_stream_status_field >
377 SerializeRstStreamStatus(version, RST_STREAM_ENHANCE_YOUR_CALM)) {
383 LOG(DFATAL) << "Unhandled SPDY version " << version;
387 SpdyRstStreamStatus SpdyConstants::ParseRstStreamStatus(
388 SpdyMajorVersion version,
389 int rst_stream_status_field) {
393 switch (rst_stream_status_field) {
395 return RST_STREAM_PROTOCOL_ERROR;
397 return RST_STREAM_INVALID_STREAM;
399 return RST_STREAM_REFUSED_STREAM;
401 return RST_STREAM_UNSUPPORTED_VERSION;
403 return RST_STREAM_CANCEL;
405 return RST_STREAM_INTERNAL_ERROR;
407 return RST_STREAM_FLOW_CONTROL_ERROR;
409 return RST_STREAM_STREAM_IN_USE;
411 return RST_STREAM_STREAM_ALREADY_CLOSED;
413 return RST_STREAM_INVALID_CREDENTIALS;
415 return RST_STREAM_FRAME_TOO_LARGE;
420 switch (rst_stream_status_field) {
422 return RST_STREAM_PROTOCOL_ERROR;
424 return RST_STREAM_INTERNAL_ERROR;
426 return RST_STREAM_FLOW_CONTROL_ERROR;
428 return RST_STREAM_STREAM_CLOSED;
430 return RST_STREAM_FRAME_SIZE_ERROR;
432 return RST_STREAM_REFUSED_STREAM;
434 return RST_STREAM_CANCEL;
436 return RST_STREAM_CONNECT_ERROR;
438 return RST_STREAM_ENHANCE_YOUR_CALM;
443 LOG(DFATAL) << "Invalid RST_STREAM status " << rst_stream_status_field;
444 return RST_STREAM_PROTOCOL_ERROR;
447 int SpdyConstants::SerializeRstStreamStatus(
448 SpdyMajorVersion version,
449 SpdyRstStreamStatus rst_stream_status) {
453 switch (rst_stream_status) {
454 case RST_STREAM_PROTOCOL_ERROR:
456 case RST_STREAM_INVALID_STREAM:
458 case RST_STREAM_REFUSED_STREAM:
460 case RST_STREAM_UNSUPPORTED_VERSION:
462 case RST_STREAM_CANCEL:
464 case RST_STREAM_INTERNAL_ERROR:
466 case RST_STREAM_FLOW_CONTROL_ERROR:
468 case RST_STREAM_STREAM_IN_USE:
470 case RST_STREAM_STREAM_ALREADY_CLOSED:
472 case RST_STREAM_INVALID_CREDENTIALS:
474 case RST_STREAM_FRAME_TOO_LARGE:
477 LOG(DFATAL) << "Unhandled RST_STREAM status "
478 << rst_stream_status;
483 switch (rst_stream_status) {
484 case RST_STREAM_PROTOCOL_ERROR:
486 case RST_STREAM_INTERNAL_ERROR:
488 case RST_STREAM_FLOW_CONTROL_ERROR:
490 case RST_STREAM_STREAM_CLOSED:
492 case RST_STREAM_FRAME_SIZE_ERROR:
494 case RST_STREAM_REFUSED_STREAM:
496 case RST_STREAM_CANCEL:
498 case RST_STREAM_CONNECT_ERROR:
500 case RST_STREAM_ENHANCE_YOUR_CALM:
503 LOG(DFATAL) << "Unhandled RST_STREAM status "
504 << rst_stream_status;
508 LOG(DFATAL) << "Unhandled SPDY version " << version;
512 bool SpdyConstants::IsValidGoAwayStatus(SpdyMajorVersion version,
513 int goaway_status_field) {
517 // GOAWAY_OK is the first valid status.
518 if (goaway_status_field < SerializeGoAwayStatus(version, GOAWAY_OK)) {
522 // GOAWAY_INTERNAL_ERROR is the last valid status.
523 if (goaway_status_field > SerializeGoAwayStatus(version,
524 GOAWAY_INTERNAL_ERROR)) {
531 // GOAWAY_NO_ERROR is the first valid status.
532 if (goaway_status_field < SerializeGoAwayStatus(version,
537 // GOAWAY_INADEQUATE_SECURITY is the last valid status.
538 if (goaway_status_field >
539 SerializeGoAwayStatus(version, GOAWAY_INADEQUATE_SECURITY)) {
545 LOG(DFATAL) << "Unknown SpdyMajorVersion " << version;
549 SpdyGoAwayStatus SpdyConstants::ParseGoAwayStatus(SpdyMajorVersion version,
550 int goaway_status_field) {
554 switch (goaway_status_field) {
558 return GOAWAY_PROTOCOL_ERROR;
560 return GOAWAY_INTERNAL_ERROR;
565 switch (goaway_status_field) {
567 return GOAWAY_NO_ERROR;
569 return GOAWAY_PROTOCOL_ERROR;
571 return GOAWAY_INTERNAL_ERROR;
573 return GOAWAY_FLOW_CONTROL_ERROR;
575 return GOAWAY_SETTINGS_TIMEOUT;
577 return GOAWAY_STREAM_CLOSED;
579 return GOAWAY_FRAME_SIZE_ERROR;
581 return GOAWAY_REFUSED_STREAM;
583 return GOAWAY_CANCEL;
585 return GOAWAY_COMPRESSION_ERROR;
587 return GOAWAY_CONNECT_ERROR;
589 return GOAWAY_ENHANCE_YOUR_CALM;
591 return GOAWAY_INADEQUATE_SECURITY;
596 LOG(DFATAL) << "Unhandled GOAWAY status " << goaway_status_field;
597 return GOAWAY_PROTOCOL_ERROR;
600 SpdyMajorVersion SpdyConstants::ParseMajorVersion(int version_number) {
601 switch (version_number) {
611 LOG(DFATAL) << "Unsupported SPDY version number: " << version_number;
616 int SpdyConstants::SerializeMajorVersion(SpdyMajorVersion version) {
627 LOG(DFATAL) << "Unsupported SPDY major version: " << version;
632 std::string SpdyConstants::GetVersionString(SpdyMajorVersion version) {
643 LOG(DFATAL) << "Unsupported SPDY major version: " << version;
648 int SpdyConstants::SerializeGoAwayStatus(SpdyMajorVersion version,
649 SpdyGoAwayStatus status) {
653 // TODO(jgraettinger): Merge this back to server-side.
655 case GOAWAY_NO_ERROR:
657 case GOAWAY_PROTOCOL_ERROR:
658 case GOAWAY_INTERNAL_ERROR:
659 case GOAWAY_FLOW_CONTROL_ERROR:
660 case GOAWAY_SETTINGS_TIMEOUT:
661 case GOAWAY_STREAM_CLOSED:
662 case GOAWAY_FRAME_SIZE_ERROR:
663 case GOAWAY_REFUSED_STREAM:
665 case GOAWAY_COMPRESSION_ERROR:
666 case GOAWAY_CONNECT_ERROR:
667 case GOAWAY_ENHANCE_YOUR_CALM:
668 case GOAWAY_INADEQUATE_SECURITY:
669 return 1; // PROTOCOL_ERROR.
671 LOG(DFATAL) << "Serializing unhandled GOAWAY status " << status;
677 case GOAWAY_NO_ERROR:
679 case GOAWAY_PROTOCOL_ERROR:
681 case GOAWAY_INTERNAL_ERROR:
683 case GOAWAY_FLOW_CONTROL_ERROR:
685 case GOAWAY_SETTINGS_TIMEOUT:
687 case GOAWAY_STREAM_CLOSED:
689 case GOAWAY_FRAME_SIZE_ERROR:
691 case GOAWAY_REFUSED_STREAM:
695 case GOAWAY_COMPRESSION_ERROR:
697 case GOAWAY_CONNECT_ERROR:
699 case GOAWAY_ENHANCE_YOUR_CALM:
701 case GOAWAY_INADEQUATE_SECURITY:
704 LOG(DFATAL) << "Serializing unhandled GOAWAY status " << status;
708 LOG(DFATAL) << "Unknown SpdyMajorVersion " << version;
712 size_t SpdyConstants::GetDataFrameMinimumSize(SpdyMajorVersion version) {
721 LOG(DFATAL) << "Unhandled SPDY version.";
725 size_t SpdyConstants::GetControlFrameHeaderSize(SpdyMajorVersion version) {
734 LOG(DFATAL) << "Unhandled SPDY version.";
738 size_t SpdyConstants::GetPrefixLength(SpdyFrameType type,
739 SpdyMajorVersion version) {
741 return GetControlFrameHeaderSize(version);
743 return GetDataFrameMinimumSize(version);
747 size_t SpdyConstants::GetFrameMaximumSize(SpdyMajorVersion version) {
748 if (version < SPDY4) {
749 // 24-bit length field plus eight-byte frame header.
750 return ((1<<24) - 1) + 8;
752 // Max payload of 2^14 plus nine-byte frame header.
753 // TODO(mlavan): In HTTP/2 this is actually not a constant;
754 // payload size can be set using the MAX_FRAME_SIZE setting to
755 // anything between 1 << 14 and (1 << 24) - 1
756 return (1 << 14) + 9;
760 size_t SpdyConstants::GetSizeOfSizeField(SpdyMajorVersion version) {
761 return (version < SPDY3) ? sizeof(uint16) : sizeof(uint32);
764 size_t SpdyConstants::GetSettingSize(SpdyMajorVersion version) {
765 return version <= SPDY3 ? 8 : 6;
768 void SpdyDataIR::Visit(SpdyFrameVisitor* visitor) const {
769 return visitor->VisitData(*this);
772 void SpdySynStreamIR::Visit(SpdyFrameVisitor* visitor) const {
773 return visitor->VisitSynStream(*this);
776 void SpdySynReplyIR::Visit(SpdyFrameVisitor* visitor) const {
777 return visitor->VisitSynReply(*this);
780 SpdyRstStreamIR::SpdyRstStreamIR(SpdyStreamId stream_id,
781 SpdyRstStreamStatus status,
782 base::StringPiece description)
783 : SpdyFrameWithStreamIdIR(stream_id),
784 description_(description) {
788 SpdyRstStreamIR::~SpdyRstStreamIR() {}
790 void SpdyRstStreamIR::Visit(SpdyFrameVisitor* visitor) const {
791 return visitor->VisitRstStream(*this);
794 SpdySettingsIR::SpdySettingsIR()
795 : clear_settings_(false),
798 SpdySettingsIR::~SpdySettingsIR() {}
800 void SpdySettingsIR::Visit(SpdyFrameVisitor* visitor) const {
801 return visitor->VisitSettings(*this);
804 void SpdyPingIR::Visit(SpdyFrameVisitor* visitor) const {
805 return visitor->VisitPing(*this);
808 SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id,
809 SpdyGoAwayStatus status,
810 const base::StringPiece& description)
811 : description_(description) {
812 set_last_good_stream_id(last_good_stream_id);
816 SpdyGoAwayIR::~SpdyGoAwayIR() {}
818 const base::StringPiece& SpdyGoAwayIR::description() const {
822 void SpdyGoAwayIR::Visit(SpdyFrameVisitor* visitor) const {
823 return visitor->VisitGoAway(*this);
826 void SpdyHeadersIR::Visit(SpdyFrameVisitor* visitor) const {
827 return visitor->VisitHeaders(*this);
830 void SpdyWindowUpdateIR::Visit(SpdyFrameVisitor* visitor) const {
831 return visitor->VisitWindowUpdate(*this);
834 void SpdyBlockedIR::Visit(SpdyFrameVisitor* visitor) const {
835 return visitor->VisitBlocked(*this);
838 void SpdyPushPromiseIR::Visit(SpdyFrameVisitor* visitor) const {
839 return visitor->VisitPushPromise(*this);
842 void SpdyContinuationIR::Visit(SpdyFrameVisitor* visitor) const {
843 return visitor->VisitContinuation(*this);
846 SpdyAltSvcIR::SpdyAltSvcIR(SpdyStreamId stream_id)
847 : SpdyFrameWithStreamIdIR(stream_id),
851 void SpdyAltSvcIR::Visit(SpdyFrameVisitor* visitor) const {
852 return visitor->VisitAltSvc(*this);
855 SpdyPriorityIR::SpdyPriorityIR(SpdyStreamId stream_id)
856 : SpdyFrameWithStreamIdIR(stream_id) {
859 SpdyPriorityIR::SpdyPriorityIR(SpdyStreamId stream_id,
860 SpdyStreamId parent_stream_id,
863 : SpdyFrameWithStreamIdIR(stream_id),
864 parent_stream_id_(parent_stream_id),
866 exclusive_(exclusive) {
869 void SpdyPriorityIR::Visit(SpdyFrameVisitor* visitor) const {
870 return visitor->VisitPriority(*this);