xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 "quiche/spdy/core/spdy_protocol.h"
6 
7 #include <cstddef>
8 #include <cstdint>
9 #include <limits>
10 #include <memory>
11 #include <ostream>
12 #include <string>
13 #include <utility>
14 
15 #include "absl/strings/str_cat.h"
16 #include "absl/strings/string_view.h"
17 #include "quiche/common/platform/api/quiche_bug_tracker.h"
18 #include "quiche/common/platform/api/quiche_flag_utils.h"
19 #include "quiche/common/platform/api/quiche_logging.h"
20 #include "quiche/spdy/core/http2_header_block.h"
21 #include "quiche/spdy/core/spdy_alt_svc_wire_format.h"
22 
23 namespace spdy {
24 
25 const char* const kHttp2ConnectionHeaderPrefix =
26     "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
27 
operator <<(std::ostream & out,SpdyKnownSettingsId id)28 std::ostream& operator<<(std::ostream& out, SpdyKnownSettingsId id) {
29   return out << static_cast<SpdySettingsId>(id);
30 }
31 
operator <<(std::ostream & out,SpdyFrameType frame_type)32 std::ostream& operator<<(std::ostream& out, SpdyFrameType frame_type) {
33   return out << SerializeFrameType(frame_type);
34 }
35 
ClampSpdy3Priority(SpdyPriority priority)36 SpdyPriority ClampSpdy3Priority(SpdyPriority priority) {
37   static_assert(std::numeric_limits<SpdyPriority>::min() == kV3HighestPriority,
38                 "The value of given priority shouldn't be smaller than highest "
39                 "priority. Check this invariant explicitly.");
40   if (priority > kV3LowestPriority) {
41     QUICHE_BUG(spdy_bug_22_1)
42         << "Invalid priority: " << static_cast<int>(priority);
43     return kV3LowestPriority;
44   }
45   return priority;
46 }
47 
ClampHttp2Weight(int weight)48 int ClampHttp2Weight(int weight) {
49   if (weight < kHttp2MinStreamWeight) {
50     QUICHE_BUG(spdy_bug_22_2) << "Invalid weight: " << weight;
51     return kHttp2MinStreamWeight;
52   }
53   if (weight > kHttp2MaxStreamWeight) {
54     QUICHE_BUG(spdy_bug_22_3) << "Invalid weight: " << weight;
55     return kHttp2MaxStreamWeight;
56   }
57   return weight;
58 }
59 
Spdy3PriorityToHttp2Weight(SpdyPriority priority)60 int Spdy3PriorityToHttp2Weight(SpdyPriority priority) {
61   priority = ClampSpdy3Priority(priority);
62   const float kSteps = 255.9f / 7.f;
63   return static_cast<int>(kSteps * (7.f - priority)) + 1;
64 }
65 
Http2WeightToSpdy3Priority(int weight)66 SpdyPriority Http2WeightToSpdy3Priority(int weight) {
67   weight = ClampHttp2Weight(weight);
68   const float kSteps = 255.9f / 7.f;
69   return static_cast<SpdyPriority>(7.f - (weight - 1) / kSteps);
70 }
71 
IsDefinedFrameType(uint8_t frame_type_field)72 bool IsDefinedFrameType(uint8_t frame_type_field) {
73   switch (static_cast<SpdyFrameType>(frame_type_field)) {
74     case SpdyFrameType::DATA:
75       return true;
76     case SpdyFrameType::HEADERS:
77       return true;
78     case SpdyFrameType::PRIORITY:
79       return true;
80     case SpdyFrameType::RST_STREAM:
81       return true;
82     case SpdyFrameType::SETTINGS:
83       return true;
84     case SpdyFrameType::PUSH_PROMISE:
85       return true;
86     case SpdyFrameType::PING:
87       return true;
88     case SpdyFrameType::GOAWAY:
89       return true;
90     case SpdyFrameType::WINDOW_UPDATE:
91       return true;
92     case SpdyFrameType::CONTINUATION:
93       return true;
94     case SpdyFrameType::ALTSVC:
95       return true;
96     case SpdyFrameType::PRIORITY_UPDATE:
97       return true;
98     case SpdyFrameType::ACCEPT_CH:
99       return true;
100   }
101   return false;
102 }
103 
ParseFrameType(uint8_t frame_type_field)104 SpdyFrameType ParseFrameType(uint8_t frame_type_field) {
105   QUICHE_BUG_IF(spdy_bug_22_4, !IsDefinedFrameType(frame_type_field))
106       << "Frame type not defined: " << static_cast<int>(frame_type_field);
107   return static_cast<SpdyFrameType>(frame_type_field);
108 }
109 
SerializeFrameType(SpdyFrameType frame_type)110 uint8_t SerializeFrameType(SpdyFrameType frame_type) {
111   return static_cast<uint8_t>(frame_type);
112 }
113 
IsValidHTTP2FrameStreamId(SpdyStreamId current_frame_stream_id,SpdyFrameType frame_type_field)114 bool IsValidHTTP2FrameStreamId(SpdyStreamId current_frame_stream_id,
115                                SpdyFrameType frame_type_field) {
116   if (current_frame_stream_id == 0) {
117     switch (frame_type_field) {
118       case SpdyFrameType::DATA:
119       case SpdyFrameType::HEADERS:
120       case SpdyFrameType::PRIORITY:
121       case SpdyFrameType::RST_STREAM:
122       case SpdyFrameType::CONTINUATION:
123       case SpdyFrameType::PUSH_PROMISE:
124         // These frame types must specify a stream
125         return false;
126       default:
127         return true;
128     }
129   } else {
130     switch (frame_type_field) {
131       case SpdyFrameType::GOAWAY:
132       case SpdyFrameType::SETTINGS:
133       case SpdyFrameType::PING:
134         // These frame types must not specify a stream
135         return false;
136       default:
137         return true;
138     }
139   }
140 }
141 
FrameTypeToString(SpdyFrameType frame_type)142 const char* FrameTypeToString(SpdyFrameType frame_type) {
143   switch (frame_type) {
144     case SpdyFrameType::DATA:
145       return "DATA";
146     case SpdyFrameType::RST_STREAM:
147       return "RST_STREAM";
148     case SpdyFrameType::SETTINGS:
149       return "SETTINGS";
150     case SpdyFrameType::PING:
151       return "PING";
152     case SpdyFrameType::GOAWAY:
153       return "GOAWAY";
154     case SpdyFrameType::HEADERS:
155       return "HEADERS";
156     case SpdyFrameType::WINDOW_UPDATE:
157       return "WINDOW_UPDATE";
158     case SpdyFrameType::PUSH_PROMISE:
159       return "PUSH_PROMISE";
160     case SpdyFrameType::CONTINUATION:
161       return "CONTINUATION";
162     case SpdyFrameType::PRIORITY:
163       return "PRIORITY";
164     case SpdyFrameType::ALTSVC:
165       return "ALTSVC";
166     case SpdyFrameType::PRIORITY_UPDATE:
167       return "PRIORITY_UPDATE";
168     case SpdyFrameType::ACCEPT_CH:
169       return "ACCEPT_CH";
170   }
171   return "UNKNOWN_FRAME_TYPE";
172 }
173 
ParseSettingsId(SpdySettingsId wire_setting_id,SpdyKnownSettingsId * setting_id)174 bool ParseSettingsId(SpdySettingsId wire_setting_id,
175                      SpdyKnownSettingsId* setting_id) {
176   if (wire_setting_id != SETTINGS_EXPERIMENT_SCHEDULER &&
177       (wire_setting_id < SETTINGS_MIN || wire_setting_id > SETTINGS_MAX)) {
178     return false;
179   }
180 
181   *setting_id = static_cast<SpdyKnownSettingsId>(wire_setting_id);
182   // This switch ensures that the casted value is valid. The default case is
183   // explicitly omitted to have compile-time guarantees that new additions to
184   // |SpdyKnownSettingsId| must also be handled here.
185   switch (*setting_id) {
186     case SETTINGS_HEADER_TABLE_SIZE:
187     case SETTINGS_ENABLE_PUSH:
188     case SETTINGS_MAX_CONCURRENT_STREAMS:
189     case SETTINGS_INITIAL_WINDOW_SIZE:
190     case SETTINGS_MAX_FRAME_SIZE:
191     case SETTINGS_MAX_HEADER_LIST_SIZE:
192     case SETTINGS_ENABLE_CONNECT_PROTOCOL:
193     case SETTINGS_DEPRECATE_HTTP2_PRIORITIES:
194     case SETTINGS_EXPERIMENT_SCHEDULER:
195       return true;
196   }
197   return false;
198 }
199 
SettingsIdToString(SpdySettingsId id)200 std::string SettingsIdToString(SpdySettingsId id) {
201   SpdyKnownSettingsId known_id;
202   if (!ParseSettingsId(id, &known_id)) {
203     return absl::StrCat("SETTINGS_UNKNOWN_", absl::Hex(uint32_t{id}));
204   }
205 
206   switch (known_id) {
207     case SETTINGS_HEADER_TABLE_SIZE:
208       return "SETTINGS_HEADER_TABLE_SIZE";
209     case SETTINGS_ENABLE_PUSH:
210       return "SETTINGS_ENABLE_PUSH";
211     case SETTINGS_MAX_CONCURRENT_STREAMS:
212       return "SETTINGS_MAX_CONCURRENT_STREAMS";
213     case SETTINGS_INITIAL_WINDOW_SIZE:
214       return "SETTINGS_INITIAL_WINDOW_SIZE";
215     case SETTINGS_MAX_FRAME_SIZE:
216       return "SETTINGS_MAX_FRAME_SIZE";
217     case SETTINGS_MAX_HEADER_LIST_SIZE:
218       return "SETTINGS_MAX_HEADER_LIST_SIZE";
219     case SETTINGS_ENABLE_CONNECT_PROTOCOL:
220       return "SETTINGS_ENABLE_CONNECT_PROTOCOL";
221     case SETTINGS_DEPRECATE_HTTP2_PRIORITIES:
222       return "SETTINGS_DEPRECATE_HTTP2_PRIORITIES";
223     case SETTINGS_EXPERIMENT_SCHEDULER:
224       return "SETTINGS_EXPERIMENT_SCHEDULER";
225   }
226 
227   return absl::StrCat("SETTINGS_UNKNOWN_", absl::Hex(uint32_t{id}));
228 }
229 
ParseErrorCode(uint32_t wire_error_code)230 SpdyErrorCode ParseErrorCode(uint32_t wire_error_code) {
231   if (wire_error_code > ERROR_CODE_MAX) {
232     return ERROR_CODE_INTERNAL_ERROR;
233   }
234 
235   return static_cast<SpdyErrorCode>(wire_error_code);
236 }
237 
ErrorCodeToString(SpdyErrorCode error_code)238 const char* ErrorCodeToString(SpdyErrorCode error_code) {
239   switch (error_code) {
240     case ERROR_CODE_NO_ERROR:
241       return "NO_ERROR";
242     case ERROR_CODE_PROTOCOL_ERROR:
243       return "PROTOCOL_ERROR";
244     case ERROR_CODE_INTERNAL_ERROR:
245       return "INTERNAL_ERROR";
246     case ERROR_CODE_FLOW_CONTROL_ERROR:
247       return "FLOW_CONTROL_ERROR";
248     case ERROR_CODE_SETTINGS_TIMEOUT:
249       return "SETTINGS_TIMEOUT";
250     case ERROR_CODE_STREAM_CLOSED:
251       return "STREAM_CLOSED";
252     case ERROR_CODE_FRAME_SIZE_ERROR:
253       return "FRAME_SIZE_ERROR";
254     case ERROR_CODE_REFUSED_STREAM:
255       return "REFUSED_STREAM";
256     case ERROR_CODE_CANCEL:
257       return "CANCEL";
258     case ERROR_CODE_COMPRESSION_ERROR:
259       return "COMPRESSION_ERROR";
260     case ERROR_CODE_CONNECT_ERROR:
261       return "CONNECT_ERROR";
262     case ERROR_CODE_ENHANCE_YOUR_CALM:
263       return "ENHANCE_YOUR_CALM";
264     case ERROR_CODE_INADEQUATE_SECURITY:
265       return "INADEQUATE_SECURITY";
266     case ERROR_CODE_HTTP_1_1_REQUIRED:
267       return "HTTP_1_1_REQUIRED";
268   }
269   return "UNKNOWN_ERROR_CODE";
270 }
271 
WriteSchedulerTypeToString(WriteSchedulerType type)272 const char* WriteSchedulerTypeToString(WriteSchedulerType type) {
273   switch (type) {
274     case WriteSchedulerType::LIFO:
275       return "LIFO";
276     case WriteSchedulerType::SPDY:
277       return "SPDY";
278     case WriteSchedulerType::HTTP2:
279       return "HTTP2";
280     case WriteSchedulerType::FIFO:
281       return "FIFO";
282   }
283   return "UNKNOWN";
284 }
285 
GetNumberRequiredContinuationFrames(size_t size)286 size_t GetNumberRequiredContinuationFrames(size_t size) {
287   QUICHE_DCHECK_GT(size, kHttp2MaxControlFrameSendSize);
288   size_t overflow = size - kHttp2MaxControlFrameSendSize;
289   int payload_size =
290       kHttp2MaxControlFrameSendSize - kContinuationFrameMinimumSize;
291   // This is ceiling(overflow/payload_size) using integer arithmetics.
292   return (overflow - 1) / payload_size + 1;
293 }
294 
295 const char* const kHttp2Npn = "h2";
296 
297 const char* const kHttp2AuthorityHeader = ":authority";
298 const char* const kHttp2MethodHeader = ":method";
299 const char* const kHttp2PathHeader = ":path";
300 const char* const kHttp2SchemeHeader = ":scheme";
301 const char* const kHttp2ProtocolHeader = ":protocol";
302 
303 const char* const kHttp2StatusHeader = ":status";
304 
fin() const305 bool SpdyFrameIR::fin() const { return false; }
306 
flow_control_window_consumed() const307 int SpdyFrameIR::flow_control_window_consumed() const { return 0; }
308 
fin() const309 bool SpdyFrameWithFinIR::fin() const { return fin_; }
310 
SpdyFrameWithHeaderBlockIR(SpdyStreamId stream_id,Http2HeaderBlock header_block)311 SpdyFrameWithHeaderBlockIR::SpdyFrameWithHeaderBlockIR(
312     SpdyStreamId stream_id, Http2HeaderBlock header_block)
313     : SpdyFrameWithFinIR(stream_id), header_block_(std::move(header_block)) {}
314 
315 SpdyFrameWithHeaderBlockIR::~SpdyFrameWithHeaderBlockIR() = default;
316 
SpdyDataIR(SpdyStreamId stream_id,absl::string_view data)317 SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, absl::string_view data)
318     : SpdyFrameWithFinIR(stream_id),
319       data_(nullptr),
320       data_len_(0),
321       padded_(false),
322       padding_payload_len_(0) {
323   SetDataDeep(data);
324 }
325 
SpdyDataIR(SpdyStreamId stream_id,const char * data)326 SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, const char* data)
327     : SpdyDataIR(stream_id, absl::string_view(data)) {}
328 
SpdyDataIR(SpdyStreamId stream_id,std::string data)329 SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, std::string data)
330     : SpdyFrameWithFinIR(stream_id),
331       data_store_(std::make_unique<std::string>(std::move(data))),
332       data_(data_store_->data()),
333       data_len_(data_store_->size()),
334       padded_(false),
335       padding_payload_len_(0) {}
336 
SpdyDataIR(SpdyStreamId stream_id)337 SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id)
338     : SpdyFrameWithFinIR(stream_id),
339       data_(nullptr),
340       data_len_(0),
341       padded_(false),
342       padding_payload_len_(0) {}
343 
344 SpdyDataIR::~SpdyDataIR() = default;
345 
Visit(SpdyFrameVisitor * visitor) const346 void SpdyDataIR::Visit(SpdyFrameVisitor* visitor) const {
347   return visitor->VisitData(*this);
348 }
349 
frame_type() const350 SpdyFrameType SpdyDataIR::frame_type() const { return SpdyFrameType::DATA; }
351 
flow_control_window_consumed() const352 int SpdyDataIR::flow_control_window_consumed() const {
353   return padded_ ? 1 + padding_payload_len_ + data_len_ : data_len_;
354 }
355 
size() const356 size_t SpdyDataIR::size() const {
357   return kFrameHeaderSize +
358          (padded() ? 1 + padding_payload_len() + data_len() : data_len());
359 }
360 
SpdyRstStreamIR(SpdyStreamId stream_id,SpdyErrorCode error_code)361 SpdyRstStreamIR::SpdyRstStreamIR(SpdyStreamId stream_id,
362                                  SpdyErrorCode error_code)
363     : SpdyFrameIR(stream_id) {
364   set_error_code(error_code);
365 }
366 
367 SpdyRstStreamIR::~SpdyRstStreamIR() = default;
368 
Visit(SpdyFrameVisitor * visitor) const369 void SpdyRstStreamIR::Visit(SpdyFrameVisitor* visitor) const {
370   return visitor->VisitRstStream(*this);
371 }
372 
frame_type() const373 SpdyFrameType SpdyRstStreamIR::frame_type() const {
374   return SpdyFrameType::RST_STREAM;
375 }
376 
size() const377 size_t SpdyRstStreamIR::size() const { return kRstStreamFrameSize; }
378 
SpdySettingsIR()379 SpdySettingsIR::SpdySettingsIR() : is_ack_(false) {}
380 
381 SpdySettingsIR::~SpdySettingsIR() = default;
382 
Visit(SpdyFrameVisitor * visitor) const383 void SpdySettingsIR::Visit(SpdyFrameVisitor* visitor) const {
384   return visitor->VisitSettings(*this);
385 }
386 
frame_type() const387 SpdyFrameType SpdySettingsIR::frame_type() const {
388   return SpdyFrameType::SETTINGS;
389 }
390 
size() const391 size_t SpdySettingsIR::size() const {
392   return kFrameHeaderSize + values_.size() * kSettingsOneSettingSize;
393 }
394 
Visit(SpdyFrameVisitor * visitor) const395 void SpdyPingIR::Visit(SpdyFrameVisitor* visitor) const {
396   return visitor->VisitPing(*this);
397 }
398 
frame_type() const399 SpdyFrameType SpdyPingIR::frame_type() const { return SpdyFrameType::PING; }
400 
size() const401 size_t SpdyPingIR::size() const { return kPingFrameSize; }
402 
SpdyGoAwayIR(SpdyStreamId last_good_stream_id,SpdyErrorCode error_code,absl::string_view description)403 SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id,
404                            SpdyErrorCode error_code,
405                            absl::string_view description)
406     : description_(description) {
407   set_last_good_stream_id(last_good_stream_id);
408   set_error_code(error_code);
409 }
410 
SpdyGoAwayIR(SpdyStreamId last_good_stream_id,SpdyErrorCode error_code,const char * description)411 SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id,
412                            SpdyErrorCode error_code, const char* description)
413     : SpdyGoAwayIR(last_good_stream_id, error_code,
414                    absl::string_view(description)) {}
415 
SpdyGoAwayIR(SpdyStreamId last_good_stream_id,SpdyErrorCode error_code,std::string description)416 SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id,
417                            SpdyErrorCode error_code, std::string description)
418     : description_store_(std::move(description)),
419       description_(description_store_) {
420   set_last_good_stream_id(last_good_stream_id);
421   set_error_code(error_code);
422 }
423 
424 SpdyGoAwayIR::~SpdyGoAwayIR() = default;
425 
Visit(SpdyFrameVisitor * visitor) const426 void SpdyGoAwayIR::Visit(SpdyFrameVisitor* visitor) const {
427   return visitor->VisitGoAway(*this);
428 }
429 
frame_type() const430 SpdyFrameType SpdyGoAwayIR::frame_type() const { return SpdyFrameType::GOAWAY; }
431 
size() const432 size_t SpdyGoAwayIR::size() const {
433   return kGoawayFrameMinimumSize + description_.size();
434 }
435 
SpdyContinuationIR(SpdyStreamId stream_id)436 SpdyContinuationIR::SpdyContinuationIR(SpdyStreamId stream_id)
437     : SpdyFrameIR(stream_id), end_headers_(false) {}
438 
439 SpdyContinuationIR::~SpdyContinuationIR() = default;
440 
Visit(SpdyFrameVisitor * visitor) const441 void SpdyContinuationIR::Visit(SpdyFrameVisitor* visitor) const {
442   return visitor->VisitContinuation(*this);
443 }
444 
frame_type() const445 SpdyFrameType SpdyContinuationIR::frame_type() const {
446   return SpdyFrameType::CONTINUATION;
447 }
448 
size() const449 size_t SpdyContinuationIR::size() const {
450   // We don't need to get the size of CONTINUATION frame directly. It is
451   // calculated in HEADERS or PUSH_PROMISE frame.
452   QUICHE_DLOG(WARNING) << "Shouldn't not call size() for CONTINUATION frame.";
453   return 0;
454 }
455 
Visit(SpdyFrameVisitor * visitor) const456 void SpdyHeadersIR::Visit(SpdyFrameVisitor* visitor) const {
457   return visitor->VisitHeaders(*this);
458 }
459 
frame_type() const460 SpdyFrameType SpdyHeadersIR::frame_type() const {
461   return SpdyFrameType::HEADERS;
462 }
463 
size() const464 size_t SpdyHeadersIR::size() const {
465   size_t size = kHeadersFrameMinimumSize;
466 
467   if (padded_) {
468     // Padding field length.
469     size += 1;
470     size += padding_payload_len_;
471   }
472 
473   if (has_priority_) {
474     size += 5;
475   }
476 
477   // TODO(b/322146543): Remove `hpack_overhead` with deprecation of
478   // --gfe2_reloadable_flag_http2_add_hpack_overhead_bytes2.
479   size_t hpack_overhead = kPerHeaderHpackOverheadOld;
480   if (add_hpack_overhead_bytes_) {
481     QUICHE_RELOADABLE_FLAG_COUNT(http2_add_hpack_overhead_bytes2);
482     hpack_overhead = kPerHeaderHpackOverheadNew;
483   }
484   // Assume no hpack encoding is applied.
485   size +=
486       header_block().TotalBytesUsed() + header_block().size() * hpack_overhead;
487   if (size > kHttp2MaxControlFrameSendSize) {
488     size += GetNumberRequiredContinuationFrames(size) *
489             kContinuationFrameMinimumSize;
490   }
491   return size;
492 }
493 
Visit(SpdyFrameVisitor * visitor) const494 void SpdyWindowUpdateIR::Visit(SpdyFrameVisitor* visitor) const {
495   return visitor->VisitWindowUpdate(*this);
496 }
497 
frame_type() const498 SpdyFrameType SpdyWindowUpdateIR::frame_type() const {
499   return SpdyFrameType::WINDOW_UPDATE;
500 }
501 
size() const502 size_t SpdyWindowUpdateIR::size() const { return kWindowUpdateFrameSize; }
503 
Visit(SpdyFrameVisitor * visitor) const504 void SpdyPushPromiseIR::Visit(SpdyFrameVisitor* visitor) const {
505   return visitor->VisitPushPromise(*this);
506 }
507 
frame_type() const508 SpdyFrameType SpdyPushPromiseIR::frame_type() const {
509   return SpdyFrameType::PUSH_PROMISE;
510 }
511 
size() const512 size_t SpdyPushPromiseIR::size() const {
513   size_t size = kPushPromiseFrameMinimumSize;
514 
515   if (padded_) {
516     // Padding length field.
517     size += 1;
518     size += padding_payload_len_;
519   }
520 
521   size += header_block().TotalBytesUsed();
522   if (size > kHttp2MaxControlFrameSendSize) {
523     size += GetNumberRequiredContinuationFrames(size) *
524             kContinuationFrameMinimumSize;
525   }
526   return size;
527 }
528 
SpdyAltSvcIR(SpdyStreamId stream_id)529 SpdyAltSvcIR::SpdyAltSvcIR(SpdyStreamId stream_id) : SpdyFrameIR(stream_id) {}
530 
531 SpdyAltSvcIR::~SpdyAltSvcIR() = default;
532 
Visit(SpdyFrameVisitor * visitor) const533 void SpdyAltSvcIR::Visit(SpdyFrameVisitor* visitor) const {
534   return visitor->VisitAltSvc(*this);
535 }
536 
frame_type() const537 SpdyFrameType SpdyAltSvcIR::frame_type() const { return SpdyFrameType::ALTSVC; }
538 
size() const539 size_t SpdyAltSvcIR::size() const {
540   size_t size = kGetAltSvcFrameMinimumSize;
541   size += origin_.length();
542   // TODO(yasong): estimates the size without serializing the vector.
543   std::string str =
544       SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector_);
545   size += str.size();
546   return size;
547 }
548 
Visit(SpdyFrameVisitor * visitor) const549 void SpdyPriorityIR::Visit(SpdyFrameVisitor* visitor) const {
550   return visitor->VisitPriority(*this);
551 }
552 
frame_type() const553 SpdyFrameType SpdyPriorityIR::frame_type() const {
554   return SpdyFrameType::PRIORITY;
555 }
556 
size() const557 size_t SpdyPriorityIR::size() const { return kPriorityFrameSize; }
558 
Visit(SpdyFrameVisitor * visitor) const559 void SpdyPriorityUpdateIR::Visit(SpdyFrameVisitor* visitor) const {
560   return visitor->VisitPriorityUpdate(*this);
561 }
562 
frame_type() const563 SpdyFrameType SpdyPriorityUpdateIR::frame_type() const {
564   return SpdyFrameType::PRIORITY_UPDATE;
565 }
566 
size() const567 size_t SpdyPriorityUpdateIR::size() const {
568   return kPriorityUpdateFrameMinimumSize + priority_field_value_.size();
569 }
570 
Visit(SpdyFrameVisitor * visitor) const571 void SpdyAcceptChIR::Visit(SpdyFrameVisitor* visitor) const {
572   return visitor->VisitAcceptCh(*this);
573 }
574 
frame_type() const575 SpdyFrameType SpdyAcceptChIR::frame_type() const {
576   return SpdyFrameType::ACCEPT_CH;
577 }
578 
size() const579 size_t SpdyAcceptChIR::size() const {
580   size_t total_size = kAcceptChFrameMinimumSize;
581   for (const AcceptChOriginValuePair& entry : entries_) {
582     total_size += entry.origin.size() + entry.value.size() +
583                   kAcceptChFramePerEntryOverhead;
584   }
585   return total_size;
586 }
587 
Visit(SpdyFrameVisitor * visitor) const588 void SpdyUnknownIR::Visit(SpdyFrameVisitor* visitor) const {
589   return visitor->VisitUnknown(*this);
590 }
591 
frame_type() const592 SpdyFrameType SpdyUnknownIR::frame_type() const {
593   return static_cast<SpdyFrameType>(type());
594 }
595 
size() const596 size_t SpdyUnknownIR::size() const {
597   return kFrameHeaderSize + payload_.size();
598 }
599 
flow_control_window_consumed() const600 int SpdyUnknownIR::flow_control_window_consumed() const {
601   if (frame_type() == SpdyFrameType::DATA) {
602     return payload_.size();
603   } else {
604     return 0;
605   }
606 }
607 
608 // Wire size of pad length field.
609 const size_t kPadLengthFieldSize = 1;
610 
GetHeaderFrameSizeSansBlock(const SpdyHeadersIR & header_ir)611 size_t GetHeaderFrameSizeSansBlock(const SpdyHeadersIR& header_ir) {
612   size_t min_size = kFrameHeaderSize;
613   if (header_ir.padded()) {
614     min_size += kPadLengthFieldSize;
615     min_size += header_ir.padding_payload_len();
616   }
617   if (header_ir.has_priority()) {
618     min_size += 5;
619   }
620   return min_size;
621 }
622 
GetPushPromiseFrameSizeSansBlock(const SpdyPushPromiseIR & push_promise_ir)623 size_t GetPushPromiseFrameSizeSansBlock(
624     const SpdyPushPromiseIR& push_promise_ir) {
625   size_t min_size = kPushPromiseFrameMinimumSize;
626   if (push_promise_ir.padded()) {
627     min_size += kPadLengthFieldSize;
628     min_size += push_promise_ir.padding_payload_len();
629   }
630   return min_size;
631 }
632 
633 }  // namespace spdy
634