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 SpdyFrameWithHeaderBlockIR::SpdyFrameWithHeaderBlockIR(SpdyStreamId stream_id
)
10 : SpdyFrameWithFinIR(stream_id
) {}
12 SpdyFrameWithHeaderBlockIR::~SpdyFrameWithHeaderBlockIR() {}
14 SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id
, base::StringPiece data
)
15 : SpdyFrameWithFinIR(stream_id
), padded_(false), padding_payload_len_(0) {
19 SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id
)
20 : SpdyFrameWithFinIR(stream_id
),
22 padding_payload_len_(0) {}
24 SpdyDataIR::~SpdyDataIR() {}
26 bool SpdyConstants::IsValidFrameType(SpdyMajorVersion version
,
27 int frame_type_field
) {
31 // SYN_STREAM is the first valid frame.
32 if (frame_type_field
< SerializeFrameType(version
, SYN_STREAM
)) {
36 // WINDOW_UPDATE is the last valid frame.
37 if (frame_type_field
> SerializeFrameType(version
, WINDOW_UPDATE
)) {
43 // Check for recognized extensions.
44 if (frame_type_field
== SerializeFrameType(version
, ALTSVC
) ||
45 frame_type_field
== SerializeFrameType(version
, BLOCKED
)) {
49 // DATA is the first valid frame.
50 if (frame_type_field
< SerializeFrameType(version
, DATA
)) {
54 // CONTINUATION is the last valid frame.
55 if (frame_type_field
> SerializeFrameType(version
, CONTINUATION
)) {
62 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
66 SpdyFrameType
SpdyConstants::ParseFrameType(SpdyMajorVersion version
,
67 int frame_type_field
) {
71 switch (frame_type_field
) {
91 switch (frame_type_field
) {
109 return WINDOW_UPDATE
;
120 LOG(DFATAL
) << "Unhandled frame type " << frame_type_field
;
124 int SpdyConstants::SerializeFrameType(SpdyMajorVersion version
,
125 SpdyFrameType frame_type
) {
129 switch (frame_type
) {
147 LOG(DFATAL
) << "Serializing unhandled frame type " << frame_type
;
151 switch (frame_type
) {
172 // ALTSVC and BLOCKED are extensions.
178 LOG(DFATAL
) << "Serializing unhandled frame type " << frame_type
;
183 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
187 int SpdyConstants::DataFrameType(SpdyMajorVersion version
) {
193 return SerializeFrameType(version
, DATA
);
196 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
200 bool SpdyConstants::IsValidSettingId(SpdyMajorVersion version
,
201 int setting_id_field
) {
205 // UPLOAD_BANDWIDTH is the first valid setting id.
206 if (setting_id_field
<
207 SerializeSettingId(version
, SETTINGS_UPLOAD_BANDWIDTH
)) {
211 // INITIAL_WINDOW_SIZE is the last valid setting id.
212 if (setting_id_field
>
213 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 // MAX_HEADER_LIST_SIZE is the last valid setting id.
226 if (setting_id_field
>
227 SerializeSettingId(version
, SETTINGS_MAX_HEADER_LIST_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
;
261 switch (setting_id_field
) {
263 return SETTINGS_HEADER_TABLE_SIZE
;
265 return SETTINGS_ENABLE_PUSH
;
267 return SETTINGS_MAX_CONCURRENT_STREAMS
;
269 return SETTINGS_INITIAL_WINDOW_SIZE
;
271 return SETTINGS_MAX_FRAME_SIZE
;
273 return SETTINGS_MAX_HEADER_LIST_SIZE
;
278 LOG(DFATAL
) << "Unhandled setting ID " << setting_id_field
;
279 return SETTINGS_UPLOAD_BANDWIDTH
;
282 int SpdyConstants::SerializeSettingId(SpdyMajorVersion version
,
283 SpdySettingsIds id
) {
288 case SETTINGS_UPLOAD_BANDWIDTH
:
290 case SETTINGS_DOWNLOAD_BANDWIDTH
:
292 case SETTINGS_ROUND_TRIP_TIME
:
294 case SETTINGS_MAX_CONCURRENT_STREAMS
:
296 case SETTINGS_CURRENT_CWND
:
298 case SETTINGS_DOWNLOAD_RETRANS_RATE
:
300 case SETTINGS_INITIAL_WINDOW_SIZE
:
303 LOG(DFATAL
) << "Serializing unhandled setting id " << id
;
308 case SETTINGS_HEADER_TABLE_SIZE
:
310 case SETTINGS_ENABLE_PUSH
:
312 case SETTINGS_MAX_CONCURRENT_STREAMS
:
314 case SETTINGS_INITIAL_WINDOW_SIZE
:
316 case SETTINGS_MAX_FRAME_SIZE
:
318 case SETTINGS_MAX_HEADER_LIST_SIZE
:
321 LOG(DFATAL
) << "Serializing unhandled setting id " << id
;
325 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
329 bool SpdyConstants::IsValidRstStreamStatus(SpdyMajorVersion version
,
330 int rst_stream_status_field
) {
334 // PROTOCOL_ERROR is the valid first status code.
335 if (rst_stream_status_field
<
336 SerializeRstStreamStatus(version
, RST_STREAM_PROTOCOL_ERROR
)) {
340 // FRAME_TOO_LARGE is the valid last status code.
341 if (rst_stream_status_field
>
342 SerializeRstStreamStatus(version
, RST_STREAM_FRAME_TOO_LARGE
)) {
348 // NO_ERROR is the first valid status code.
349 if (rst_stream_status_field
<
350 SerializeRstStreamStatus(version
, RST_STREAM_PROTOCOL_ERROR
)) {
354 // TODO(hkhalil): Omit COMPRESSION_ERROR and SETTINGS_TIMEOUT
356 // This works because GOAWAY and RST_STREAM share a namespace.
357 if (rst_stream_status_field ==
358 SerializeGoAwayStatus(version, GOAWAY_COMPRESSION_ERROR) ||
359 rst_stream_status_field ==
360 SerializeGoAwayStatus(version, GOAWAY_SETTINGS_TIMEOUT)) {
365 // HTTP_1_1_REQUIRED is the last valid status code.
366 if (rst_stream_status_field
>
367 SerializeRstStreamStatus(version
, RST_STREAM_HTTP_1_1_REQUIRED
)) {
373 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
377 SpdyRstStreamStatus
SpdyConstants::ParseRstStreamStatus(
378 SpdyMajorVersion version
,
379 int rst_stream_status_field
) {
383 switch (rst_stream_status_field
) {
385 return RST_STREAM_PROTOCOL_ERROR
;
387 return RST_STREAM_INVALID_STREAM
;
389 return RST_STREAM_REFUSED_STREAM
;
391 return RST_STREAM_UNSUPPORTED_VERSION
;
393 return RST_STREAM_CANCEL
;
395 return RST_STREAM_INTERNAL_ERROR
;
397 return RST_STREAM_FLOW_CONTROL_ERROR
;
399 return RST_STREAM_STREAM_IN_USE
;
401 return RST_STREAM_STREAM_ALREADY_CLOSED
;
403 return RST_STREAM_INVALID_CREDENTIALS
;
405 return RST_STREAM_FRAME_TOO_LARGE
;
409 switch (rst_stream_status_field
) {
411 return RST_STREAM_PROTOCOL_ERROR
;
413 return RST_STREAM_INTERNAL_ERROR
;
415 return RST_STREAM_FLOW_CONTROL_ERROR
;
417 return RST_STREAM_STREAM_CLOSED
;
419 return RST_STREAM_FRAME_SIZE_ERROR
;
421 return RST_STREAM_REFUSED_STREAM
;
423 return RST_STREAM_CANCEL
;
425 return RST_STREAM_CONNECT_ERROR
;
427 return RST_STREAM_ENHANCE_YOUR_CALM
;
429 return RST_STREAM_INADEQUATE_SECURITY
;
431 return RST_STREAM_HTTP_1_1_REQUIRED
;
436 LOG(DFATAL
) << "Invalid RST_STREAM status " << rst_stream_status_field
;
437 return RST_STREAM_PROTOCOL_ERROR
;
440 int SpdyConstants::SerializeRstStreamStatus(
441 SpdyMajorVersion version
,
442 SpdyRstStreamStatus rst_stream_status
) {
446 switch (rst_stream_status
) {
447 case RST_STREAM_PROTOCOL_ERROR
:
449 case RST_STREAM_INVALID_STREAM
:
451 case RST_STREAM_REFUSED_STREAM
:
453 case RST_STREAM_UNSUPPORTED_VERSION
:
455 case RST_STREAM_CANCEL
:
457 case RST_STREAM_INTERNAL_ERROR
:
459 case RST_STREAM_FLOW_CONTROL_ERROR
:
461 case RST_STREAM_STREAM_IN_USE
:
463 case RST_STREAM_STREAM_ALREADY_CLOSED
:
465 case RST_STREAM_INVALID_CREDENTIALS
:
467 case RST_STREAM_FRAME_TOO_LARGE
:
470 LOG(DFATAL
) << "Unhandled RST_STREAM status "
471 << rst_stream_status
;
475 switch (rst_stream_status
) {
476 case RST_STREAM_PROTOCOL_ERROR
:
478 case RST_STREAM_INTERNAL_ERROR
:
480 case RST_STREAM_FLOW_CONTROL_ERROR
:
482 case RST_STREAM_STREAM_CLOSED
:
484 case RST_STREAM_FRAME_SIZE_ERROR
:
486 case RST_STREAM_REFUSED_STREAM
:
488 case RST_STREAM_CANCEL
:
490 case RST_STREAM_CONNECT_ERROR
:
492 case RST_STREAM_ENHANCE_YOUR_CALM
:
494 case RST_STREAM_INADEQUATE_SECURITY
:
496 case RST_STREAM_HTTP_1_1_REQUIRED
:
499 LOG(DFATAL
) << "Unhandled RST_STREAM status "
500 << rst_stream_status
;
504 LOG(DFATAL
) << "Unhandled SPDY version " << version
;
508 bool SpdyConstants::IsValidGoAwayStatus(SpdyMajorVersion version
,
509 int goaway_status_field
) {
513 // GOAWAY_OK is the first valid status.
514 if (goaway_status_field
< SerializeGoAwayStatus(version
, GOAWAY_OK
)) {
518 // GOAWAY_INTERNAL_ERROR is the last valid status.
519 if (goaway_status_field
> SerializeGoAwayStatus(version
,
520 GOAWAY_INTERNAL_ERROR
)) {
526 // GOAWAY_NO_ERROR is the first valid status.
527 if (goaway_status_field
< SerializeGoAwayStatus(version
,
532 // GOAWAY_HTTP_1_1_REQUIRED is the last valid status.
533 if (goaway_status_field
>
534 SerializeGoAwayStatus(version
, GOAWAY_HTTP_1_1_REQUIRED
)) {
540 LOG(DFATAL
) << "Unknown SpdyMajorVersion " << version
;
544 SpdyGoAwayStatus
SpdyConstants::ParseGoAwayStatus(SpdyMajorVersion version
,
545 int goaway_status_field
) {
549 switch (goaway_status_field
) {
553 return GOAWAY_PROTOCOL_ERROR
;
555 return GOAWAY_INTERNAL_ERROR
;
559 switch (goaway_status_field
) {
561 return GOAWAY_NO_ERROR
;
563 return GOAWAY_PROTOCOL_ERROR
;
565 return GOAWAY_INTERNAL_ERROR
;
567 return GOAWAY_FLOW_CONTROL_ERROR
;
569 return GOAWAY_SETTINGS_TIMEOUT
;
571 return GOAWAY_STREAM_CLOSED
;
573 return GOAWAY_FRAME_SIZE_ERROR
;
575 return GOAWAY_REFUSED_STREAM
;
577 return GOAWAY_CANCEL
;
579 return GOAWAY_COMPRESSION_ERROR
;
581 return GOAWAY_CONNECT_ERROR
;
583 return GOAWAY_ENHANCE_YOUR_CALM
;
585 return GOAWAY_INADEQUATE_SECURITY
;
587 return GOAWAY_HTTP_1_1_REQUIRED
;
592 LOG(DFATAL
) << "Unhandled GOAWAY status " << goaway_status_field
;
593 return GOAWAY_PROTOCOL_ERROR
;
596 SpdyMajorVersion
SpdyConstants::ParseMajorVersion(int version_number
) {
597 switch (version_number
) {
605 LOG(DFATAL
) << "Unsupported SPDY version number: " << version_number
;
610 int SpdyConstants::SerializeMajorVersion(SpdyMajorVersion version
) {
619 LOG(DFATAL
) << "Unsupported SPDY major version: " << version
;
624 std::string
SpdyConstants::GetVersionString(SpdyMajorVersion version
) {
633 LOG(DFATAL
) << "Unsupported SPDY major version: " << version
;
638 int SpdyConstants::SerializeGoAwayStatus(SpdyMajorVersion version
,
639 SpdyGoAwayStatus status
) {
643 // TODO(jgraettinger): Merge this back to server-side.
645 case GOAWAY_NO_ERROR
:
647 case GOAWAY_PROTOCOL_ERROR
:
648 case GOAWAY_INTERNAL_ERROR
:
649 case GOAWAY_FLOW_CONTROL_ERROR
:
650 case GOAWAY_SETTINGS_TIMEOUT
:
651 case GOAWAY_STREAM_CLOSED
:
652 case GOAWAY_FRAME_SIZE_ERROR
:
653 case GOAWAY_REFUSED_STREAM
:
655 case GOAWAY_COMPRESSION_ERROR
:
656 case GOAWAY_CONNECT_ERROR
:
657 case GOAWAY_ENHANCE_YOUR_CALM
:
658 case GOAWAY_INADEQUATE_SECURITY
:
659 case GOAWAY_HTTP_1_1_REQUIRED
:
660 return 1; // PROTOCOL_ERROR.
662 LOG(DFATAL
) << "Serializing unhandled GOAWAY status " << status
;
667 case GOAWAY_NO_ERROR
:
669 case GOAWAY_PROTOCOL_ERROR
:
671 case GOAWAY_INTERNAL_ERROR
:
673 case GOAWAY_FLOW_CONTROL_ERROR
:
675 case GOAWAY_SETTINGS_TIMEOUT
:
677 case GOAWAY_STREAM_CLOSED
:
679 case GOAWAY_FRAME_SIZE_ERROR
:
681 case GOAWAY_REFUSED_STREAM
:
685 case GOAWAY_COMPRESSION_ERROR
:
687 case GOAWAY_CONNECT_ERROR
:
689 case GOAWAY_ENHANCE_YOUR_CALM
:
691 case GOAWAY_INADEQUATE_SECURITY
:
693 case GOAWAY_HTTP_1_1_REQUIRED
:
696 LOG(DFATAL
) << "Serializing unhandled GOAWAY status " << status
;
700 LOG(DFATAL
) << "Unknown SpdyMajorVersion " << version
;
704 size_t SpdyConstants::GetDataFrameMinimumSize(SpdyMajorVersion version
) {
712 LOG(DFATAL
) << "Unhandled SPDY version.";
716 size_t SpdyConstants::GetControlFrameHeaderSize(SpdyMajorVersion version
) {
724 LOG(DFATAL
) << "Unhandled SPDY version.";
728 size_t SpdyConstants::GetPrefixLength(SpdyFrameType type
,
729 SpdyMajorVersion version
) {
731 return GetControlFrameHeaderSize(version
);
733 return GetDataFrameMinimumSize(version
);
737 size_t SpdyConstants::GetFrameMaximumSize(SpdyMajorVersion version
) {
738 if (version
< HTTP2
) {
739 // 24-bit length field plus eight-byte frame header.
740 return ((1<<24) - 1) + 8;
742 // Max payload of 2^14 plus nine-byte frame header.
743 // TODO(mlavan): In HTTP/2 this is actually not a constant;
744 // payload size can be set using the MAX_FRAME_SIZE setting to
745 // anything between 1 << 14 and (1 << 24) - 1
746 return (1 << 14) + 9;
750 size_t SpdyConstants::GetSizeOfSizeField(SpdyMajorVersion version
) {
751 return (version
< SPDY3
) ? sizeof(uint16
) : sizeof(uint32
);
754 size_t SpdyConstants::GetSettingSize(SpdyMajorVersion version
) {
755 return version
<= SPDY3
? 8 : 6;
758 int32
SpdyConstants::GetInitialStreamWindowSize(SpdyMajorVersion version
) {
759 return (version
<= SPDY3
) ? (64 * 1024) : (64 * 1024 - 1);
762 int32
SpdyConstants::GetInitialSessionWindowSize(SpdyMajorVersion version
) {
763 return (version
<= SPDY3
) ? (64 * 1024) : (64 * 1024 - 1);
766 void SpdyDataIR::Visit(SpdyFrameVisitor
* visitor
) const {
767 return visitor
->VisitData(*this);
770 void SpdySynStreamIR::Visit(SpdyFrameVisitor
* visitor
) const {
771 return visitor
->VisitSynStream(*this);
774 void SpdySynReplyIR::Visit(SpdyFrameVisitor
* visitor
) const {
775 return visitor
->VisitSynReply(*this);
778 SpdyRstStreamIR::SpdyRstStreamIR(SpdyStreamId stream_id
,
779 SpdyRstStreamStatus status
,
780 base::StringPiece description
)
781 : SpdyFrameWithStreamIdIR(stream_id
),
782 description_(description
) {
786 SpdyRstStreamIR::~SpdyRstStreamIR() {}
788 void SpdyRstStreamIR::Visit(SpdyFrameVisitor
* visitor
) const {
789 return visitor
->VisitRstStream(*this);
792 SpdySettingsIR::SpdySettingsIR()
793 : clear_settings_(false),
796 SpdySettingsIR::~SpdySettingsIR() {}
798 void SpdySettingsIR::Visit(SpdyFrameVisitor
* visitor
) const {
799 return visitor
->VisitSettings(*this);
802 void SpdyPingIR::Visit(SpdyFrameVisitor
* visitor
) const {
803 return visitor
->VisitPing(*this);
806 SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id
,
807 SpdyGoAwayStatus status
,
808 base::StringPiece description
)
809 : description_(description
) {
810 set_last_good_stream_id(last_good_stream_id
);
814 SpdyGoAwayIR::~SpdyGoAwayIR() {}
816 const base::StringPiece
& SpdyGoAwayIR::description() const {
820 void SpdyGoAwayIR::Visit(SpdyFrameVisitor
* visitor
) const {
821 return visitor
->VisitGoAway(*this);
824 void SpdyHeadersIR::Visit(SpdyFrameVisitor
* visitor
) const {
825 return visitor
->VisitHeaders(*this);
828 void SpdyWindowUpdateIR::Visit(SpdyFrameVisitor
* visitor
) const {
829 return visitor
->VisitWindowUpdate(*this);
832 void SpdyBlockedIR::Visit(SpdyFrameVisitor
* visitor
) const {
833 return visitor
->VisitBlocked(*this);
836 void SpdyPushPromiseIR::Visit(SpdyFrameVisitor
* visitor
) const {
837 return visitor
->VisitPushPromise(*this);
840 void SpdyContinuationIR::Visit(SpdyFrameVisitor
* visitor
) const {
841 return visitor
->VisitContinuation(*this);
844 SpdyAltSvcIR::SpdyAltSvcIR(SpdyStreamId stream_id
)
845 : SpdyFrameWithStreamIdIR(stream_id
) {
848 SpdyAltSvcIR::~SpdyAltSvcIR() {
851 void SpdyAltSvcIR::Visit(SpdyFrameVisitor
* visitor
) const {
852 return visitor
->VisitAltSvc(*this);
855 void SpdyPriorityIR::Visit(SpdyFrameVisitor
* visitor
) const {
856 return visitor
->VisitPriority(*this);