blob: 0ab6737950b9b2d2019fb4742f78bcffb75df298 [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"
QUICHE team82dee2f2019-01-18 12:35:12 -050011#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) {
danzh8f3a5762019-06-25 13:43:51 -070027 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 team82dee2f2019-01-18 12:35:12 -050030 if (priority > kV3LowestPriority) {
31 SPDY_BUG << "Invalid priority: " << static_cast<int>(priority);
32 return kV3LowestPriority;
33 }
34 return priority;
35}
36
37int 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
49int 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
55SpdyPriority 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
61bool IsDefinedFrameType(uint8_t frame_type_field) {
62 return frame_type_field <= SerializeFrameType(SpdyFrameType::MAX_FRAME_TYPE);
63}
64
65SpdyFrameType 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
71uint8_t SerializeFrameType(SpdyFrameType frame_type) {
72 return static_cast<uint8_t>(frame_type);
73}
74
75bool 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
103const 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
133bool 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
bnc44712912019-08-15 18:58:14 -0700159std::string SettingsIdToString(SpdySettingsId id) {
QUICHE team82dee2f2019-01-18 12:35:12 -0500160 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
189SpdyErrorCode 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
197const 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
fayange606e0c2019-08-05 06:56:05 -0700231const 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 team82dee2f2019-01-18 12:35:12 -0500245size_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
254const char* const kHttp2Npn = "h2";
255
256const char* const kHttp2AuthorityHeader = ":authority";
257const char* const kHttp2MethodHeader = ":method";
258const char* const kHttp2PathHeader = ":path";
259const char* const kHttp2SchemeHeader = ":scheme";
260const char* const kHttp2ProtocolHeader = ":protocol";
261
262const char* const kHttp2StatusHeader = ":status";
263
264bool SpdyFrameIR::fin() const {
265 return false;
266}
267
268int SpdyFrameIR::flow_control_window_consumed() const {
269 return 0;
270}
271
272bool SpdyFrameWithFinIR::fin() const {
273 return fin_;
274}
275
276SpdyFrameWithHeaderBlockIR::SpdyFrameWithHeaderBlockIR(
277 SpdyStreamId stream_id,
278 SpdyHeaderBlock header_block)
279 : SpdyFrameWithFinIR(stream_id), header_block_(std::move(header_block)) {}
280
281SpdyFrameWithHeaderBlockIR::~SpdyFrameWithHeaderBlockIR() = default;
282
283SpdyDataIR::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
292SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, const char* data)
293 : SpdyDataIR(stream_id, SpdyStringPiece(data)) {}
294
bnc44712912019-08-15 18:58:14 -0700295SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, std::string data)
QUICHE team82dee2f2019-01-18 12:35:12 -0500296 : SpdyFrameWithFinIR(stream_id),
bnc463f2352019-10-10 04:49:34 -0700297 data_store_(std::make_unique<std::string>(std::move(data))),
QUICHE team82dee2f2019-01-18 12:35:12 -0500298 data_(data_store_->data()),
299 data_len_(data_store_->size()),
300 padded_(false),
301 padding_payload_len_(0) {}
302
303SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id)
304 : SpdyFrameWithFinIR(stream_id),
305 data_(nullptr),
306 data_len_(0),
307 padded_(false),
308 padding_payload_len_(0) {}
309
310SpdyDataIR::~SpdyDataIR() = default;
311
312void SpdyDataIR::Visit(SpdyFrameVisitor* visitor) const {
313 return visitor->VisitData(*this);
314}
315
316SpdyFrameType SpdyDataIR::frame_type() const {
317 return SpdyFrameType::DATA;
318}
319
320int SpdyDataIR::flow_control_window_consumed() const {
321 return padded_ ? 1 + padding_payload_len_ + data_len_ : data_len_;
322}
323
324size_t SpdyDataIR::size() const {
325 return kFrameHeaderSize +
326 (padded() ? 1 + padding_payload_len() + data_len() : data_len());
327}
328
329SpdyRstStreamIR::SpdyRstStreamIR(SpdyStreamId stream_id,
330 SpdyErrorCode error_code)
331 : SpdyFrameIR(stream_id) {
332 set_error_code(error_code);
333}
334
335SpdyRstStreamIR::~SpdyRstStreamIR() = default;
336
337void SpdyRstStreamIR::Visit(SpdyFrameVisitor* visitor) const {
338 return visitor->VisitRstStream(*this);
339}
340
341SpdyFrameType SpdyRstStreamIR::frame_type() const {
342 return SpdyFrameType::RST_STREAM;
343}
344
345size_t SpdyRstStreamIR::size() const {
346 return kRstStreamFrameSize;
347}
348
349SpdySettingsIR::SpdySettingsIR() : is_ack_(false) {}
350
351SpdySettingsIR::~SpdySettingsIR() = default;
352
353void SpdySettingsIR::Visit(SpdyFrameVisitor* visitor) const {
354 return visitor->VisitSettings(*this);
355}
356
357SpdyFrameType SpdySettingsIR::frame_type() const {
358 return SpdyFrameType::SETTINGS;
359}
360
361size_t SpdySettingsIR::size() const {
362 return kFrameHeaderSize + values_.size() * kSettingsOneSettingSize;
363}
364
365void SpdyPingIR::Visit(SpdyFrameVisitor* visitor) const {
366 return visitor->VisitPing(*this);
367}
368
369SpdyFrameType SpdyPingIR::frame_type() const {
370 return SpdyFrameType::PING;
371}
372
373size_t SpdyPingIR::size() const {
374 return kPingFrameSize;
375}
376
377SpdyGoAwayIR::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
385SpdyGoAwayIR::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
392SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id,
393 SpdyErrorCode error_code,
bnc44712912019-08-15 18:58:14 -0700394 std::string description)
QUICHE team82dee2f2019-01-18 12:35:12 -0500395 : 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
401SpdyGoAwayIR::~SpdyGoAwayIR() = default;
402
403void SpdyGoAwayIR::Visit(SpdyFrameVisitor* visitor) const {
404 return visitor->VisitGoAway(*this);
405}
406
407SpdyFrameType SpdyGoAwayIR::frame_type() const {
408 return SpdyFrameType::GOAWAY;
409}
410
411size_t SpdyGoAwayIR::size() const {
412 return kGoawayFrameMinimumSize + description_.size();
413}
414
415SpdyContinuationIR::SpdyContinuationIR(SpdyStreamId stream_id)
416 : SpdyFrameIR(stream_id), end_headers_(false) {
bnc463f2352019-10-10 04:49:34 -0700417 encoding_ = std::make_unique<std::string>();
QUICHE team82dee2f2019-01-18 12:35:12 -0500418}
419
420SpdyContinuationIR::~SpdyContinuationIR() = default;
421
422void SpdyContinuationIR::Visit(SpdyFrameVisitor* visitor) const {
423 return visitor->VisitContinuation(*this);
424}
425
426SpdyFrameType SpdyContinuationIR::frame_type() const {
427 return SpdyFrameType::CONTINUATION;
428}
429
430size_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 teamded03512019-03-07 14:45:11 -0800433 SPDY_DLOG(WARNING) << "Shouldn't not call size() for CONTINUATION frame.";
QUICHE team82dee2f2019-01-18 12:35:12 -0500434 return 0;
435}
436
437void SpdyHeadersIR::Visit(SpdyFrameVisitor* visitor) const {
438 return visitor->VisitHeaders(*this);
439}
440
441SpdyFrameType SpdyHeadersIR::frame_type() const {
442 return SpdyFrameType::HEADERS;
443}
444
445size_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
468void SpdyWindowUpdateIR::Visit(SpdyFrameVisitor* visitor) const {
469 return visitor->VisitWindowUpdate(*this);
470}
471
472SpdyFrameType SpdyWindowUpdateIR::frame_type() const {
473 return SpdyFrameType::WINDOW_UPDATE;
474}
475
476size_t SpdyWindowUpdateIR::size() const {
477 return kWindowUpdateFrameSize;
478}
479
480void SpdyPushPromiseIR::Visit(SpdyFrameVisitor* visitor) const {
481 return visitor->VisitPushPromise(*this);
482}
483
484SpdyFrameType SpdyPushPromiseIR::frame_type() const {
485 return SpdyFrameType::PUSH_PROMISE;
486}
487
488size_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
505SpdyAltSvcIR::SpdyAltSvcIR(SpdyStreamId stream_id) : SpdyFrameIR(stream_id) {}
506
507SpdyAltSvcIR::~SpdyAltSvcIR() = default;
508
509void SpdyAltSvcIR::Visit(SpdyFrameVisitor* visitor) const {
510 return visitor->VisitAltSvc(*this);
511}
512
513SpdyFrameType SpdyAltSvcIR::frame_type() const {
514 return SpdyFrameType::ALTSVC;
515}
516
517size_t SpdyAltSvcIR::size() const {
518 size_t size = kGetAltSvcFrameMinimumSize;
519 size += origin_.length();
520 // TODO(yasong): estimates the size without serializing the vector.
bnc44712912019-08-15 18:58:14 -0700521 std::string str =
QUICHE team82dee2f2019-01-18 12:35:12 -0500522 SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector_);
523 size += str.size();
524 return size;
525}
526
527void SpdyPriorityIR::Visit(SpdyFrameVisitor* visitor) const {
528 return visitor->VisitPriority(*this);
529}
530
531SpdyFrameType SpdyPriorityIR::frame_type() const {
532 return SpdyFrameType::PRIORITY;
533}
534
535size_t SpdyPriorityIR::size() const {
536 return kPriorityFrameSize;
537}
538
539void SpdyUnknownIR::Visit(SpdyFrameVisitor* visitor) const {
540 return visitor->VisitUnknown(*this);
541}
542
543SpdyFrameType SpdyUnknownIR::frame_type() const {
544 return static_cast<SpdyFrameType>(type());
545}
546
547size_t SpdyUnknownIR::size() const {
548 return kFrameHeaderSize + payload_.size();
549}
550
551int 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.
560const size_t kPadLengthFieldSize = 1;
561
562size_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
574size_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