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 // HTTP_1_1_REQUIRED is the last valid status code.
376 if (rst_stream_status_field
>
377 SerializeRstStreamStatus(version
, RST_STREAM_HTTP_1_1_REQUIRED
)) {
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
;
440 return RST_STREAM_INADEQUATE_SECURITY
;
442 return RST_STREAM_HTTP_1_1_REQUIRED
;
447 LOG(DFATAL
) << "Invalid RST_STREAM status " << rst_stream_status_field
;
448 return RST_STREAM_PROTOCOL_ERROR
;
451 int SpdyConstants::SerializeRstStreamStatus(
452 SpdyMajorVersion version
,
453 SpdyRstStreamStatus rst_stream_status
) {
457 switch (rst_stream_status
) {
458 case RST_STREAM_PROTOCOL_ERROR
:
460 case RST_STREAM_INVALID_STREAM
:
462 case RST_STREAM_REFUSED_STREAM
:
464 case RST_STREAM_UNSUPPORTED_VERSION
:
466 case RST_STREAM_CANCEL
:
468 case RST_STREAM_INTERNAL_ERROR
:
470 case RST_STREAM_FLOW_CONTROL_ERROR
:
472 case RST_STREAM_STREAM_IN_USE
:
474 case RST_STREAM_STREAM_ALREADY_CLOSED
:
476 case RST_STREAM_INVALID_CREDENTIALS
:
478 case RST_STREAM_FRAME_TOO_LARGE
:
481 LOG(DFATAL
) << "Unhandled RST_STREAM status "
482 << rst_stream_status
;
487 switch (rst_stream_status
) {
488 case RST_STREAM_PROTOCOL_ERROR
:
490 case RST_STREAM_INTERNAL_ERROR
:
492 case RST_STREAM_FLOW_CONTROL_ERROR
:
494 case RST_STREAM_STREAM_CLOSED
:
496 case RST_STREAM_FRAME_SIZE_ERROR
:
498 case RST_STREAM_REFUSED_STREAM
:
500 case RST_STREAM_CANCEL
:
502 case RST_STREAM_CONNECT_ERROR
:
504 case RST_STREAM_ENHANCE_YOUR_CALM
:
506 case RST_STREAM_INADEQUATE_SECURITY
:
508 case RST_STREAM_HTTP_1_1_REQUIRED
:
511 LOG(DFATAL
) << "Unhandled RST_STREAM status "
512 << rst_stream_status
;
516 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
520 bool SpdyConstants::IsValidGoAwayStatus(SpdyMajorVersion version
,
521 int goaway_status_field
) {
525 // GOAWAY_OK is the first valid status.
526 if (goaway_status_field
< SerializeGoAwayStatus(version
, GOAWAY_OK
)) {
530 // GOAWAY_INTERNAL_ERROR is the last valid status.
531 if (goaway_status_field
> SerializeGoAwayStatus(version
,
532 GOAWAY_INTERNAL_ERROR
)) {
539 // GOAWAY_NO_ERROR is the first valid status.
540 if (goaway_status_field
< SerializeGoAwayStatus(version
,
545 // GOAWAY_INADEQUATE_SECURITY is the last valid status.
546 if (goaway_status_field
>
547 SerializeGoAwayStatus(version
, GOAWAY_INADEQUATE_SECURITY
)) {
553 LOG(DFATAL
) << "Unknown SpdyMajorVersion " << version
;
557 SpdyGoAwayStatus
SpdyConstants::ParseGoAwayStatus(SpdyMajorVersion version
,
558 int goaway_status_field
) {
562 switch (goaway_status_field
) {
566 return GOAWAY_PROTOCOL_ERROR
;
568 return GOAWAY_INTERNAL_ERROR
;
573 switch (goaway_status_field
) {
575 return GOAWAY_NO_ERROR
;
577 return GOAWAY_PROTOCOL_ERROR
;
579 return GOAWAY_INTERNAL_ERROR
;
581 return GOAWAY_FLOW_CONTROL_ERROR
;
583 return GOAWAY_SETTINGS_TIMEOUT
;
585 return GOAWAY_STREAM_CLOSED
;
587 return GOAWAY_FRAME_SIZE_ERROR
;
589 return GOAWAY_REFUSED_STREAM
;
591 return GOAWAY_CANCEL
;
593 return GOAWAY_COMPRESSION_ERROR
;
595 return GOAWAY_CONNECT_ERROR
;
597 return GOAWAY_ENHANCE_YOUR_CALM
;
599 return GOAWAY_INADEQUATE_SECURITY
;
601 return GOAWAY_HTTP_1_1_REQUIRED
;
606 LOG(DFATAL
) << "Unhandled GOAWAY status " << goaway_status_field
;
607 return GOAWAY_PROTOCOL_ERROR
;
610 SpdyMajorVersion
SpdyConstants::ParseMajorVersion(int version_number
) {
611 switch (version_number
) {
621 LOG(DFATAL
) << "Unsupported SPDY version number: " << version_number
;
626 int SpdyConstants::SerializeMajorVersion(SpdyMajorVersion version
) {
637 LOG(DFATAL
) << "Unsupported SPDY major version: " << version
;
642 std::string
SpdyConstants::GetVersionString(SpdyMajorVersion version
) {
653 LOG(DFATAL
) << "Unsupported SPDY major version: " << version
;
658 int SpdyConstants::SerializeGoAwayStatus(SpdyMajorVersion version
,
659 SpdyGoAwayStatus status
) {
663 // TODO(jgraettinger): Merge this back to server-side.
665 case GOAWAY_NO_ERROR
:
667 case GOAWAY_PROTOCOL_ERROR
:
668 case GOAWAY_INTERNAL_ERROR
:
669 case GOAWAY_FLOW_CONTROL_ERROR
:
670 case GOAWAY_SETTINGS_TIMEOUT
:
671 case GOAWAY_STREAM_CLOSED
:
672 case GOAWAY_FRAME_SIZE_ERROR
:
673 case GOAWAY_REFUSED_STREAM
:
675 case GOAWAY_COMPRESSION_ERROR
:
676 case GOAWAY_CONNECT_ERROR
:
677 case GOAWAY_ENHANCE_YOUR_CALM
:
678 case GOAWAY_INADEQUATE_SECURITY
:
679 case GOAWAY_HTTP_1_1_REQUIRED
:
680 return 1; // PROTOCOL_ERROR.
682 LOG(DFATAL
) << "Serializing unhandled GOAWAY status " << status
;
688 case GOAWAY_NO_ERROR
:
690 case GOAWAY_PROTOCOL_ERROR
:
692 case GOAWAY_INTERNAL_ERROR
:
694 case GOAWAY_FLOW_CONTROL_ERROR
:
696 case GOAWAY_SETTINGS_TIMEOUT
:
698 case GOAWAY_STREAM_CLOSED
:
700 case GOAWAY_FRAME_SIZE_ERROR
:
702 case GOAWAY_REFUSED_STREAM
:
706 case GOAWAY_COMPRESSION_ERROR
:
708 case GOAWAY_CONNECT_ERROR
:
710 case GOAWAY_ENHANCE_YOUR_CALM
:
712 case GOAWAY_INADEQUATE_SECURITY
:
714 case GOAWAY_HTTP_1_1_REQUIRED
:
717 LOG(DFATAL
) << "Serializing unhandled GOAWAY status " << status
;
721 LOG(DFATAL
) << "Unknown SpdyMajorVersion " << version
;
725 size_t SpdyConstants::GetDataFrameMinimumSize(SpdyMajorVersion version
) {
734 LOG(DFATAL
) << "Unhandled SPDY version.";
738 size_t SpdyConstants::GetControlFrameHeaderSize(SpdyMajorVersion version
) {
747 LOG(DFATAL
) << "Unhandled SPDY version.";
751 size_t SpdyConstants::GetPrefixLength(SpdyFrameType type
,
752 SpdyMajorVersion version
) {
754 return GetControlFrameHeaderSize(version
);
756 return GetDataFrameMinimumSize(version
);
760 size_t SpdyConstants::GetFrameMaximumSize(SpdyMajorVersion version
) {
761 if (version
< SPDY4
) {
762 // 24-bit length field plus eight-byte frame header.
763 return ((1<<24) - 1) + 8;
765 // Max payload of 2^14 plus nine-byte frame header.
766 // TODO(mlavan): In HTTP/2 this is actually not a constant;
767 // payload size can be set using the MAX_FRAME_SIZE setting to
768 // anything between 1 << 14 and (1 << 24) - 1
769 return (1 << 14) + 9;
773 size_t SpdyConstants::GetSizeOfSizeField(SpdyMajorVersion version
) {
774 return (version
< SPDY3
) ? sizeof(uint16
) : sizeof(uint32
);
777 size_t SpdyConstants::GetSettingSize(SpdyMajorVersion version
) {
778 return version
<= SPDY3
? 8 : 6;
781 void SpdyDataIR::Visit(SpdyFrameVisitor
* visitor
) const {
782 return visitor
->VisitData(*this);
785 void SpdySynStreamIR::Visit(SpdyFrameVisitor
* visitor
) const {
786 return visitor
->VisitSynStream(*this);
789 void SpdySynReplyIR::Visit(SpdyFrameVisitor
* visitor
) const {
790 return visitor
->VisitSynReply(*this);
793 SpdyRstStreamIR::SpdyRstStreamIR(SpdyStreamId stream_id
,
794 SpdyRstStreamStatus status
,
795 base::StringPiece description
)
796 : SpdyFrameWithStreamIdIR(stream_id
),
797 description_(description
) {
801 SpdyRstStreamIR::~SpdyRstStreamIR() {}
803 void SpdyRstStreamIR::Visit(SpdyFrameVisitor
* visitor
) const {
804 return visitor
->VisitRstStream(*this);
807 SpdySettingsIR::SpdySettingsIR()
808 : clear_settings_(false),
811 SpdySettingsIR::~SpdySettingsIR() {}
813 void SpdySettingsIR::Visit(SpdyFrameVisitor
* visitor
) const {
814 return visitor
->VisitSettings(*this);
817 void SpdyPingIR::Visit(SpdyFrameVisitor
* visitor
) const {
818 return visitor
->VisitPing(*this);
821 SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id
,
822 SpdyGoAwayStatus status
,
823 const base::StringPiece
& description
)
824 : description_(description
) {
825 set_last_good_stream_id(last_good_stream_id
);
829 SpdyGoAwayIR::~SpdyGoAwayIR() {}
831 const base::StringPiece
& SpdyGoAwayIR::description() const {
835 void SpdyGoAwayIR::Visit(SpdyFrameVisitor
* visitor
) const {
836 return visitor
->VisitGoAway(*this);
839 void SpdyHeadersIR::Visit(SpdyFrameVisitor
* visitor
) const {
840 return visitor
->VisitHeaders(*this);
843 void SpdyWindowUpdateIR::Visit(SpdyFrameVisitor
* visitor
) const {
844 return visitor
->VisitWindowUpdate(*this);
847 void SpdyBlockedIR::Visit(SpdyFrameVisitor
* visitor
) const {
848 return visitor
->VisitBlocked(*this);
851 void SpdyPushPromiseIR::Visit(SpdyFrameVisitor
* visitor
) const {
852 return visitor
->VisitPushPromise(*this);
855 void SpdyContinuationIR::Visit(SpdyFrameVisitor
* visitor
) const {
856 return visitor
->VisitContinuation(*this);
859 SpdyAltSvcIR::SpdyAltSvcIR(SpdyStreamId stream_id
)
860 : SpdyFrameWithStreamIdIR(stream_id
),
864 void SpdyAltSvcIR::Visit(SpdyFrameVisitor
* visitor
) const {
865 return visitor
->VisitAltSvc(*this);
868 SpdyPriorityIR::SpdyPriorityIR(SpdyStreamId stream_id
)
869 : SpdyFrameWithStreamIdIR(stream_id
) {
872 SpdyPriorityIR::SpdyPriorityIR(SpdyStreamId stream_id
,
873 SpdyStreamId parent_stream_id
,
876 : SpdyFrameWithStreamIdIR(stream_id
),
877 parent_stream_id_(parent_stream_id
),
879 exclusive_(exclusive
) {
882 void SpdyPriorityIR::Visit(SpdyFrameVisitor
* visitor
) const {
883 return visitor
->VisitPriority(*this);