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 // DATA is the first valid frame.
47 if (frame_type_field
< SerializeFrameType(version
, DATA
)) {
51 // BLOCKED is the last valid frame.
52 if (frame_type_field
> SerializeFrameType(version
, BLOCKED
)) {
59 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
63 SpdyFrameType
SpdyConstants::ParseFrameType(SpdyMajorVersion version
,
64 int frame_type_field
) {
68 switch (frame_type_field
) {
89 switch (frame_type_field
) {
107 return WINDOW_UPDATE
;
118 LOG(DFATAL
) << "Unhandled frame type " << frame_type_field
;
122 int SpdyConstants::SerializeFrameType(SpdyMajorVersion version
,
123 SpdyFrameType frame_type
) {
127 switch (frame_type
) {
145 LOG(DFATAL
) << "Serializing unhandled frame type " << frame_type
;
150 switch (frame_type
) {
176 LOG(DFATAL
) << "Serializing unhandled frame type " << frame_type
;
181 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
185 int SpdyConstants::DataFrameType(SpdyMajorVersion version
) {
192 return SerializeFrameType(version
, DATA
);
195 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
199 bool SpdyConstants::IsValidSettingId(SpdyMajorVersion version
,
200 int setting_id_field
) {
204 // UPLOAD_BANDWIDTH is the first valid setting id.
205 if (setting_id_field
<
206 SerializeSettingId(version
, SETTINGS_UPLOAD_BANDWIDTH
)) {
210 // INITIAL_WINDOW_SIZE is the last valid setting id.
211 if (setting_id_field
>
212 SerializeSettingId(version
, SETTINGS_INITIAL_WINDOW_SIZE
)) {
219 // HEADER_TABLE_SIZE is the first valid setting id.
220 if (setting_id_field
<
221 SerializeSettingId(version
, SETTINGS_HEADER_TABLE_SIZE
)) {
225 // INITIAL_WINDOW_SIZE is the last valid setting id.
226 if (setting_id_field
>
227 SerializeSettingId(version
, SETTINGS_INITIAL_WINDOW_SIZE
)) {
234 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
238 SpdySettingsIds
SpdyConstants::ParseSettingId(SpdyMajorVersion version
,
239 int setting_id_field
) {
243 switch (setting_id_field
) {
245 return SETTINGS_UPLOAD_BANDWIDTH
;
247 return SETTINGS_DOWNLOAD_BANDWIDTH
;
249 return SETTINGS_ROUND_TRIP_TIME
;
251 return SETTINGS_MAX_CONCURRENT_STREAMS
;
253 return SETTINGS_CURRENT_CWND
;
255 return SETTINGS_DOWNLOAD_RETRANS_RATE
;
257 return SETTINGS_INITIAL_WINDOW_SIZE
;
262 switch (setting_id_field
) {
264 return SETTINGS_HEADER_TABLE_SIZE
;
266 return SETTINGS_ENABLE_PUSH
;
268 return SETTINGS_MAX_CONCURRENT_STREAMS
;
270 return SETTINGS_INITIAL_WINDOW_SIZE
;
275 LOG(DFATAL
) << "Unhandled setting ID " << setting_id_field
;
276 return SETTINGS_UPLOAD_BANDWIDTH
;
279 int SpdyConstants::SerializeSettingId(SpdyMajorVersion version
,
280 SpdySettingsIds id
) {
285 case SETTINGS_UPLOAD_BANDWIDTH
:
287 case SETTINGS_DOWNLOAD_BANDWIDTH
:
289 case SETTINGS_ROUND_TRIP_TIME
:
291 case SETTINGS_MAX_CONCURRENT_STREAMS
:
293 case SETTINGS_CURRENT_CWND
:
295 case SETTINGS_DOWNLOAD_RETRANS_RATE
:
297 case SETTINGS_INITIAL_WINDOW_SIZE
:
300 LOG(DFATAL
) << "Serializing unhandled setting id " << id
;
306 case SETTINGS_HEADER_TABLE_SIZE
:
308 case SETTINGS_ENABLE_PUSH
:
310 case SETTINGS_MAX_CONCURRENT_STREAMS
:
312 case SETTINGS_INITIAL_WINDOW_SIZE
:
315 LOG(DFATAL
) << "Serializing unhandled setting id " << id
;
319 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
323 bool SpdyConstants::IsValidRstStreamStatus(SpdyMajorVersion version
,
324 int rst_stream_status_field
) {
328 // PROTOCOL_ERROR is the valid first status code.
329 if (rst_stream_status_field
<
330 SerializeRstStreamStatus(version
, RST_STREAM_PROTOCOL_ERROR
)) {
334 // FRAME_TOO_LARGE is the valid last status code.
335 if (rst_stream_status_field
>
336 SerializeRstStreamStatus(version
, RST_STREAM_FRAME_TOO_LARGE
)) {
343 // NO_ERROR is the first valid status code.
344 if (rst_stream_status_field
<
345 SerializeRstStreamStatus(version
, RST_STREAM_PROTOCOL_ERROR
)) {
349 // TODO(hkhalil): Omit COMPRESSION_ERROR and SETTINGS_TIMEOUT
351 // This works because GOAWAY and RST_STREAM share a namespace.
352 if (rst_stream_status_field ==
353 SerializeGoAwayStatus(version, GOAWAY_COMPRESSION_ERROR) ||
354 rst_stream_status_field ==
355 SerializeGoAwayStatus(version, GOAWAY_SETTINGS_TIMEOUT)) {
360 // ENHANCE_YOUR_CALM is the last valid status code.
361 if (rst_stream_status_field
>
362 SerializeRstStreamStatus(version
, RST_STREAM_ENHANCE_YOUR_CALM
)) {
368 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
372 SpdyRstStreamStatus
SpdyConstants::ParseRstStreamStatus(
373 SpdyMajorVersion version
,
374 int rst_stream_status_field
) {
378 switch (rst_stream_status_field
) {
380 return RST_STREAM_PROTOCOL_ERROR
;
382 return RST_STREAM_INVALID_STREAM
;
384 return RST_STREAM_REFUSED_STREAM
;
386 return RST_STREAM_UNSUPPORTED_VERSION
;
388 return RST_STREAM_CANCEL
;
390 return RST_STREAM_INTERNAL_ERROR
;
392 return RST_STREAM_FLOW_CONTROL_ERROR
;
394 return RST_STREAM_STREAM_IN_USE
;
396 return RST_STREAM_STREAM_ALREADY_CLOSED
;
398 return RST_STREAM_INVALID_CREDENTIALS
;
400 return RST_STREAM_FRAME_TOO_LARGE
;
405 switch (rst_stream_status_field
) {
407 return RST_STREAM_PROTOCOL_ERROR
;
409 return RST_STREAM_INTERNAL_ERROR
;
411 return RST_STREAM_FLOW_CONTROL_ERROR
;
413 return RST_STREAM_STREAM_CLOSED
;
415 return RST_STREAM_FRAME_SIZE_ERROR
;
417 return RST_STREAM_REFUSED_STREAM
;
419 return RST_STREAM_CANCEL
;
421 return RST_STREAM_CONNECT_ERROR
;
423 return RST_STREAM_ENHANCE_YOUR_CALM
;
428 LOG(DFATAL
) << "Invalid RST_STREAM status " << rst_stream_status_field
;
429 return RST_STREAM_PROTOCOL_ERROR
;
432 int SpdyConstants::SerializeRstStreamStatus(
433 SpdyMajorVersion version
,
434 SpdyRstStreamStatus rst_stream_status
) {
438 switch (rst_stream_status
) {
439 case RST_STREAM_PROTOCOL_ERROR
:
441 case RST_STREAM_INVALID_STREAM
:
443 case RST_STREAM_REFUSED_STREAM
:
445 case RST_STREAM_UNSUPPORTED_VERSION
:
447 case RST_STREAM_CANCEL
:
449 case RST_STREAM_INTERNAL_ERROR
:
451 case RST_STREAM_FLOW_CONTROL_ERROR
:
453 case RST_STREAM_STREAM_IN_USE
:
455 case RST_STREAM_STREAM_ALREADY_CLOSED
:
457 case RST_STREAM_INVALID_CREDENTIALS
:
459 case RST_STREAM_FRAME_TOO_LARGE
:
462 LOG(DFATAL
) << "Unhandled RST_STREAM status "
463 << rst_stream_status
;
468 switch (rst_stream_status
) {
469 case RST_STREAM_PROTOCOL_ERROR
:
471 case RST_STREAM_INTERNAL_ERROR
:
473 case RST_STREAM_FLOW_CONTROL_ERROR
:
475 case RST_STREAM_STREAM_CLOSED
:
477 case RST_STREAM_FRAME_SIZE_ERROR
:
479 case RST_STREAM_REFUSED_STREAM
:
481 case RST_STREAM_CANCEL
:
483 case RST_STREAM_CONNECT_ERROR
:
485 case RST_STREAM_ENHANCE_YOUR_CALM
:
488 LOG(DFATAL
) << "Unhandled RST_STREAM status "
489 << rst_stream_status
;
493 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
497 bool SpdyConstants::IsValidGoAwayStatus(SpdyMajorVersion version
,
498 int goaway_status_field
) {
502 // GOAWAY_OK is the first valid status.
503 if (goaway_status_field
< SerializeGoAwayStatus(version
, GOAWAY_OK
)) {
507 // GOAWAY_INTERNAL_ERROR is the last valid status.
508 if (goaway_status_field
> SerializeGoAwayStatus(version
,
509 GOAWAY_INTERNAL_ERROR
)) {
516 // GOAWAY_NO_ERROR is the first valid status.
517 if (goaway_status_field
< SerializeGoAwayStatus(version
,
522 // GOAWAY_INADEQUATE_SECURITY is the last valid status.
523 if (goaway_status_field
>
524 SerializeGoAwayStatus(version
, GOAWAY_INADEQUATE_SECURITY
)) {
530 LOG(DFATAL
) << "Unknown SpdyMajorVersion " << version
;
534 SpdyGoAwayStatus
SpdyConstants::ParseGoAwayStatus(SpdyMajorVersion version
,
535 int goaway_status_field
) {
539 switch (goaway_status_field
) {
543 return GOAWAY_PROTOCOL_ERROR
;
545 return GOAWAY_INTERNAL_ERROR
;
550 switch (goaway_status_field
) {
552 return GOAWAY_NO_ERROR
;
554 return GOAWAY_PROTOCOL_ERROR
;
556 return GOAWAY_INTERNAL_ERROR
;
558 return GOAWAY_FLOW_CONTROL_ERROR
;
560 return GOAWAY_SETTINGS_TIMEOUT
;
562 return GOAWAY_STREAM_CLOSED
;
564 return GOAWAY_FRAME_SIZE_ERROR
;
566 return GOAWAY_REFUSED_STREAM
;
568 return GOAWAY_CANCEL
;
570 return GOAWAY_COMPRESSION_ERROR
;
572 return GOAWAY_CONNECT_ERROR
;
574 return GOAWAY_ENHANCE_YOUR_CALM
;
576 return GOAWAY_INADEQUATE_SECURITY
;
581 LOG(DFATAL
) << "Unhandled GOAWAY status " << goaway_status_field
;
582 return GOAWAY_PROTOCOL_ERROR
;
585 SpdyMajorVersion
SpdyConstants::ParseMajorVersion(int version_number
) {
586 switch (version_number
) {
596 LOG(DFATAL
) << "Unsupported SPDY version number: " << version_number
;
601 int SpdyConstants::SerializeMajorVersion(SpdyMajorVersion version
) {
612 LOG(DFATAL
) << "Unsupported SPDY major version: " << version
;
617 std::string
SpdyConstants::GetVersionString(SpdyMajorVersion version
) {
628 LOG(DFATAL
) << "Unsupported SPDY major version: " << version
;
633 int SpdyConstants::SerializeGoAwayStatus(SpdyMajorVersion version
,
634 SpdyGoAwayStatus status
) {
638 // TODO(jgraettinger): Merge this back to server-side.
640 case GOAWAY_NO_ERROR
:
642 case GOAWAY_PROTOCOL_ERROR
:
643 case GOAWAY_INTERNAL_ERROR
:
644 case GOAWAY_FLOW_CONTROL_ERROR
:
645 case GOAWAY_SETTINGS_TIMEOUT
:
646 case GOAWAY_STREAM_CLOSED
:
647 case GOAWAY_FRAME_SIZE_ERROR
:
648 case GOAWAY_REFUSED_STREAM
:
650 case GOAWAY_COMPRESSION_ERROR
:
651 case GOAWAY_CONNECT_ERROR
:
652 case GOAWAY_ENHANCE_YOUR_CALM
:
653 case GOAWAY_INADEQUATE_SECURITY
:
654 return 1; // PROTOCOL_ERROR.
656 LOG(DFATAL
) << "Serializing unhandled GOAWAY status " << status
;
662 case GOAWAY_NO_ERROR
:
664 case GOAWAY_PROTOCOL_ERROR
:
666 case GOAWAY_INTERNAL_ERROR
:
668 case GOAWAY_FLOW_CONTROL_ERROR
:
670 case GOAWAY_SETTINGS_TIMEOUT
:
672 case GOAWAY_STREAM_CLOSED
:
674 case GOAWAY_FRAME_SIZE_ERROR
:
676 case GOAWAY_REFUSED_STREAM
:
680 case GOAWAY_COMPRESSION_ERROR
:
682 case GOAWAY_CONNECT_ERROR
:
684 case GOAWAY_ENHANCE_YOUR_CALM
:
686 case GOAWAY_INADEQUATE_SECURITY
:
689 LOG(DFATAL
) << "Serializing unhandled GOAWAY status " << status
;
693 LOG(DFATAL
) << "Unknown SpdyMajorVersion " << version
;
697 size_t SpdyConstants::GetDataFrameMinimumSize() {
701 size_t SpdyConstants::GetControlFrameHeaderSize(SpdyMajorVersion version
) {
709 LOG(DFATAL
) << "Unhandled SPDY version.";
713 size_t SpdyConstants::GetPrefixLength(SpdyFrameType type
,
714 SpdyMajorVersion version
) {
716 return GetControlFrameHeaderSize(version
);
718 return GetDataFrameMinimumSize();
722 size_t SpdyConstants::GetFrameMaximumSize(SpdyMajorVersion version
) {
723 if (version
< SPDY4
) {
724 // 24-bit length field plus eight-byte frame header.
725 return ((1<<24) - 1) + 8;
727 // 14-bit length field.
732 size_t SpdyConstants::GetSizeOfSizeField(SpdyMajorVersion version
) {
733 return (version
< SPDY3
) ? sizeof(uint16
) : sizeof(uint32
);
736 size_t SpdyConstants::GetSettingSize(SpdyMajorVersion version
) {
737 return version
<= SPDY3
? 8 : 6;
740 void SpdyDataIR::Visit(SpdyFrameVisitor
* visitor
) const {
741 return visitor
->VisitData(*this);
744 void SpdySynStreamIR::Visit(SpdyFrameVisitor
* visitor
) const {
745 return visitor
->VisitSynStream(*this);
748 void SpdySynReplyIR::Visit(SpdyFrameVisitor
* visitor
) const {
749 return visitor
->VisitSynReply(*this);
752 SpdyRstStreamIR::SpdyRstStreamIR(SpdyStreamId stream_id
,
753 SpdyRstStreamStatus status
,
754 base::StringPiece description
)
755 : SpdyFrameWithStreamIdIR(stream_id
),
756 description_(description
) {
760 SpdyRstStreamIR::~SpdyRstStreamIR() {}
762 void SpdyRstStreamIR::Visit(SpdyFrameVisitor
* visitor
) const {
763 return visitor
->VisitRstStream(*this);
766 SpdySettingsIR::SpdySettingsIR()
767 : clear_settings_(false),
770 SpdySettingsIR::~SpdySettingsIR() {}
772 void SpdySettingsIR::Visit(SpdyFrameVisitor
* visitor
) const {
773 return visitor
->VisitSettings(*this);
776 void SpdyPingIR::Visit(SpdyFrameVisitor
* visitor
) const {
777 return visitor
->VisitPing(*this);
780 SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id
,
781 SpdyGoAwayStatus status
,
782 const base::StringPiece
& description
)
783 : description_(description
) {
784 set_last_good_stream_id(last_good_stream_id
);
788 SpdyGoAwayIR::~SpdyGoAwayIR() {}
790 const base::StringPiece
& SpdyGoAwayIR::description() const {
794 void SpdyGoAwayIR::Visit(SpdyFrameVisitor
* visitor
) const {
795 return visitor
->VisitGoAway(*this);
798 void SpdyHeadersIR::Visit(SpdyFrameVisitor
* visitor
) const {
799 return visitor
->VisitHeaders(*this);
802 void SpdyWindowUpdateIR::Visit(SpdyFrameVisitor
* visitor
) const {
803 return visitor
->VisitWindowUpdate(*this);
806 void SpdyBlockedIR::Visit(SpdyFrameVisitor
* visitor
) const {
807 return visitor
->VisitBlocked(*this);
810 void SpdyPushPromiseIR::Visit(SpdyFrameVisitor
* visitor
) const {
811 return visitor
->VisitPushPromise(*this);
814 void SpdyContinuationIR::Visit(SpdyFrameVisitor
* visitor
) const {
815 return visitor
->VisitContinuation(*this);
818 SpdyAltSvcIR::SpdyAltSvcIR(SpdyStreamId stream_id
)
819 : SpdyFrameWithStreamIdIR(stream_id
),
823 void SpdyAltSvcIR::Visit(SpdyFrameVisitor
* visitor
) const {
824 return visitor
->VisitAltSvc(*this);
827 SpdyPriorityIR::SpdyPriorityIR(SpdyStreamId stream_id
)
828 : SpdyFrameWithStreamIdIR(stream_id
) {
831 SpdyPriorityIR::SpdyPriorityIR(SpdyStreamId stream_id
,
832 SpdyStreamId parent_stream_id
,
835 : SpdyFrameWithStreamIdIR(stream_id
),
836 parent_stream_id_(parent_stream_id
),
838 exclusive_(exclusive
) {
841 void SpdyPriorityIR::Visit(SpdyFrameVisitor
* visitor
) const {
842 return visitor
->VisitPriority(*this);