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