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
)) {
45 // Check for recognized extensions.
46 if (frame_type_field
== SerializeFrameType(version
, ALTSVC
) ||
47 frame_type_field
== SerializeFrameType(version
, BLOCKED
)) {
51 // DATA is the first valid frame.
52 if (frame_type_field
< SerializeFrameType(version
, DATA
)) {
56 // CONTINUATION is the last valid frame.
57 if (frame_type_field
> SerializeFrameType(version
, CONTINUATION
)) {
64 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
68 SpdyFrameType
SpdyConstants::ParseFrameType(SpdyMajorVersion version
,
69 int frame_type_field
) {
73 switch (frame_type_field
) {
93 switch (frame_type_field
) {
111 return WINDOW_UPDATE
;
122 LOG(DFATAL
) << "Unhandled frame type " << frame_type_field
;
126 int SpdyConstants::SerializeFrameType(SpdyMajorVersion version
,
127 SpdyFrameType frame_type
) {
131 switch (frame_type
) {
149 LOG(DFATAL
) << "Serializing unhandled frame type " << frame_type
;
153 switch (frame_type
) {
174 // ALTSVC and BLOCKED are extensions.
180 LOG(DFATAL
) << "Serializing unhandled frame type " << frame_type
;
185 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
189 int SpdyConstants::DataFrameType(SpdyMajorVersion version
) {
195 return SerializeFrameType(version
, DATA
);
198 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
202 bool SpdyConstants::IsValidSettingId(SpdyMajorVersion version
,
203 int setting_id_field
) {
207 // UPLOAD_BANDWIDTH is the first valid setting id.
208 if (setting_id_field
<
209 SerializeSettingId(version
, SETTINGS_UPLOAD_BANDWIDTH
)) {
213 // INITIAL_WINDOW_SIZE is the last valid setting id.
214 if (setting_id_field
>
215 SerializeSettingId(version
, SETTINGS_INITIAL_WINDOW_SIZE
)) {
221 // HEADER_TABLE_SIZE is the first valid setting id.
222 if (setting_id_field
<
223 SerializeSettingId(version
, SETTINGS_HEADER_TABLE_SIZE
)) {
227 // MAX_HEADER_LIST_SIZE is the last valid setting id.
228 if (setting_id_field
>
229 SerializeSettingId(version
, SETTINGS_MAX_HEADER_LIST_SIZE
)) {
236 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
240 SpdySettingsIds
SpdyConstants::ParseSettingId(SpdyMajorVersion version
,
241 int setting_id_field
) {
245 switch (setting_id_field
) {
247 return SETTINGS_UPLOAD_BANDWIDTH
;
249 return SETTINGS_DOWNLOAD_BANDWIDTH
;
251 return SETTINGS_ROUND_TRIP_TIME
;
253 return SETTINGS_MAX_CONCURRENT_STREAMS
;
255 return SETTINGS_CURRENT_CWND
;
257 return SETTINGS_DOWNLOAD_RETRANS_RATE
;
259 return SETTINGS_INITIAL_WINDOW_SIZE
;
263 switch (setting_id_field
) {
265 return SETTINGS_HEADER_TABLE_SIZE
;
267 return SETTINGS_ENABLE_PUSH
;
269 return SETTINGS_MAX_CONCURRENT_STREAMS
;
271 return SETTINGS_INITIAL_WINDOW_SIZE
;
273 return SETTINGS_MAX_FRAME_SIZE
;
275 return SETTINGS_MAX_HEADER_LIST_SIZE
;
280 LOG(DFATAL
) << "Unhandled setting ID " << setting_id_field
;
281 return SETTINGS_UPLOAD_BANDWIDTH
;
284 int SpdyConstants::SerializeSettingId(SpdyMajorVersion version
,
285 SpdySettingsIds id
) {
290 case SETTINGS_UPLOAD_BANDWIDTH
:
292 case SETTINGS_DOWNLOAD_BANDWIDTH
:
294 case SETTINGS_ROUND_TRIP_TIME
:
296 case SETTINGS_MAX_CONCURRENT_STREAMS
:
298 case SETTINGS_CURRENT_CWND
:
300 case SETTINGS_DOWNLOAD_RETRANS_RATE
:
302 case SETTINGS_INITIAL_WINDOW_SIZE
:
305 LOG(DFATAL
) << "Serializing unhandled setting id " << id
;
310 case SETTINGS_HEADER_TABLE_SIZE
:
312 case SETTINGS_ENABLE_PUSH
:
314 case SETTINGS_MAX_CONCURRENT_STREAMS
:
316 case SETTINGS_INITIAL_WINDOW_SIZE
:
318 case SETTINGS_MAX_FRAME_SIZE
:
320 case SETTINGS_MAX_HEADER_LIST_SIZE
:
323 LOG(DFATAL
) << "Serializing unhandled setting id " << id
;
327 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
331 bool SpdyConstants::IsValidRstStreamStatus(SpdyMajorVersion version
,
332 int rst_stream_status_field
) {
336 // PROTOCOL_ERROR is the valid first status code.
337 if (rst_stream_status_field
<
338 SerializeRstStreamStatus(version
, RST_STREAM_PROTOCOL_ERROR
)) {
342 // FRAME_TOO_LARGE is the valid last status code.
343 if (rst_stream_status_field
>
344 SerializeRstStreamStatus(version
, RST_STREAM_FRAME_TOO_LARGE
)) {
350 // NO_ERROR is the first valid status code.
351 if (rst_stream_status_field
<
352 SerializeRstStreamStatus(version
, RST_STREAM_PROTOCOL_ERROR
)) {
356 // TODO(hkhalil): Omit COMPRESSION_ERROR and SETTINGS_TIMEOUT
358 // This works because GOAWAY and RST_STREAM share a namespace.
359 if (rst_stream_status_field ==
360 SerializeGoAwayStatus(version, GOAWAY_COMPRESSION_ERROR) ||
361 rst_stream_status_field ==
362 SerializeGoAwayStatus(version, GOAWAY_SETTINGS_TIMEOUT)) {
367 // HTTP_1_1_REQUIRED is the last valid status code.
368 if (rst_stream_status_field
>
369 SerializeRstStreamStatus(version
, RST_STREAM_HTTP_1_1_REQUIRED
)) {
375 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
379 SpdyRstStreamStatus
SpdyConstants::ParseRstStreamStatus(
380 SpdyMajorVersion version
,
381 int rst_stream_status_field
) {
385 switch (rst_stream_status_field
) {
387 return RST_STREAM_PROTOCOL_ERROR
;
389 return RST_STREAM_INVALID_STREAM
;
391 return RST_STREAM_REFUSED_STREAM
;
393 return RST_STREAM_UNSUPPORTED_VERSION
;
395 return RST_STREAM_CANCEL
;
397 return RST_STREAM_INTERNAL_ERROR
;
399 return RST_STREAM_FLOW_CONTROL_ERROR
;
401 return RST_STREAM_STREAM_IN_USE
;
403 return RST_STREAM_STREAM_ALREADY_CLOSED
;
405 return RST_STREAM_INVALID_CREDENTIALS
;
407 return RST_STREAM_FRAME_TOO_LARGE
;
411 switch (rst_stream_status_field
) {
413 return RST_STREAM_PROTOCOL_ERROR
;
415 return RST_STREAM_INTERNAL_ERROR
;
417 return RST_STREAM_FLOW_CONTROL_ERROR
;
419 return RST_STREAM_STREAM_CLOSED
;
421 return RST_STREAM_FRAME_SIZE_ERROR
;
423 return RST_STREAM_REFUSED_STREAM
;
425 return RST_STREAM_CANCEL
;
427 return RST_STREAM_CONNECT_ERROR
;
429 return RST_STREAM_ENHANCE_YOUR_CALM
;
431 return RST_STREAM_INADEQUATE_SECURITY
;
433 return RST_STREAM_HTTP_1_1_REQUIRED
;
438 LOG(DFATAL
) << "Invalid RST_STREAM status " << rst_stream_status_field
;
439 return RST_STREAM_PROTOCOL_ERROR
;
442 int SpdyConstants::SerializeRstStreamStatus(
443 SpdyMajorVersion version
,
444 SpdyRstStreamStatus rst_stream_status
) {
448 switch (rst_stream_status
) {
449 case RST_STREAM_PROTOCOL_ERROR
:
451 case RST_STREAM_INVALID_STREAM
:
453 case RST_STREAM_REFUSED_STREAM
:
455 case RST_STREAM_UNSUPPORTED_VERSION
:
457 case RST_STREAM_CANCEL
:
459 case RST_STREAM_INTERNAL_ERROR
:
461 case RST_STREAM_FLOW_CONTROL_ERROR
:
463 case RST_STREAM_STREAM_IN_USE
:
465 case RST_STREAM_STREAM_ALREADY_CLOSED
:
467 case RST_STREAM_INVALID_CREDENTIALS
:
469 case RST_STREAM_FRAME_TOO_LARGE
:
472 LOG(DFATAL
) << "Unhandled RST_STREAM status "
473 << rst_stream_status
;
477 switch (rst_stream_status
) {
478 case RST_STREAM_PROTOCOL_ERROR
:
480 case RST_STREAM_INTERNAL_ERROR
:
482 case RST_STREAM_FLOW_CONTROL_ERROR
:
484 case RST_STREAM_STREAM_CLOSED
:
486 case RST_STREAM_FRAME_SIZE_ERROR
:
488 case RST_STREAM_REFUSED_STREAM
:
490 case RST_STREAM_CANCEL
:
492 case RST_STREAM_CONNECT_ERROR
:
494 case RST_STREAM_ENHANCE_YOUR_CALM
:
496 case RST_STREAM_INADEQUATE_SECURITY
:
498 case RST_STREAM_HTTP_1_1_REQUIRED
:
501 LOG(DFATAL
) << "Unhandled RST_STREAM status "
502 << rst_stream_status
;
506 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
510 bool SpdyConstants::IsValidGoAwayStatus(SpdyMajorVersion version
,
511 int goaway_status_field
) {
515 // GOAWAY_OK is the first valid status.
516 if (goaway_status_field
< SerializeGoAwayStatus(version
, GOAWAY_OK
)) {
520 // GOAWAY_INTERNAL_ERROR is the last valid status.
521 if (goaway_status_field
> SerializeGoAwayStatus(version
,
522 GOAWAY_INTERNAL_ERROR
)) {
528 // GOAWAY_NO_ERROR is the first valid status.
529 if (goaway_status_field
< SerializeGoAwayStatus(version
,
534 // GOAWAY_HTTP_1_1_REQUIRED is the last valid status.
535 if (goaway_status_field
>
536 SerializeGoAwayStatus(version
, GOAWAY_HTTP_1_1_REQUIRED
)) {
542 LOG(DFATAL
) << "Unknown SpdyMajorVersion " << version
;
546 SpdyGoAwayStatus
SpdyConstants::ParseGoAwayStatus(SpdyMajorVersion version
,
547 int goaway_status_field
) {
551 switch (goaway_status_field
) {
555 return GOAWAY_PROTOCOL_ERROR
;
557 return GOAWAY_INTERNAL_ERROR
;
561 switch (goaway_status_field
) {
563 return GOAWAY_NO_ERROR
;
565 return GOAWAY_PROTOCOL_ERROR
;
567 return GOAWAY_INTERNAL_ERROR
;
569 return GOAWAY_FLOW_CONTROL_ERROR
;
571 return GOAWAY_SETTINGS_TIMEOUT
;
573 return GOAWAY_STREAM_CLOSED
;
575 return GOAWAY_FRAME_SIZE_ERROR
;
577 return GOAWAY_REFUSED_STREAM
;
579 return GOAWAY_CANCEL
;
581 return GOAWAY_COMPRESSION_ERROR
;
583 return GOAWAY_CONNECT_ERROR
;
585 return GOAWAY_ENHANCE_YOUR_CALM
;
587 return GOAWAY_INADEQUATE_SECURITY
;
589 return GOAWAY_HTTP_1_1_REQUIRED
;
594 LOG(DFATAL
) << "Unhandled GOAWAY status " << goaway_status_field
;
595 return GOAWAY_PROTOCOL_ERROR
;
598 SpdyMajorVersion
SpdyConstants::ParseMajorVersion(int version_number
) {
599 switch (version_number
) {
607 LOG(DFATAL
) << "Unsupported SPDY version number: " << version_number
;
612 int SpdyConstants::SerializeMajorVersion(SpdyMajorVersion version
) {
621 LOG(DFATAL
) << "Unsupported SPDY major version: " << version
;
626 std::string
SpdyConstants::GetVersionString(SpdyMajorVersion version
) {
635 LOG(DFATAL
) << "Unsupported SPDY major version: " << version
;
640 int SpdyConstants::SerializeGoAwayStatus(SpdyMajorVersion version
,
641 SpdyGoAwayStatus status
) {
645 // TODO(jgraettinger): Merge this back to server-side.
647 case GOAWAY_NO_ERROR
:
649 case GOAWAY_PROTOCOL_ERROR
:
650 case GOAWAY_INTERNAL_ERROR
:
651 case GOAWAY_FLOW_CONTROL_ERROR
:
652 case GOAWAY_SETTINGS_TIMEOUT
:
653 case GOAWAY_STREAM_CLOSED
:
654 case GOAWAY_FRAME_SIZE_ERROR
:
655 case GOAWAY_REFUSED_STREAM
:
657 case GOAWAY_COMPRESSION_ERROR
:
658 case GOAWAY_CONNECT_ERROR
:
659 case GOAWAY_ENHANCE_YOUR_CALM
:
660 case GOAWAY_INADEQUATE_SECURITY
:
661 case GOAWAY_HTTP_1_1_REQUIRED
:
662 return 1; // PROTOCOL_ERROR.
664 LOG(DFATAL
) << "Serializing unhandled GOAWAY status " << status
;
669 case GOAWAY_NO_ERROR
:
671 case GOAWAY_PROTOCOL_ERROR
:
673 case GOAWAY_INTERNAL_ERROR
:
675 case GOAWAY_FLOW_CONTROL_ERROR
:
677 case GOAWAY_SETTINGS_TIMEOUT
:
679 case GOAWAY_STREAM_CLOSED
:
681 case GOAWAY_FRAME_SIZE_ERROR
:
683 case GOAWAY_REFUSED_STREAM
:
687 case GOAWAY_COMPRESSION_ERROR
:
689 case GOAWAY_CONNECT_ERROR
:
691 case GOAWAY_ENHANCE_YOUR_CALM
:
693 case GOAWAY_INADEQUATE_SECURITY
:
695 case GOAWAY_HTTP_1_1_REQUIRED
:
698 LOG(DFATAL
) << "Serializing unhandled GOAWAY status " << status
;
702 LOG(DFATAL
) << "Unknown SpdyMajorVersion " << version
;
706 size_t SpdyConstants::GetDataFrameMinimumSize(SpdyMajorVersion version
) {
714 LOG(DFATAL
) << "Unhandled SPDY version.";
718 size_t SpdyConstants::GetControlFrameHeaderSize(SpdyMajorVersion version
) {
726 LOG(DFATAL
) << "Unhandled SPDY version.";
730 size_t SpdyConstants::GetPrefixLength(SpdyFrameType type
,
731 SpdyMajorVersion version
) {
733 return GetControlFrameHeaderSize(version
);
735 return GetDataFrameMinimumSize(version
);
739 size_t SpdyConstants::GetFrameMaximumSize(SpdyMajorVersion version
) {
740 if (version
< SPDY4
) {
741 // 24-bit length field plus eight-byte frame header.
742 return ((1<<24) - 1) + 8;
744 // Max payload of 2^14 plus nine-byte frame header.
745 // TODO(mlavan): In HTTP/2 this is actually not a constant;
746 // payload size can be set using the MAX_FRAME_SIZE setting to
747 // anything between 1 << 14 and (1 << 24) - 1
748 return (1 << 14) + 9;
752 size_t SpdyConstants::GetSizeOfSizeField(SpdyMajorVersion version
) {
753 return (version
< SPDY3
) ? sizeof(uint16
) : sizeof(uint32
);
756 size_t SpdyConstants::GetSettingSize(SpdyMajorVersion version
) {
757 return version
<= SPDY3
? 8 : 6;
760 int32
SpdyConstants::GetInitialStreamWindowSize(SpdyMajorVersion version
) {
761 return (version
<= SPDY3
) ? (64 * 1024) : (64 * 1024 - 1);
764 int32
SpdyConstants::GetInitialSessionWindowSize(SpdyMajorVersion version
) {
765 return (version
<= SPDY3
) ? (64 * 1024) : (64 * 1024 - 1);
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);