blob: f51dc6e6dfc36a17efe33a13bf7a1fa5457abe63 [file] [log] [blame]
QUICHE teamc9b2cec2019-01-07 17:54:15 -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
7#include <ostream>
8
QUICHE teamdc5ce1a2019-01-30 16:01:47 -05009#include "net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h"
QUICHE teamc9b2cec2019-01-07 17:54:15 -050010#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
13namespace spdy {
14
15const char* const kHttp2ConnectionHeaderPrefix =
16 "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
17
18std::ostream& operator<<(std::ostream& out, SpdyKnownSettingsId id) {
19 return out << static_cast<SpdySettingsId>(id);
20}
21
22std::ostream& operator<<(std::ostream& out, SpdyFrameType frame_type) {
23 return out << SerializeFrameType(frame_type);
24}
25
26SpdyPriority 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
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
232size_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
241const char* const kHttp2Npn = "h2";
242
243const char* const kHttp2AuthorityHeader = ":authority";
244const char* const kHttp2MethodHeader = ":method";
245const char* const kHttp2PathHeader = ":path";
246const char* const kHttp2SchemeHeader = ":scheme";
247const char* const kHttp2ProtocolHeader = ":protocol";
248
249const char* const kHttp2StatusHeader = ":status";
250
251bool SpdyFrameIR::fin() const {
252 return false;
253}
254
255int SpdyFrameIR::flow_control_window_consumed() const {
256 return 0;
257}
258
259bool SpdyFrameWithFinIR::fin() const {
260 return fin_;
261}
262
263SpdyFrameWithHeaderBlockIR::SpdyFrameWithHeaderBlockIR(
264 SpdyStreamId stream_id,
265 SpdyHeaderBlock header_block)
266 : SpdyFrameWithFinIR(stream_id), header_block_(std::move(header_block)) {}
267
268SpdyFrameWithHeaderBlockIR::~SpdyFrameWithHeaderBlockIR() = default;
269
270SpdyDataIR::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
279SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, const char* data)
280 : SpdyDataIR(stream_id, SpdyStringPiece(data)) {}
281
282SpdyDataIR::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
290SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id)
291 : SpdyFrameWithFinIR(stream_id),
292 data_(nullptr),
293 data_len_(0),
294 padded_(false),
295 padding_payload_len_(0) {}
296
297SpdyDataIR::~SpdyDataIR() = default;
298
299void SpdyDataIR::Visit(SpdyFrameVisitor* visitor) const {
300 return visitor->VisitData(*this);
301}
302
303SpdyFrameType SpdyDataIR::frame_type() const {
304 return SpdyFrameType::DATA;
305}
306
307int SpdyDataIR::flow_control_window_consumed() const {
308 return padded_ ? 1 + padding_payload_len_ + data_len_ : data_len_;
309}
310
311size_t SpdyDataIR::size() const {
312 return kFrameHeaderSize +
313 (padded() ? 1 + padding_payload_len() + data_len() : data_len());
314}
315
316SpdyRstStreamIR::SpdyRstStreamIR(SpdyStreamId stream_id,
317 SpdyErrorCode error_code)
318 : SpdyFrameIR(stream_id) {
319 set_error_code(error_code);
320}
321
322SpdyRstStreamIR::~SpdyRstStreamIR() = default;
323
324void SpdyRstStreamIR::Visit(SpdyFrameVisitor* visitor) const {
325 return visitor->VisitRstStream(*this);
326}
327
328SpdyFrameType SpdyRstStreamIR::frame_type() const {
329 return SpdyFrameType::RST_STREAM;
330}
331
332size_t SpdyRstStreamIR::size() const {
333 return kRstStreamFrameSize;
334}
335
336SpdySettingsIR::SpdySettingsIR() : is_ack_(false) {}
337
338SpdySettingsIR::~SpdySettingsIR() = default;
339
340void SpdySettingsIR::Visit(SpdyFrameVisitor* visitor) const {
341 return visitor->VisitSettings(*this);
342}
343
344SpdyFrameType SpdySettingsIR::frame_type() const {
345 return SpdyFrameType::SETTINGS;
346}
347
348size_t SpdySettingsIR::size() const {
349 return kFrameHeaderSize + values_.size() * kSettingsOneSettingSize;
350}
351
352void SpdyPingIR::Visit(SpdyFrameVisitor* visitor) const {
353 return visitor->VisitPing(*this);
354}
355
356SpdyFrameType SpdyPingIR::frame_type() const {
357 return SpdyFrameType::PING;
358}
359
360size_t SpdyPingIR::size() const {
361 return kPingFrameSize;
362}
363
364SpdyGoAwayIR::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
372SpdyGoAwayIR::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
379SpdyGoAwayIR::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
388SpdyGoAwayIR::~SpdyGoAwayIR() = default;
389
390void SpdyGoAwayIR::Visit(SpdyFrameVisitor* visitor) const {
391 return visitor->VisitGoAway(*this);
392}
393
394SpdyFrameType SpdyGoAwayIR::frame_type() const {
395 return SpdyFrameType::GOAWAY;
396}
397
398size_t SpdyGoAwayIR::size() const {
399 return kGoawayFrameMinimumSize + description_.size();
400}
401
402SpdyContinuationIR::SpdyContinuationIR(SpdyStreamId stream_id)
403 : SpdyFrameIR(stream_id), end_headers_(false) {
404 encoding_ = SpdyMakeUnique<SpdyString>();
405}
406
407SpdyContinuationIR::~SpdyContinuationIR() = default;
408
409void SpdyContinuationIR::Visit(SpdyFrameVisitor* visitor) const {
410 return visitor->VisitContinuation(*this);
411}
412
413SpdyFrameType SpdyContinuationIR::frame_type() const {
414 return SpdyFrameType::CONTINUATION;
415}
416
417size_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
424void SpdyHeadersIR::Visit(SpdyFrameVisitor* visitor) const {
425 return visitor->VisitHeaders(*this);
426}
427
428SpdyFrameType SpdyHeadersIR::frame_type() const {
429 return SpdyFrameType::HEADERS;
430}
431
432size_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
455void SpdyWindowUpdateIR::Visit(SpdyFrameVisitor* visitor) const {
456 return visitor->VisitWindowUpdate(*this);
457}
458
459SpdyFrameType SpdyWindowUpdateIR::frame_type() const {
460 return SpdyFrameType::WINDOW_UPDATE;
461}
462
463size_t SpdyWindowUpdateIR::size() const {
464 return kWindowUpdateFrameSize;
465}
466
467void SpdyPushPromiseIR::Visit(SpdyFrameVisitor* visitor) const {
468 return visitor->VisitPushPromise(*this);
469}
470
471SpdyFrameType SpdyPushPromiseIR::frame_type() const {
472 return SpdyFrameType::PUSH_PROMISE;
473}
474
475size_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
492SpdyAltSvcIR::SpdyAltSvcIR(SpdyStreamId stream_id) : SpdyFrameIR(stream_id) {}
493
494SpdyAltSvcIR::~SpdyAltSvcIR() = default;
495
496void SpdyAltSvcIR::Visit(SpdyFrameVisitor* visitor) const {
497 return visitor->VisitAltSvc(*this);
498}
499
500SpdyFrameType SpdyAltSvcIR::frame_type() const {
501 return SpdyFrameType::ALTSVC;
502}
503
504size_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
514void SpdyPriorityIR::Visit(SpdyFrameVisitor* visitor) const {
515 return visitor->VisitPriority(*this);
516}
517
518SpdyFrameType SpdyPriorityIR::frame_type() const {
519 return SpdyFrameType::PRIORITY;
520}
521
522size_t SpdyPriorityIR::size() const {
523 return kPriorityFrameSize;
524}
525
526void SpdyUnknownIR::Visit(SpdyFrameVisitor* visitor) const {
527 return visitor->VisitUnknown(*this);
528}
529
530SpdyFrameType SpdyUnknownIR::frame_type() const {
531 return static_cast<SpdyFrameType>(type());
532}
533
534size_t SpdyUnknownIR::size() const {
535 return kFrameHeaderSize + payload_.size();
536}
537
538int 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.
547const size_t kPadLengthFieldSize = 1;
548
549size_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
561size_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