QUICHE team | c9b2cec | 2019-01-07 17:54:15 -0500 | [diff] [blame] | 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. |
| 4 | |
| 5 | #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" |
| 6 | |
| 7 | #include <ostream> |
| 8 | |
QUICHE team | dc5ce1a | 2019-01-30 16:01:47 -0500 | [diff] [blame] | 9 | #include "net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h" |
QUICHE team | c9b2cec | 2019-01-07 17:54:15 -0500 | [diff] [blame] | 10 | #include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h" |
| 11 | #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h" |
| 12 | |
| 13 | namespace spdy { |
| 14 | |
| 15 | const char* const kHttp2ConnectionHeaderPrefix = |
| 16 | "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"; |
| 17 | |
| 18 | std::ostream& operator<<(std::ostream& out, SpdyKnownSettingsId id) { |
| 19 | return out << static_cast<SpdySettingsId>(id); |
| 20 | } |
| 21 | |
| 22 | std::ostream& operator<<(std::ostream& out, SpdyFrameType frame_type) { |
| 23 | return out << SerializeFrameType(frame_type); |
| 24 | } |
| 25 | |
| 26 | SpdyPriority ClampSpdy3Priority(SpdyPriority priority) { |
| 27 | if (priority < kV3HighestPriority) { |
| 28 | SPDY_BUG << "Invalid priority: " << static_cast<int>(priority); |
| 29 | return kV3HighestPriority; |
| 30 | } |
| 31 | if (priority > kV3LowestPriority) { |
| 32 | SPDY_BUG << "Invalid priority: " << static_cast<int>(priority); |
| 33 | return kV3LowestPriority; |
| 34 | } |
| 35 | return priority; |
| 36 | } |
| 37 | |
| 38 | int ClampHttp2Weight(int weight) { |
| 39 | if (weight < kHttp2MinStreamWeight) { |
| 40 | SPDY_BUG << "Invalid weight: " << weight; |
| 41 | return kHttp2MinStreamWeight; |
| 42 | } |
| 43 | if (weight > kHttp2MaxStreamWeight) { |
| 44 | SPDY_BUG << "Invalid weight: " << weight; |
| 45 | return kHttp2MaxStreamWeight; |
| 46 | } |
| 47 | return weight; |
| 48 | } |
| 49 | |
| 50 | int Spdy3PriorityToHttp2Weight(SpdyPriority priority) { |
| 51 | priority = ClampSpdy3Priority(priority); |
| 52 | const float kSteps = 255.9f / 7.f; |
| 53 | return static_cast<int>(kSteps * (7.f - priority)) + 1; |
| 54 | } |
| 55 | |
| 56 | SpdyPriority Http2WeightToSpdy3Priority(int weight) { |
| 57 | weight = ClampHttp2Weight(weight); |
| 58 | const float kSteps = 255.9f / 7.f; |
| 59 | return static_cast<SpdyPriority>(7.f - (weight - 1) / kSteps); |
| 60 | } |
| 61 | |
| 62 | bool IsDefinedFrameType(uint8_t frame_type_field) { |
| 63 | return frame_type_field <= SerializeFrameType(SpdyFrameType::MAX_FRAME_TYPE); |
| 64 | } |
| 65 | |
| 66 | SpdyFrameType ParseFrameType(uint8_t frame_type_field) { |
| 67 | SPDY_BUG_IF(!IsDefinedFrameType(frame_type_field)) |
| 68 | << "Frame type not defined: " << static_cast<int>(frame_type_field); |
| 69 | return static_cast<SpdyFrameType>(frame_type_field); |
| 70 | } |
| 71 | |
| 72 | uint8_t SerializeFrameType(SpdyFrameType frame_type) { |
| 73 | return static_cast<uint8_t>(frame_type); |
| 74 | } |
| 75 | |
| 76 | bool IsValidHTTP2FrameStreamId(SpdyStreamId current_frame_stream_id, |
| 77 | SpdyFrameType frame_type_field) { |
| 78 | if (current_frame_stream_id == 0) { |
| 79 | switch (frame_type_field) { |
| 80 | case SpdyFrameType::DATA: |
| 81 | case SpdyFrameType::HEADERS: |
| 82 | case SpdyFrameType::PRIORITY: |
| 83 | case SpdyFrameType::RST_STREAM: |
| 84 | case SpdyFrameType::CONTINUATION: |
| 85 | case SpdyFrameType::PUSH_PROMISE: |
| 86 | // These frame types must specify a stream |
| 87 | return false; |
| 88 | default: |
| 89 | return true; |
| 90 | } |
| 91 | } else { |
| 92 | switch (frame_type_field) { |
| 93 | case SpdyFrameType::GOAWAY: |
| 94 | case SpdyFrameType::SETTINGS: |
| 95 | case SpdyFrameType::PING: |
| 96 | // These frame types must not specify a stream |
| 97 | return false; |
| 98 | default: |
| 99 | return true; |
| 100 | } |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | const char* FrameTypeToString(SpdyFrameType frame_type) { |
| 105 | switch (frame_type) { |
| 106 | case SpdyFrameType::DATA: |
| 107 | return "DATA"; |
| 108 | case SpdyFrameType::RST_STREAM: |
| 109 | return "RST_STREAM"; |
| 110 | case SpdyFrameType::SETTINGS: |
| 111 | return "SETTINGS"; |
| 112 | case SpdyFrameType::PING: |
| 113 | return "PING"; |
| 114 | case SpdyFrameType::GOAWAY: |
| 115 | return "GOAWAY"; |
| 116 | case SpdyFrameType::HEADERS: |
| 117 | return "HEADERS"; |
| 118 | case SpdyFrameType::WINDOW_UPDATE: |
| 119 | return "WINDOW_UPDATE"; |
| 120 | case SpdyFrameType::PUSH_PROMISE: |
| 121 | return "PUSH_PROMISE"; |
| 122 | case SpdyFrameType::CONTINUATION: |
| 123 | return "CONTINUATION"; |
| 124 | case SpdyFrameType::PRIORITY: |
| 125 | return "PRIORITY"; |
| 126 | case SpdyFrameType::ALTSVC: |
| 127 | return "ALTSVC"; |
| 128 | case SpdyFrameType::EXTENSION: |
| 129 | return "EXTENSION (unspecified)"; |
| 130 | } |
| 131 | return "UNKNOWN_FRAME_TYPE"; |
| 132 | } |
| 133 | |
| 134 | bool ParseSettingsId(SpdySettingsId wire_setting_id, |
| 135 | SpdyKnownSettingsId* setting_id) { |
| 136 | if (wire_setting_id != SETTINGS_EXPERIMENT_SCHEDULER && |
| 137 | (wire_setting_id < SETTINGS_MIN || wire_setting_id > SETTINGS_MAX)) { |
| 138 | return false; |
| 139 | } |
| 140 | |
| 141 | *setting_id = static_cast<SpdyKnownSettingsId>(wire_setting_id); |
| 142 | // This switch ensures that the casted value is valid. The default case is |
| 143 | // explicitly omitted to have compile-time guarantees that new additions to |
| 144 | // |SpdyKnownSettingsId| must also be handled here. |
| 145 | switch (*setting_id) { |
| 146 | case SETTINGS_HEADER_TABLE_SIZE: |
| 147 | case SETTINGS_ENABLE_PUSH: |
| 148 | case SETTINGS_MAX_CONCURRENT_STREAMS: |
| 149 | case SETTINGS_INITIAL_WINDOW_SIZE: |
| 150 | case SETTINGS_MAX_FRAME_SIZE: |
| 151 | case SETTINGS_MAX_HEADER_LIST_SIZE: |
| 152 | case SETTINGS_ENABLE_CONNECT_PROTOCOL: |
| 153 | case SETTINGS_EXPERIMENT_SCHEDULER: |
| 154 | // FALLTHROUGH_INTENDED |
| 155 | return true; |
| 156 | } |
| 157 | return false; |
| 158 | } |
| 159 | |
| 160 | SpdyString SettingsIdToString(SpdySettingsId id) { |
| 161 | SpdyKnownSettingsId known_id; |
| 162 | if (!ParseSettingsId(id, &known_id)) { |
| 163 | return SpdyStrCat("SETTINGS_UNKNOWN_", |
| 164 | SpdyHexEncodeUInt32AndTrim(uint32_t{id})); |
| 165 | } |
| 166 | |
| 167 | switch (known_id) { |
| 168 | case SETTINGS_HEADER_TABLE_SIZE: |
| 169 | return "SETTINGS_HEADER_TABLE_SIZE"; |
| 170 | case SETTINGS_ENABLE_PUSH: |
| 171 | return "SETTINGS_ENABLE_PUSH"; |
| 172 | case SETTINGS_MAX_CONCURRENT_STREAMS: |
| 173 | return "SETTINGS_MAX_CONCURRENT_STREAMS"; |
| 174 | case SETTINGS_INITIAL_WINDOW_SIZE: |
| 175 | return "SETTINGS_INITIAL_WINDOW_SIZE"; |
| 176 | case SETTINGS_MAX_FRAME_SIZE: |
| 177 | return "SETTINGS_MAX_FRAME_SIZE"; |
| 178 | case SETTINGS_MAX_HEADER_LIST_SIZE: |
| 179 | return "SETTINGS_MAX_HEADER_LIST_SIZE"; |
| 180 | case SETTINGS_ENABLE_CONNECT_PROTOCOL: |
| 181 | return "SETTINGS_ENABLE_CONNECT_PROTOCOL"; |
| 182 | case SETTINGS_EXPERIMENT_SCHEDULER: |
| 183 | return "SETTINGS_EXPERIMENT_SCHEDULER"; |
| 184 | } |
| 185 | |
| 186 | return SpdyStrCat("SETTINGS_UNKNOWN_", |
| 187 | SpdyHexEncodeUInt32AndTrim(uint32_t{id})); |
| 188 | } |
| 189 | |
| 190 | SpdyErrorCode ParseErrorCode(uint32_t wire_error_code) { |
| 191 | if (wire_error_code > ERROR_CODE_MAX) { |
| 192 | return ERROR_CODE_INTERNAL_ERROR; |
| 193 | } |
| 194 | |
| 195 | return static_cast<SpdyErrorCode>(wire_error_code); |
| 196 | } |
| 197 | |
| 198 | const char* ErrorCodeToString(SpdyErrorCode error_code) { |
| 199 | switch (error_code) { |
| 200 | case ERROR_CODE_NO_ERROR: |
| 201 | return "NO_ERROR"; |
| 202 | case ERROR_CODE_PROTOCOL_ERROR: |
| 203 | return "PROTOCOL_ERROR"; |
| 204 | case ERROR_CODE_INTERNAL_ERROR: |
| 205 | return "INTERNAL_ERROR"; |
| 206 | case ERROR_CODE_FLOW_CONTROL_ERROR: |
| 207 | return "FLOW_CONTROL_ERROR"; |
| 208 | case ERROR_CODE_SETTINGS_TIMEOUT: |
| 209 | return "SETTINGS_TIMEOUT"; |
| 210 | case ERROR_CODE_STREAM_CLOSED: |
| 211 | return "STREAM_CLOSED"; |
| 212 | case ERROR_CODE_FRAME_SIZE_ERROR: |
| 213 | return "FRAME_SIZE_ERROR"; |
| 214 | case ERROR_CODE_REFUSED_STREAM: |
| 215 | return "REFUSED_STREAM"; |
| 216 | case ERROR_CODE_CANCEL: |
| 217 | return "CANCEL"; |
| 218 | case ERROR_CODE_COMPRESSION_ERROR: |
| 219 | return "COMPRESSION_ERROR"; |
| 220 | case ERROR_CODE_CONNECT_ERROR: |
| 221 | return "CONNECT_ERROR"; |
| 222 | case ERROR_CODE_ENHANCE_YOUR_CALM: |
| 223 | return "ENHANCE_YOUR_CALM"; |
| 224 | case ERROR_CODE_INADEQUATE_SECURITY: |
| 225 | return "INADEQUATE_SECURITY"; |
| 226 | case ERROR_CODE_HTTP_1_1_REQUIRED: |
| 227 | return "HTTP_1_1_REQUIRED"; |
| 228 | } |
| 229 | return "UNKNOWN_ERROR_CODE"; |
| 230 | } |
| 231 | |
| 232 | size_t GetNumberRequiredContinuationFrames(size_t size) { |
| 233 | DCHECK_GT(size, kHttp2MaxControlFrameSendSize); |
| 234 | size_t overflow = size - kHttp2MaxControlFrameSendSize; |
| 235 | int payload_size = |
| 236 | kHttp2MaxControlFrameSendSize - kContinuationFrameMinimumSize; |
| 237 | // This is ceiling(overflow/payload_size) using integer arithmetics. |
| 238 | return (overflow - 1) / payload_size + 1; |
| 239 | } |
| 240 | |
| 241 | const char* const kHttp2Npn = "h2"; |
| 242 | |
| 243 | const char* const kHttp2AuthorityHeader = ":authority"; |
| 244 | const char* const kHttp2MethodHeader = ":method"; |
| 245 | const char* const kHttp2PathHeader = ":path"; |
| 246 | const char* const kHttp2SchemeHeader = ":scheme"; |
| 247 | const char* const kHttp2ProtocolHeader = ":protocol"; |
| 248 | |
| 249 | const char* const kHttp2StatusHeader = ":status"; |
| 250 | |
| 251 | bool SpdyFrameIR::fin() const { |
| 252 | return false; |
| 253 | } |
| 254 | |
| 255 | int SpdyFrameIR::flow_control_window_consumed() const { |
| 256 | return 0; |
| 257 | } |
| 258 | |
| 259 | bool SpdyFrameWithFinIR::fin() const { |
| 260 | return fin_; |
| 261 | } |
| 262 | |
| 263 | SpdyFrameWithHeaderBlockIR::SpdyFrameWithHeaderBlockIR( |
| 264 | SpdyStreamId stream_id, |
| 265 | SpdyHeaderBlock header_block) |
| 266 | : SpdyFrameWithFinIR(stream_id), header_block_(std::move(header_block)) {} |
| 267 | |
| 268 | SpdyFrameWithHeaderBlockIR::~SpdyFrameWithHeaderBlockIR() = default; |
| 269 | |
| 270 | SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, SpdyStringPiece data) |
| 271 | : SpdyFrameWithFinIR(stream_id), |
| 272 | data_(nullptr), |
| 273 | data_len_(0), |
| 274 | padded_(false), |
| 275 | padding_payload_len_(0) { |
| 276 | SetDataDeep(data); |
| 277 | } |
| 278 | |
| 279 | SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, const char* data) |
| 280 | : SpdyDataIR(stream_id, SpdyStringPiece(data)) {} |
| 281 | |
| 282 | SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, SpdyString data) |
| 283 | : SpdyFrameWithFinIR(stream_id), |
| 284 | data_store_(SpdyMakeUnique<SpdyString>(std::move(data))), |
| 285 | data_(data_store_->data()), |
| 286 | data_len_(data_store_->size()), |
| 287 | padded_(false), |
| 288 | padding_payload_len_(0) {} |
| 289 | |
| 290 | SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id) |
| 291 | : SpdyFrameWithFinIR(stream_id), |
| 292 | data_(nullptr), |
| 293 | data_len_(0), |
| 294 | padded_(false), |
| 295 | padding_payload_len_(0) {} |
| 296 | |
| 297 | SpdyDataIR::~SpdyDataIR() = default; |
| 298 | |
| 299 | void SpdyDataIR::Visit(SpdyFrameVisitor* visitor) const { |
| 300 | return visitor->VisitData(*this); |
| 301 | } |
| 302 | |
| 303 | SpdyFrameType SpdyDataIR::frame_type() const { |
| 304 | return SpdyFrameType::DATA; |
| 305 | } |
| 306 | |
| 307 | int SpdyDataIR::flow_control_window_consumed() const { |
| 308 | return padded_ ? 1 + padding_payload_len_ + data_len_ : data_len_; |
| 309 | } |
| 310 | |
| 311 | size_t SpdyDataIR::size() const { |
| 312 | return kFrameHeaderSize + |
| 313 | (padded() ? 1 + padding_payload_len() + data_len() : data_len()); |
| 314 | } |
| 315 | |
| 316 | SpdyRstStreamIR::SpdyRstStreamIR(SpdyStreamId stream_id, |
| 317 | SpdyErrorCode error_code) |
| 318 | : SpdyFrameIR(stream_id) { |
| 319 | set_error_code(error_code); |
| 320 | } |
| 321 | |
| 322 | SpdyRstStreamIR::~SpdyRstStreamIR() = default; |
| 323 | |
| 324 | void SpdyRstStreamIR::Visit(SpdyFrameVisitor* visitor) const { |
| 325 | return visitor->VisitRstStream(*this); |
| 326 | } |
| 327 | |
| 328 | SpdyFrameType SpdyRstStreamIR::frame_type() const { |
| 329 | return SpdyFrameType::RST_STREAM; |
| 330 | } |
| 331 | |
| 332 | size_t SpdyRstStreamIR::size() const { |
| 333 | return kRstStreamFrameSize; |
| 334 | } |
| 335 | |
| 336 | SpdySettingsIR::SpdySettingsIR() : is_ack_(false) {} |
| 337 | |
| 338 | SpdySettingsIR::~SpdySettingsIR() = default; |
| 339 | |
| 340 | void SpdySettingsIR::Visit(SpdyFrameVisitor* visitor) const { |
| 341 | return visitor->VisitSettings(*this); |
| 342 | } |
| 343 | |
| 344 | SpdyFrameType SpdySettingsIR::frame_type() const { |
| 345 | return SpdyFrameType::SETTINGS; |
| 346 | } |
| 347 | |
| 348 | size_t SpdySettingsIR::size() const { |
| 349 | return kFrameHeaderSize + values_.size() * kSettingsOneSettingSize; |
| 350 | } |
| 351 | |
| 352 | void SpdyPingIR::Visit(SpdyFrameVisitor* visitor) const { |
| 353 | return visitor->VisitPing(*this); |
| 354 | } |
| 355 | |
| 356 | SpdyFrameType SpdyPingIR::frame_type() const { |
| 357 | return SpdyFrameType::PING; |
| 358 | } |
| 359 | |
| 360 | size_t SpdyPingIR::size() const { |
| 361 | return kPingFrameSize; |
| 362 | } |
| 363 | |
| 364 | SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id, |
| 365 | SpdyErrorCode error_code, |
| 366 | SpdyStringPiece description) |
| 367 | : description_(description) { |
| 368 | set_last_good_stream_id(last_good_stream_id); |
| 369 | set_error_code(error_code); |
| 370 | } |
| 371 | |
| 372 | SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id, |
| 373 | SpdyErrorCode error_code, |
| 374 | const char* description) |
| 375 | : SpdyGoAwayIR(last_good_stream_id, |
| 376 | error_code, |
| 377 | SpdyStringPiece(description)) {} |
| 378 | |
| 379 | SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id, |
| 380 | SpdyErrorCode error_code, |
| 381 | SpdyString description) |
| 382 | : description_store_(std::move(description)), |
| 383 | description_(description_store_) { |
| 384 | set_last_good_stream_id(last_good_stream_id); |
| 385 | set_error_code(error_code); |
| 386 | } |
| 387 | |
| 388 | SpdyGoAwayIR::~SpdyGoAwayIR() = default; |
| 389 | |
| 390 | void SpdyGoAwayIR::Visit(SpdyFrameVisitor* visitor) const { |
| 391 | return visitor->VisitGoAway(*this); |
| 392 | } |
| 393 | |
| 394 | SpdyFrameType SpdyGoAwayIR::frame_type() const { |
| 395 | return SpdyFrameType::GOAWAY; |
| 396 | } |
| 397 | |
| 398 | size_t SpdyGoAwayIR::size() const { |
| 399 | return kGoawayFrameMinimumSize + description_.size(); |
| 400 | } |
| 401 | |
| 402 | SpdyContinuationIR::SpdyContinuationIR(SpdyStreamId stream_id) |
| 403 | : SpdyFrameIR(stream_id), end_headers_(false) { |
| 404 | encoding_ = SpdyMakeUnique<SpdyString>(); |
| 405 | } |
| 406 | |
| 407 | SpdyContinuationIR::~SpdyContinuationIR() = default; |
| 408 | |
| 409 | void SpdyContinuationIR::Visit(SpdyFrameVisitor* visitor) const { |
| 410 | return visitor->VisitContinuation(*this); |
| 411 | } |
| 412 | |
| 413 | SpdyFrameType SpdyContinuationIR::frame_type() const { |
| 414 | return SpdyFrameType::CONTINUATION; |
| 415 | } |
| 416 | |
| 417 | size_t SpdyContinuationIR::size() const { |
| 418 | // We don't need to get the size of CONTINUATION frame directly. It is |
| 419 | // calculated in HEADERS or PUSH_PROMISE frame. |
| 420 | DLOG(WARNING) << "Shouldn't not call size() for CONTINUATION frame."; |
| 421 | return 0; |
| 422 | } |
| 423 | |
| 424 | void SpdyHeadersIR::Visit(SpdyFrameVisitor* visitor) const { |
| 425 | return visitor->VisitHeaders(*this); |
| 426 | } |
| 427 | |
| 428 | SpdyFrameType SpdyHeadersIR::frame_type() const { |
| 429 | return SpdyFrameType::HEADERS; |
| 430 | } |
| 431 | |
| 432 | size_t SpdyHeadersIR::size() const { |
| 433 | size_t size = kHeadersFrameMinimumSize; |
| 434 | |
| 435 | if (padded_) { |
| 436 | // Padding field length. |
| 437 | size += 1; |
| 438 | size += padding_payload_len_; |
| 439 | } |
| 440 | |
| 441 | if (has_priority_) { |
| 442 | size += 5; |
| 443 | } |
| 444 | |
| 445 | // Assume no hpack encoding is applied. |
| 446 | size += header_block().TotalBytesUsed() + |
| 447 | header_block().size() * kPerHeaderHpackOverhead; |
| 448 | if (size > kHttp2MaxControlFrameSendSize) { |
| 449 | size += GetNumberRequiredContinuationFrames(size) * |
| 450 | kContinuationFrameMinimumSize; |
| 451 | } |
| 452 | return size; |
| 453 | } |
| 454 | |
| 455 | void SpdyWindowUpdateIR::Visit(SpdyFrameVisitor* visitor) const { |
| 456 | return visitor->VisitWindowUpdate(*this); |
| 457 | } |
| 458 | |
| 459 | SpdyFrameType SpdyWindowUpdateIR::frame_type() const { |
| 460 | return SpdyFrameType::WINDOW_UPDATE; |
| 461 | } |
| 462 | |
| 463 | size_t SpdyWindowUpdateIR::size() const { |
| 464 | return kWindowUpdateFrameSize; |
| 465 | } |
| 466 | |
| 467 | void SpdyPushPromiseIR::Visit(SpdyFrameVisitor* visitor) const { |
| 468 | return visitor->VisitPushPromise(*this); |
| 469 | } |
| 470 | |
| 471 | SpdyFrameType SpdyPushPromiseIR::frame_type() const { |
| 472 | return SpdyFrameType::PUSH_PROMISE; |
| 473 | } |
| 474 | |
| 475 | size_t SpdyPushPromiseIR::size() const { |
| 476 | size_t size = kPushPromiseFrameMinimumSize; |
| 477 | |
| 478 | if (padded_) { |
| 479 | // Padding length field. |
| 480 | size += 1; |
| 481 | size += padding_payload_len_; |
| 482 | } |
| 483 | |
| 484 | size += header_block().TotalBytesUsed(); |
| 485 | if (size > kHttp2MaxControlFrameSendSize) { |
| 486 | size += GetNumberRequiredContinuationFrames(size) * |
| 487 | kContinuationFrameMinimumSize; |
| 488 | } |
| 489 | return size; |
| 490 | } |
| 491 | |
| 492 | SpdyAltSvcIR::SpdyAltSvcIR(SpdyStreamId stream_id) : SpdyFrameIR(stream_id) {} |
| 493 | |
| 494 | SpdyAltSvcIR::~SpdyAltSvcIR() = default; |
| 495 | |
| 496 | void SpdyAltSvcIR::Visit(SpdyFrameVisitor* visitor) const { |
| 497 | return visitor->VisitAltSvc(*this); |
| 498 | } |
| 499 | |
| 500 | SpdyFrameType SpdyAltSvcIR::frame_type() const { |
| 501 | return SpdyFrameType::ALTSVC; |
| 502 | } |
| 503 | |
| 504 | size_t SpdyAltSvcIR::size() const { |
| 505 | size_t size = kGetAltSvcFrameMinimumSize; |
| 506 | size += origin_.length(); |
| 507 | // TODO(yasong): estimates the size without serializing the vector. |
| 508 | SpdyString str = |
| 509 | SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector_); |
| 510 | size += str.size(); |
| 511 | return size; |
| 512 | } |
| 513 | |
| 514 | void SpdyPriorityIR::Visit(SpdyFrameVisitor* visitor) const { |
| 515 | return visitor->VisitPriority(*this); |
| 516 | } |
| 517 | |
| 518 | SpdyFrameType SpdyPriorityIR::frame_type() const { |
| 519 | return SpdyFrameType::PRIORITY; |
| 520 | } |
| 521 | |
| 522 | size_t SpdyPriorityIR::size() const { |
| 523 | return kPriorityFrameSize; |
| 524 | } |
| 525 | |
| 526 | void SpdyUnknownIR::Visit(SpdyFrameVisitor* visitor) const { |
| 527 | return visitor->VisitUnknown(*this); |
| 528 | } |
| 529 | |
| 530 | SpdyFrameType SpdyUnknownIR::frame_type() const { |
| 531 | return static_cast<SpdyFrameType>(type()); |
| 532 | } |
| 533 | |
| 534 | size_t SpdyUnknownIR::size() const { |
| 535 | return kFrameHeaderSize + payload_.size(); |
| 536 | } |
| 537 | |
| 538 | int SpdyUnknownIR::flow_control_window_consumed() const { |
| 539 | if (frame_type() == SpdyFrameType::DATA) { |
| 540 | return payload_.size(); |
| 541 | } else { |
| 542 | return 0; |
| 543 | } |
| 544 | } |
| 545 | |
| 546 | // Wire size of pad length field. |
| 547 | const size_t kPadLengthFieldSize = 1; |
| 548 | |
| 549 | size_t GetHeaderFrameSizeSansBlock(const SpdyHeadersIR& header_ir) { |
| 550 | size_t min_size = kFrameHeaderSize; |
| 551 | if (header_ir.padded()) { |
| 552 | min_size += kPadLengthFieldSize; |
| 553 | min_size += header_ir.padding_payload_len(); |
| 554 | } |
| 555 | if (header_ir.has_priority()) { |
| 556 | min_size += 5; |
| 557 | } |
| 558 | return min_size; |
| 559 | } |
| 560 | |
| 561 | size_t GetPushPromiseFrameSizeSansBlock( |
| 562 | const SpdyPushPromiseIR& push_promise_ir) { |
| 563 | size_t min_size = kPushPromiseFrameMinimumSize; |
| 564 | if (push_promise_ir.padded()) { |
| 565 | min_size += kPadLengthFieldSize; |
| 566 | min_size += push_promise_ir.padding_payload_len(); |
| 567 | } |
| 568 | return min_size; |
| 569 | } |
| 570 | |
| 571 | } // namespace spdy |