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