SpdyFrameWithNameValueBlockIR::~SpdyFrameWithNameValueBlockIR() {}
SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, const base::StringPiece& data)
- : SpdyFrameWithFinIR(stream_id) {
+ : SpdyFrameWithFinIR(stream_id),
+ pad_low_(false),
+ pad_high_(false),
+ padding_payload_len_(0) {
SetDataDeep(data);
}
SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id)
- : SpdyFrameWithFinIR(stream_id) {}
+ : SpdyFrameWithFinIR(stream_id),
+ pad_low_(false),
+ pad_high_(false),
+ padding_payload_len_(0) {}
SpdyDataIR::~SpdyDataIR() {}
+bool SpdyConstants::IsValidFrameType(SpdyMajorVersion version,
+ int frame_type_field) {
+ switch (version) {
+ case SPDY2:
+ case SPDY3:
+ // SYN_STREAM is the first valid frame.
+ if (frame_type_field < SerializeFrameType(version, SYN_STREAM)) {
+ return false;
+ }
+
+ // WINDOW_UPDATE is the last valid frame.
+ if (frame_type_field > SerializeFrameType(version, WINDOW_UPDATE)) {
+ return false;
+ }
+
+ // The valid range is non-contiguous.
+ if (frame_type_field == NOOP) {
+ return false;
+ }
+
+ return true;
+ case SPDY4:
+ case SPDY5:
+ // DATA is the first valid frame.
+ if (frame_type_field < SerializeFrameType(version, DATA)) {
+ return false;
+ }
+
+ // BLOCKED is the last valid frame.
+ if (frame_type_field > SerializeFrameType(version, BLOCKED)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ LOG(DFATAL) << "Unhandled SPDY version " << version;
+ return false;
+}
+
+SpdyFrameType SpdyConstants::ParseFrameType(SpdyMajorVersion version,
+ int frame_type_field) {
+ switch (version) {
+ case SPDY2:
+ case SPDY3:
+ switch (frame_type_field) {
+ case 1:
+ return SYN_STREAM;
+ case 2:
+ return SYN_REPLY;
+ case 3:
+ return RST_STREAM;
+ case 4:
+ return SETTINGS;
+ case 6:
+ return PING;
+ case 7:
+ return GOAWAY;
+ case 8:
+ return HEADERS;
+ case 9:
+ return WINDOW_UPDATE;
+ }
+ break;
+ case SPDY4:
+ case SPDY5:
+ switch (frame_type_field) {
+ case 0:
+ return DATA;
+ case 1:
+ return HEADERS;
+ // TODO(hkhalil): Add PRIORITY.
+ case 3:
+ return RST_STREAM;
+ case 4:
+ return SETTINGS;
+ case 5:
+ return PUSH_PROMISE;
+ case 6:
+ return PING;
+ case 7:
+ return GOAWAY;
+ case 8:
+ return WINDOW_UPDATE;
+ case 9:
+ return CONTINUATION;
+ case 10:
+ return BLOCKED;
+ }
+ break;
+ }
+
+ LOG(DFATAL) << "Unhandled frame type " << frame_type_field;
+ return DATA;
+}
+
+int SpdyConstants::SerializeFrameType(SpdyMajorVersion version,
+ SpdyFrameType frame_type) {
+ switch (version) {
+ case SPDY2:
+ case SPDY3:
+ switch (frame_type) {
+ case SYN_STREAM:
+ return 1;
+ case SYN_REPLY:
+ return 2;
+ case RST_STREAM:
+ return 3;
+ case SETTINGS:
+ return 4;
+ case PING:
+ return 6;
+ case GOAWAY:
+ return 7;
+ case HEADERS:
+ return 8;
+ case WINDOW_UPDATE:
+ return 9;
+ default:
+ LOG(DFATAL) << "Serializing unhandled frame type " << frame_type;
+ return -1;
+ }
+ case SPDY4:
+ case SPDY5:
+ switch (frame_type) {
+ case DATA:
+ return 0;
+ case HEADERS:
+ return 1;
+ // TODO(hkhalil): Add PRIORITY.
+ case RST_STREAM:
+ return 3;
+ case SETTINGS:
+ return 4;
+ case PUSH_PROMISE:
+ return 5;
+ case PING:
+ return 6;
+ case GOAWAY:
+ return 7;
+ case WINDOW_UPDATE:
+ return 8;
+ case CONTINUATION:
+ return 9;
+ case BLOCKED:
+ return 10;
+ default:
+ LOG(DFATAL) << "Serializing unhandled frame type " << frame_type;
+ return -1;
+ }
+ }
+
+ LOG(DFATAL) << "Unhandled SPDY version " << version;
+ return -1;
+}
+
+bool SpdyConstants::IsValidSettingId(SpdyMajorVersion version,
+ int setting_id_field) {
+ switch (version) {
+ case SPDY2:
+ case SPDY3:
+ // UPLOAD_BANDWIDTH is the first valid setting id.
+ if (setting_id_field <
+ SerializeSettingId(version, SETTINGS_UPLOAD_BANDWIDTH)) {
+ return false;
+ }
+
+ // INITIAL_WINDOW_SIZE is the last valid setting id.
+ if (setting_id_field >
+ SerializeSettingId(version, SETTINGS_INITIAL_WINDOW_SIZE)) {
+ return false;
+ }
+
+ return true;
+ case SPDY4:
+ case SPDY5:
+ // HEADER_TABLE_SIZE is the first valid setting id.
+ if (setting_id_field <
+ SerializeSettingId(version, SETTINGS_HEADER_TABLE_SIZE)) {
+ return false;
+ }
+
+ // INITIAL_WINDOW_SIZE is the last valid setting id.
+ if (setting_id_field >
+ SerializeSettingId(version, SETTINGS_INITIAL_WINDOW_SIZE)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ LOG(DFATAL) << "Unhandled SPDY version " << version;
+ return false;
+}
+
+SpdySettingsIds SpdyConstants::ParseSettingId(SpdyMajorVersion version,
+ int setting_id_field) {
+ switch (version) {
+ case SPDY2:
+ case SPDY3:
+ switch (setting_id_field) {
+ case 1:
+ return SETTINGS_UPLOAD_BANDWIDTH;
+ case 2:
+ return SETTINGS_DOWNLOAD_BANDWIDTH;
+ case 3:
+ return SETTINGS_ROUND_TRIP_TIME;
+ case 4:
+ return SETTINGS_MAX_CONCURRENT_STREAMS;
+ case 5:
+ return SETTINGS_CURRENT_CWND;
+ case 6:
+ return SETTINGS_DOWNLOAD_RETRANS_RATE;
+ case 7:
+ return SETTINGS_INITIAL_WINDOW_SIZE;
+ }
+ break;
+ case SPDY4:
+ case SPDY5:
+ switch (setting_id_field) {
+ case 1:
+ return SETTINGS_HEADER_TABLE_SIZE;
+ case 2:
+ return SETTINGS_ENABLE_PUSH;
+ case 3:
+ return SETTINGS_MAX_CONCURRENT_STREAMS;
+ case 4:
+ return SETTINGS_INITIAL_WINDOW_SIZE;
+ }
+ break;
+ }
+
+ LOG(DFATAL) << "Unhandled setting ID " << setting_id_field;
+ return SETTINGS_UPLOAD_BANDWIDTH;
+}
+
+int SpdyConstants::SerializeSettingId(SpdyMajorVersion version,
+ SpdySettingsIds id) {
+ switch (version) {
+ case SPDY2:
+ case SPDY3:
+ switch (id) {
+ case SETTINGS_UPLOAD_BANDWIDTH:
+ return 1;
+ case SETTINGS_DOWNLOAD_BANDWIDTH:
+ return 2;
+ case SETTINGS_ROUND_TRIP_TIME:
+ return 3;
+ case SETTINGS_MAX_CONCURRENT_STREAMS:
+ return 4;
+ case SETTINGS_CURRENT_CWND:
+ return 5;
+ case SETTINGS_DOWNLOAD_RETRANS_RATE:
+ return 6;
+ case SETTINGS_INITIAL_WINDOW_SIZE:
+ return 7;
+ default:
+ LOG(DFATAL) << "Serializing unhandled setting id " << id;
+ return -1;
+ }
+ case SPDY4:
+ case SPDY5:
+ switch (id) {
+ case SETTINGS_HEADER_TABLE_SIZE:
+ return 1;
+ case SETTINGS_ENABLE_PUSH:
+ return 2;
+ case SETTINGS_MAX_CONCURRENT_STREAMS:
+ return 3;
+ case SETTINGS_INITIAL_WINDOW_SIZE:
+ return 4;
+ default:
+ LOG(DFATAL) << "Serializing unhandled setting id " << id;
+ return -1;
+ }
+ }
+ LOG(DFATAL) << "Unhandled SPDY version " << version;
+ return -1;
+}
+
+bool SpdyConstants::IsValidRstStreamStatus(SpdyMajorVersion version,
+ int rst_stream_status_field) {
+ switch (version) {
+ case SPDY2:
+ case SPDY3:
+ // PROTOCOL_ERROR is the valid first status code.
+ if (rst_stream_status_field <
+ SerializeRstStreamStatus(version, RST_STREAM_PROTOCOL_ERROR)) {
+ return false;
+ }
+
+ // FRAME_TOO_LARGE is the valid last status code.
+ if (rst_stream_status_field >
+ SerializeRstStreamStatus(version, RST_STREAM_FRAME_TOO_LARGE)) {
+ return false;
+ }
+
+ return true;
+ case SPDY4:
+ case SPDY5:
+ // NO_ERROR is the first valid status code.
+ if (rst_stream_status_field <
+ SerializeRstStreamStatus(version, RST_STREAM_PROTOCOL_ERROR)) {
+ return false;
+ }
+
+ // TODO(hkhalil): Omit COMPRESSION_ERROR and SETTINGS_TIMEOUT
+ /*
+ // This works because GOAWAY and RST_STREAM share a namespace.
+ if (rst_stream_status_field ==
+ SerializeGoAwayStatus(version, GOAWAY_COMPRESSION_ERROR) ||
+ rst_stream_status_field ==
+ SerializeGoAwayStatus(version, GOAWAY_SETTINGS_TIMEOUT)) {
+ return false;
+ }
+ */
+
+ // ENHANCE_YOUR_CALM is the last valid status code.
+ if (rst_stream_status_field >
+ SerializeRstStreamStatus(version, RST_STREAM_ENHANCE_YOUR_CALM)) {
+ return false;
+ }
+
+ return true;
+ }
+ LOG(DFATAL) << "Unhandled SPDY version " << version;
+ return false;
+}
+
+SpdyRstStreamStatus SpdyConstants::ParseRstStreamStatus(
+ SpdyMajorVersion version,
+ int rst_stream_status_field) {
+ switch (version) {
+ case SPDY2:
+ case SPDY3:
+ switch (rst_stream_status_field) {
+ case 1:
+ return RST_STREAM_PROTOCOL_ERROR;
+ case 2:
+ return RST_STREAM_INVALID_STREAM;
+ case 3:
+ return RST_STREAM_REFUSED_STREAM;
+ case 4:
+ return RST_STREAM_UNSUPPORTED_VERSION;
+ case 5:
+ return RST_STREAM_CANCEL;
+ case 6:
+ return RST_STREAM_INTERNAL_ERROR;
+ case 7:
+ return RST_STREAM_FLOW_CONTROL_ERROR;
+ case 8:
+ return RST_STREAM_STREAM_IN_USE;
+ case 9:
+ return RST_STREAM_STREAM_ALREADY_CLOSED;
+ case 10:
+ return RST_STREAM_INVALID_CREDENTIALS;
+ case 11:
+ return RST_STREAM_FRAME_TOO_LARGE;
+ }
+ break;
+ case SPDY4:
+ case SPDY5:
+ switch (rst_stream_status_field) {
+ case 1:
+ return RST_STREAM_PROTOCOL_ERROR;
+ case 2:
+ return RST_STREAM_INTERNAL_ERROR;
+ case 3:
+ return RST_STREAM_FLOW_CONTROL_ERROR;
+ case 5:
+ return RST_STREAM_STREAM_CLOSED;
+ case 6:
+ return RST_STREAM_FRAME_SIZE_ERROR;
+ case 7:
+ return RST_STREAM_REFUSED_STREAM;
+ case 8:
+ return RST_STREAM_CANCEL;
+ case 10:
+ return RST_STREAM_CONNECT_ERROR;
+ case 11:
+ return RST_STREAM_ENHANCE_YOUR_CALM;
+ }
+ break;
+ }
+
+ LOG(DFATAL) << "Invalid RST_STREAM status " << rst_stream_status_field;
+ return RST_STREAM_PROTOCOL_ERROR;
+}
+
+int SpdyConstants::SerializeRstStreamStatus(
+ SpdyMajorVersion version,
+ SpdyRstStreamStatus rst_stream_status) {
+ switch (version) {
+ case SPDY2:
+ case SPDY3:
+ switch (rst_stream_status) {
+ case RST_STREAM_PROTOCOL_ERROR:
+ return 1;
+ case RST_STREAM_INVALID_STREAM:
+ return 2;
+ case RST_STREAM_REFUSED_STREAM:
+ return 3;
+ case RST_STREAM_UNSUPPORTED_VERSION:
+ return 4;
+ case RST_STREAM_CANCEL:
+ return 5;
+ case RST_STREAM_INTERNAL_ERROR:
+ return 6;
+ case RST_STREAM_FLOW_CONTROL_ERROR:
+ return 7;
+ case RST_STREAM_STREAM_IN_USE:
+ return 8;
+ case RST_STREAM_STREAM_ALREADY_CLOSED:
+ return 9;
+ case RST_STREAM_INVALID_CREDENTIALS:
+ return 10;
+ case RST_STREAM_FRAME_TOO_LARGE:
+ return 11;
+ default:
+ LOG(DFATAL) << "Unhandled RST_STREAM status "
+ << rst_stream_status;
+ return -1;
+ }
+ case SPDY4:
+ case SPDY5:
+ switch (rst_stream_status) {
+ case RST_STREAM_PROTOCOL_ERROR:
+ return 1;
+ case RST_STREAM_INTERNAL_ERROR:
+ return 2;
+ case RST_STREAM_FLOW_CONTROL_ERROR:
+ return 3;
+ case RST_STREAM_STREAM_CLOSED:
+ return 5;
+ case RST_STREAM_FRAME_SIZE_ERROR:
+ return 6;
+ case RST_STREAM_REFUSED_STREAM:
+ return 7;
+ case RST_STREAM_CANCEL:
+ return 8;
+ case RST_STREAM_CONNECT_ERROR:
+ return 10;
+ case RST_STREAM_ENHANCE_YOUR_CALM:
+ return 11;
+ default:
+ LOG(DFATAL) << "Unhandled RST_STREAM status "
+ << rst_stream_status;
+ return -1;
+ }
+ }
+ LOG(DFATAL) << "Unhandled SPDY version " << version;
+ return -1;
+}
+
+bool SpdyConstants::IsValidGoAwayStatus(SpdyMajorVersion version,
+ int goaway_status_field) {
+ switch (version) {
+ case SPDY2:
+ case SPDY3:
+ // GOAWAY_OK is the first valid status.
+ if (goaway_status_field < SerializeGoAwayStatus(version, GOAWAY_OK)) {
+ return false;
+ }
+
+ // GOAWAY_INTERNAL_ERROR is the last valid status.
+ if (goaway_status_field > SerializeGoAwayStatus(version,
+ GOAWAY_INTERNAL_ERROR)) {
+ return false;
+ }
+
+ return true;
+ case SPDY4:
+ case SPDY5:
+ // GOAWAY_NO_ERROR is the first valid status.
+ if (goaway_status_field < SerializeGoAwayStatus(version,
+ GOAWAY_NO_ERROR)) {
+ return false;
+ }
+
+ // GOAWAY_INADEQUATE_SECURITY is the last valid status.
+ if (goaway_status_field >
+ SerializeGoAwayStatus(version, GOAWAY_INADEQUATE_SECURITY)) {
+ return false;
+ }
+
+ return true;
+ }
+ LOG(DFATAL) << "Unknown SpdyMajorVersion " << version;
+ return false;
+}
+
+SpdyGoAwayStatus SpdyConstants::ParseGoAwayStatus(SpdyMajorVersion version,
+ int goaway_status_field) {
+ switch (version) {
+ case SPDY2:
+ case SPDY3:
+ switch (goaway_status_field) {
+ case 0:
+ return GOAWAY_OK;
+ case 1:
+ return GOAWAY_PROTOCOL_ERROR;
+ case 2:
+ return GOAWAY_INTERNAL_ERROR;
+ }
+ break;
+ case SPDY4:
+ case SPDY5:
+ switch (goaway_status_field) {
+ case 0:
+ return GOAWAY_NO_ERROR;
+ case 1:
+ return GOAWAY_PROTOCOL_ERROR;
+ case 2:
+ return GOAWAY_INTERNAL_ERROR;
+ case 3:
+ return GOAWAY_FLOW_CONTROL_ERROR;
+ case 4:
+ return GOAWAY_SETTINGS_TIMEOUT;
+ case 5:
+ return GOAWAY_STREAM_CLOSED;
+ case 6:
+ return GOAWAY_FRAME_SIZE_ERROR;
+ case 7:
+ return GOAWAY_REFUSED_STREAM;
+ case 8:
+ return GOAWAY_CANCEL;
+ case 9:
+ return GOAWAY_COMPRESSION_ERROR;
+ case 10:
+ return GOAWAY_CONNECT_ERROR;
+ case 11:
+ return GOAWAY_ENHANCE_YOUR_CALM;
+ case 12:
+ return GOAWAY_INADEQUATE_SECURITY;
+ }
+ break;
+ }
+
+ LOG(DFATAL) << "Unhandled GOAWAY status " << goaway_status_field;
+ return GOAWAY_PROTOCOL_ERROR;
+}
+
+SpdyMajorVersion SpdyConstants::ParseMajorVersion(int version_number) {
+ switch (version_number) {
+ case 2:
+ return SPDY2;
+ case 3:
+ return SPDY3;
+ case 4:
+ return SPDY4;
+ case 5:
+ return SPDY5;
+ default:
+ LOG(DFATAL) << "Unsupported SPDY version number: " << version_number;
+ return SPDY3;
+ }
+}
+
+int SpdyConstants::SerializeMajorVersion(SpdyMajorVersion version) {
+ switch (version) {
+ case SPDY2:
+ return 2;
+ case SPDY3:
+ return 3;
+ case SPDY4:
+ return 4;
+ case SPDY5:
+ return 5;
+ default:
+ LOG(DFATAL) << "Unsupported SPDY major version: " << version;
+ return -1;
+ }
+}
+
+std::string SpdyConstants::GetVersionString(SpdyMajorVersion version) {
+ switch (version) {
+ case SPDY2:
+ return "spdy/2";
+ case SPDY3:
+ return "spdy/3";
+ case SPDY4:
+ return "spdy/4";
+ case SPDY5:
+ return "spdy/5";
+ default:
+ LOG(DFATAL) << "Unsupported SPDY major version: " << version;
+ return "spdy/3";
+ }
+}
+
+int SpdyConstants::SerializeGoAwayStatus(SpdyMajorVersion version,
+ SpdyGoAwayStatus status) {
+ switch (version) {
+ case SPDY2:
+ case SPDY3:
+ switch (status) {
+ case GOAWAY_OK:
+ return 0;
+ case GOAWAY_PROTOCOL_ERROR:
+ return 1;
+ case GOAWAY_INTERNAL_ERROR:
+ return 2;
+ default:
+ LOG(DFATAL) << "Serializing unhandled GOAWAY status " << status;
+ return -1;
+ }
+ case SPDY4:
+ case SPDY5:
+ switch (status) {
+ case GOAWAY_NO_ERROR:
+ return 0;
+ case GOAWAY_PROTOCOL_ERROR:
+ return 1;
+ case GOAWAY_INTERNAL_ERROR:
+ return 2;
+ case GOAWAY_FLOW_CONTROL_ERROR:
+ return 3;
+ case GOAWAY_SETTINGS_TIMEOUT:
+ return 4;
+ case GOAWAY_STREAM_CLOSED:
+ return 5;
+ case GOAWAY_FRAME_SIZE_ERROR:
+ return 6;
+ case GOAWAY_REFUSED_STREAM:
+ return 7;
+ case GOAWAY_CANCEL:
+ return 8;
+ case GOAWAY_COMPRESSION_ERROR:
+ return 9;
+ case GOAWAY_CONNECT_ERROR:
+ return 10;
+ case GOAWAY_ENHANCE_YOUR_CALM:
+ return 11;
+ case GOAWAY_INADEQUATE_SECURITY:
+ return 12;
+ default:
+ LOG(DFATAL) << "Serializing unhandled GOAWAY status " << status;
+ return -1;
+ }
+ }
+ LOG(DFATAL) << "Unknown SpdyMajorVersion " << version;
+ return -1;
+}
+
+size_t SpdyConstants::GetDataFrameMinimumSize() {
+ return 8;
+}
+
+size_t SpdyConstants::GetControlFrameHeaderSize(SpdyMajorVersion version) {
+ switch (version) {
+ case SPDY2:
+ case SPDY3:
+ case SPDY4:
+ case SPDY5:
+ return 8;
+ }
+ LOG(DFATAL) << "Unhandled SPDY version.";
+ return 0;
+}
+
+size_t SpdyConstants::GetPrefixLength(SpdyFrameType type,
+ SpdyMajorVersion version) {
+ if (type != DATA) {
+ return GetControlFrameHeaderSize(version);
+ } else {
+ return GetDataFrameMinimumSize();
+ }
+}
+
+size_t SpdyConstants::GetFrameMaximumSize(SpdyMajorVersion version) {
+ if (version < SPDY4) {
+ // 24-bit length field plus eight-byte frame header.
+ return ((1<<24) - 1) + 8;
+ } else {
+ // 14-bit length field.
+ return (1<<14) - 1;
+ }
+}
+
void SpdyDataIR::Visit(SpdyFrameVisitor* visitor) const {
return visitor->VisitData(*this);
}