blob: 9094b475bdccb14a87476bb6e06ce9877061f49a [file] [log] [blame]
QUICHE team82dee2f2019-01-18 12:35:12 -05001// 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
danzh8f3a5762019-06-25 13:43:51 -07007#include <limits>
QUICHE team82dee2f2019-01-18 12:35:12 -05008#include <ostream>
9
10#include "net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h"
11#include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h"
12#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h"
13
14namespace spdy {
15
16const char* const kHttp2ConnectionHeaderPrefix =
17 "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
18
19std::ostream& operator<<(std::ostream& out, SpdyKnownSettingsId id) {
20 return out << static_cast<SpdySettingsId>(id);
21}
22
23std::ostream& operator<<(std::ostream& out, SpdyFrameType frame_type) {
24 return out << SerializeFrameType(frame_type);
25}
26
27SpdyPriority ClampSpdy3Priority(SpdyPriority priority) {
danzh8f3a5762019-06-25 13:43:51 -070028 static_assert(std::numeric_limits<SpdyPriority>::min() == kV3HighestPriority,
29 "The value of given priority shouldn't be smaller than highest "
30 "priority. Check this invariant explicitly.");
QUICHE team82dee2f2019-01-18 12:35:12 -050031 if (priority > kV3LowestPriority) {
32 SPDY_BUG << "Invalid priority: " << static_cast<int>(priority);
33 return kV3LowestPriority;
34 }
35 return priority;
36}
37
38int 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
50int 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
56SpdyPriority 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
62bool IsDefinedFrameType(uint8_t frame_type_field) {
63 return frame_type_field <= SerializeFrameType(SpdyFrameType::MAX_FRAME_TYPE);
64}
65
66SpdyFrameType 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
72uint8_t SerializeFrameType(SpdyFrameType frame_type) {
73 return static_cast<uint8_t>(frame_type);
74}
75
76bool 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
104const 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
134bool 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
160SpdyString 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
190SpdyErrorCode 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
198const 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
fayange606e0c2019-08-05 06:56:05 -0700232const char* WriteSchedulerTypeToString(WriteSchedulerType type) {
233 switch (type) {
234 case WriteSchedulerType::LIFO:
235 return "LIFO";
236 case WriteSchedulerType::SPDY:
237 return "SPDY";
238 case WriteSchedulerType::HTTP2:
239 return "HTTP2";
240 case WriteSchedulerType::FIFO:
241 return "FIFO";
242 }
243 return "UNKNOWN";
244}
245
QUICHE team82dee2f2019-01-18 12:35:12 -0500246size_t GetNumberRequiredContinuationFrames(size_t size) {
247 DCHECK_GT(size, kHttp2MaxControlFrameSendSize);
248 size_t overflow = size - kHttp2MaxControlFrameSendSize;
249 int payload_size =
250 kHttp2MaxControlFrameSendSize - kContinuationFrameMinimumSize;
251 // This is ceiling(overflow/payload_size) using integer arithmetics.
252 return (overflow - 1) / payload_size + 1;
253}
254
255const char* const kHttp2Npn = "h2";
256
257const char* const kHttp2AuthorityHeader = ":authority";
258const char* const kHttp2MethodHeader = ":method";
259const char* const kHttp2PathHeader = ":path";
260const char* const kHttp2SchemeHeader = ":scheme";
261const char* const kHttp2ProtocolHeader = ":protocol";
262
263const char* const kHttp2StatusHeader = ":status";
264
265bool SpdyFrameIR::fin() const {
266 return false;
267}
268
269int SpdyFrameIR::flow_control_window_consumed() const {
270 return 0;
271}
272
273bool SpdyFrameWithFinIR::fin() const {
274 return fin_;
275}
276
277SpdyFrameWithHeaderBlockIR::SpdyFrameWithHeaderBlockIR(
278 SpdyStreamId stream_id,
279 SpdyHeaderBlock header_block)
280 : SpdyFrameWithFinIR(stream_id), header_block_(std::move(header_block)) {}
281
282SpdyFrameWithHeaderBlockIR::~SpdyFrameWithHeaderBlockIR() = default;
283
284SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, SpdyStringPiece data)
285 : SpdyFrameWithFinIR(stream_id),
286 data_(nullptr),
287 data_len_(0),
288 padded_(false),
289 padding_payload_len_(0) {
290 SetDataDeep(data);
291}
292
293SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, const char* data)
294 : SpdyDataIR(stream_id, SpdyStringPiece(data)) {}
295
296SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, SpdyString data)
297 : SpdyFrameWithFinIR(stream_id),
298 data_store_(SpdyMakeUnique<SpdyString>(std::move(data))),
299 data_(data_store_->data()),
300 data_len_(data_store_->size()),
301 padded_(false),
302 padding_payload_len_(0) {}
303
304SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id)
305 : SpdyFrameWithFinIR(stream_id),
306 data_(nullptr),
307 data_len_(0),
308 padded_(false),
309 padding_payload_len_(0) {}
310
311SpdyDataIR::~SpdyDataIR() = default;
312
313void SpdyDataIR::Visit(SpdyFrameVisitor* visitor) const {
314 return visitor->VisitData(*this);
315}
316
317SpdyFrameType SpdyDataIR::frame_type() const {
318 return SpdyFrameType::DATA;
319}
320
321int SpdyDataIR::flow_control_window_consumed() const {
322 return padded_ ? 1 + padding_payload_len_ + data_len_ : data_len_;
323}
324
325size_t SpdyDataIR::size() const {
326 return kFrameHeaderSize +
327 (padded() ? 1 + padding_payload_len() + data_len() : data_len());
328}
329
330SpdyRstStreamIR::SpdyRstStreamIR(SpdyStreamId stream_id,
331 SpdyErrorCode error_code)
332 : SpdyFrameIR(stream_id) {
333 set_error_code(error_code);
334}
335
336SpdyRstStreamIR::~SpdyRstStreamIR() = default;
337
338void SpdyRstStreamIR::Visit(SpdyFrameVisitor* visitor) const {
339 return visitor->VisitRstStream(*this);
340}
341
342SpdyFrameType SpdyRstStreamIR::frame_type() const {
343 return SpdyFrameType::RST_STREAM;
344}
345
346size_t SpdyRstStreamIR::size() const {
347 return kRstStreamFrameSize;
348}
349
350SpdySettingsIR::SpdySettingsIR() : is_ack_(false) {}
351
352SpdySettingsIR::~SpdySettingsIR() = default;
353
354void SpdySettingsIR::Visit(SpdyFrameVisitor* visitor) const {
355 return visitor->VisitSettings(*this);
356}
357
358SpdyFrameType SpdySettingsIR::frame_type() const {
359 return SpdyFrameType::SETTINGS;
360}
361
362size_t SpdySettingsIR::size() const {
363 return kFrameHeaderSize + values_.size() * kSettingsOneSettingSize;
364}
365
366void SpdyPingIR::Visit(SpdyFrameVisitor* visitor) const {
367 return visitor->VisitPing(*this);
368}
369
370SpdyFrameType SpdyPingIR::frame_type() const {
371 return SpdyFrameType::PING;
372}
373
374size_t SpdyPingIR::size() const {
375 return kPingFrameSize;
376}
377
378SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id,
379 SpdyErrorCode error_code,
380 SpdyStringPiece description)
381 : description_(description) {
382 set_last_good_stream_id(last_good_stream_id);
383 set_error_code(error_code);
384}
385
386SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id,
387 SpdyErrorCode error_code,
388 const char* description)
389 : SpdyGoAwayIR(last_good_stream_id,
390 error_code,
391 SpdyStringPiece(description)) {}
392
393SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id,
394 SpdyErrorCode error_code,
395 SpdyString description)
396 : description_store_(std::move(description)),
397 description_(description_store_) {
398 set_last_good_stream_id(last_good_stream_id);
399 set_error_code(error_code);
400}
401
402SpdyGoAwayIR::~SpdyGoAwayIR() = default;
403
404void SpdyGoAwayIR::Visit(SpdyFrameVisitor* visitor) const {
405 return visitor->VisitGoAway(*this);
406}
407
408SpdyFrameType SpdyGoAwayIR::frame_type() const {
409 return SpdyFrameType::GOAWAY;
410}
411
412size_t SpdyGoAwayIR::size() const {
413 return kGoawayFrameMinimumSize + description_.size();
414}
415
416SpdyContinuationIR::SpdyContinuationIR(SpdyStreamId stream_id)
417 : SpdyFrameIR(stream_id), end_headers_(false) {
418 encoding_ = SpdyMakeUnique<SpdyString>();
419}
420
421SpdyContinuationIR::~SpdyContinuationIR() = default;
422
423void SpdyContinuationIR::Visit(SpdyFrameVisitor* visitor) const {
424 return visitor->VisitContinuation(*this);
425}
426
427SpdyFrameType SpdyContinuationIR::frame_type() const {
428 return SpdyFrameType::CONTINUATION;
429}
430
431size_t SpdyContinuationIR::size() const {
432 // We don't need to get the size of CONTINUATION frame directly. It is
433 // calculated in HEADERS or PUSH_PROMISE frame.
QUICHE teamded03512019-03-07 14:45:11 -0800434 SPDY_DLOG(WARNING) << "Shouldn't not call size() for CONTINUATION frame.";
QUICHE team82dee2f2019-01-18 12:35:12 -0500435 return 0;
436}
437
438void SpdyHeadersIR::Visit(SpdyFrameVisitor* visitor) const {
439 return visitor->VisitHeaders(*this);
440}
441
442SpdyFrameType SpdyHeadersIR::frame_type() const {
443 return SpdyFrameType::HEADERS;
444}
445
446size_t SpdyHeadersIR::size() const {
447 size_t size = kHeadersFrameMinimumSize;
448
449 if (padded_) {
450 // Padding field length.
451 size += 1;
452 size += padding_payload_len_;
453 }
454
455 if (has_priority_) {
456 size += 5;
457 }
458
459 // Assume no hpack encoding is applied.
460 size += header_block().TotalBytesUsed() +
461 header_block().size() * kPerHeaderHpackOverhead;
462 if (size > kHttp2MaxControlFrameSendSize) {
463 size += GetNumberRequiredContinuationFrames(size) *
464 kContinuationFrameMinimumSize;
465 }
466 return size;
467}
468
469void SpdyWindowUpdateIR::Visit(SpdyFrameVisitor* visitor) const {
470 return visitor->VisitWindowUpdate(*this);
471}
472
473SpdyFrameType SpdyWindowUpdateIR::frame_type() const {
474 return SpdyFrameType::WINDOW_UPDATE;
475}
476
477size_t SpdyWindowUpdateIR::size() const {
478 return kWindowUpdateFrameSize;
479}
480
481void SpdyPushPromiseIR::Visit(SpdyFrameVisitor* visitor) const {
482 return visitor->VisitPushPromise(*this);
483}
484
485SpdyFrameType SpdyPushPromiseIR::frame_type() const {
486 return SpdyFrameType::PUSH_PROMISE;
487}
488
489size_t SpdyPushPromiseIR::size() const {
490 size_t size = kPushPromiseFrameMinimumSize;
491
492 if (padded_) {
493 // Padding length field.
494 size += 1;
495 size += padding_payload_len_;
496 }
497
498 size += header_block().TotalBytesUsed();
499 if (size > kHttp2MaxControlFrameSendSize) {
500 size += GetNumberRequiredContinuationFrames(size) *
501 kContinuationFrameMinimumSize;
502 }
503 return size;
504}
505
506SpdyAltSvcIR::SpdyAltSvcIR(SpdyStreamId stream_id) : SpdyFrameIR(stream_id) {}
507
508SpdyAltSvcIR::~SpdyAltSvcIR() = default;
509
510void SpdyAltSvcIR::Visit(SpdyFrameVisitor* visitor) const {
511 return visitor->VisitAltSvc(*this);
512}
513
514SpdyFrameType SpdyAltSvcIR::frame_type() const {
515 return SpdyFrameType::ALTSVC;
516}
517
518size_t SpdyAltSvcIR::size() const {
519 size_t size = kGetAltSvcFrameMinimumSize;
520 size += origin_.length();
521 // TODO(yasong): estimates the size without serializing the vector.
522 SpdyString str =
523 SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector_);
524 size += str.size();
525 return size;
526}
527
528void SpdyPriorityIR::Visit(SpdyFrameVisitor* visitor) const {
529 return visitor->VisitPriority(*this);
530}
531
532SpdyFrameType SpdyPriorityIR::frame_type() const {
533 return SpdyFrameType::PRIORITY;
534}
535
536size_t SpdyPriorityIR::size() const {
537 return kPriorityFrameSize;
538}
539
540void SpdyUnknownIR::Visit(SpdyFrameVisitor* visitor) const {
541 return visitor->VisitUnknown(*this);
542}
543
544SpdyFrameType SpdyUnknownIR::frame_type() const {
545 return static_cast<SpdyFrameType>(type());
546}
547
548size_t SpdyUnknownIR::size() const {
549 return kFrameHeaderSize + payload_.size();
550}
551
552int SpdyUnknownIR::flow_control_window_consumed() const {
553 if (frame_type() == SpdyFrameType::DATA) {
554 return payload_.size();
555 } else {
556 return 0;
557 }
558}
559
560// Wire size of pad length field.
561const size_t kPadLengthFieldSize = 1;
562
563size_t GetHeaderFrameSizeSansBlock(const SpdyHeadersIR& header_ir) {
564 size_t min_size = kFrameHeaderSize;
565 if (header_ir.padded()) {
566 min_size += kPadLengthFieldSize;
567 min_size += header_ir.padding_payload_len();
568 }
569 if (header_ir.has_priority()) {
570 min_size += 5;
571 }
572 return min_size;
573}
574
575size_t GetPushPromiseFrameSizeSansBlock(
576 const SpdyPushPromiseIR& push_promise_ir) {
577 size_t min_size = kPushPromiseFrameMinimumSize;
578 if (push_promise_ir.padded()) {
579 min_size += kPadLengthFieldSize;
580 min_size += push_promise_ir.padding_payload_len();
581 }
582 return min_size;
583}
584
585} // namespace spdy