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);