OLD | NEW |
| (Empty) |
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 // This file contains some protocol structures for use with SPDY 3 and HTTP 2 | |
6 // The SPDY 3 spec can be found at: | |
7 // http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3 | |
8 | |
9 #ifndef NET_SPDY_SPDY_PROTOCOL_H_ | |
10 #define NET_SPDY_SPDY_PROTOCOL_H_ | |
11 | |
12 #include <stddef.h> | |
13 #include <stdint.h> | |
14 | |
15 #include <iosfwd> | |
16 #include <limits> | |
17 #include <map> | |
18 #include <memory> | |
19 #include <utility> | |
20 | |
21 #include "base/compiler_specific.h" | |
22 #include "base/logging.h" | |
23 #include "base/macros.h" | |
24 #include "base/sys_byteorder.h" | |
25 #include "net/base/net_export.h" | |
26 #include "net/spdy/platform/api/spdy_string.h" | |
27 #include "net/spdy/platform/api/spdy_string_piece.h" | |
28 #include "net/spdy/spdy_alt_svc_wire_format.h" | |
29 #include "net/spdy/spdy_bitmasks.h" | |
30 #include "net/spdy/spdy_bug_tracker.h" | |
31 #include "net/spdy/spdy_header_block.h" | |
32 | |
33 namespace net { | |
34 | |
35 // A stream id is a 31 bit entity. | |
36 typedef uint32_t SpdyStreamId; | |
37 | |
38 // Specifies the stream ID used to denote the current session (for | |
39 // flow control). | |
40 const SpdyStreamId kSessionFlowControlStreamId = 0; | |
41 | |
42 // Max stream id. | |
43 const SpdyStreamId kMaxStreamId = 0x7fffffff; | |
44 | |
45 // The maximum possible frame payload size allowed by the spec. | |
46 const uint32_t kSpdyMaxFrameSizeLimit = (1 << 24) - 1; | |
47 | |
48 // The initial value for the maximum frame payload size as per the spec. This is | |
49 // the maximum control frame size we accept. | |
50 const uint32_t kSpdyInitialFrameSizeLimit = 1 << 14; | |
51 | |
52 // The initial value for the maximum size of the header list, "unlimited" (max | |
53 // unsigned 32-bit int) as per the spec. | |
54 const uint32_t kSpdyInitialHeaderListSizeLimit = 0xFFFFFFFF; | |
55 | |
56 // Maximum window size for a Spdy stream or session. | |
57 const int32_t kSpdyMaximumWindowSize = 0x7FFFFFFF; // Max signed 32bit int | |
58 | |
59 // Maximum padding size in octets for one DATA or HEADERS or PUSH_PROMISE frame. | |
60 const int32_t kPaddingSizePerFrame = 256; | |
61 | |
62 // The HTTP/2 connection preface, which must be the first bytes sent by the | |
63 // client upon starting an HTTP/2 connection, and which must be followed by a | |
64 // SETTINGS frame. Note that even though |kHttp2ConnectionHeaderPrefix| is | |
65 // defined as a string literal with a null terminator, the actual connection | |
66 // preface is only the first |kHttp2ConnectionHeaderPrefixSize| bytes, which | |
67 // excludes the null terminator. | |
68 NET_EXPORT_PRIVATE extern const char* const kHttp2ConnectionHeaderPrefix; | |
69 const int kHttp2ConnectionHeaderPrefixSize = 24; | |
70 | |
71 // Wire values for HTTP2 frame types. | |
72 enum class SpdyFrameType : uint8_t { | |
73 DATA = 0x00, | |
74 HEADERS = 0x01, | |
75 PRIORITY = 0x02, | |
76 RST_STREAM = 0x03, | |
77 SETTINGS = 0x04, | |
78 PUSH_PROMISE = 0x05, | |
79 PING = 0x06, | |
80 GOAWAY = 0x07, | |
81 WINDOW_UPDATE = 0x08, | |
82 CONTINUATION = 0x09, | |
83 // ALTSVC is a public extension. | |
84 ALTSVC = 0x0a, | |
85 MAX_FRAME_TYPE = ALTSVC, | |
86 // The specific value of EXTENSION is meaningless; it is a placeholder used | |
87 // within SpdyFramer's state machine when handling unknown frames via an | |
88 // extension API. | |
89 EXTENSION = 0xff | |
90 }; | |
91 | |
92 // Flags on data packets. | |
93 enum SpdyDataFlags { | |
94 DATA_FLAG_NONE = 0x00, | |
95 DATA_FLAG_FIN = 0x01, | |
96 DATA_FLAG_PADDED = 0x08, | |
97 }; | |
98 | |
99 // Flags on control packets | |
100 enum SpdyControlFlags { | |
101 CONTROL_FLAG_NONE = 0x00, | |
102 CONTROL_FLAG_FIN = 0x01, | |
103 CONTROL_FLAG_UNIDIRECTIONAL = 0x02, | |
104 }; | |
105 | |
106 enum SpdyPingFlags { | |
107 PING_FLAG_ACK = 0x01, | |
108 }; | |
109 | |
110 // Used by HEADERS, PUSH_PROMISE, and CONTINUATION. | |
111 enum SpdyHeadersFlags { | |
112 HEADERS_FLAG_END_HEADERS = 0x04, | |
113 HEADERS_FLAG_PADDED = 0x08, | |
114 HEADERS_FLAG_PRIORITY = 0x20, | |
115 }; | |
116 | |
117 enum SpdyPushPromiseFlags { | |
118 PUSH_PROMISE_FLAG_END_PUSH_PROMISE = 0x04, | |
119 PUSH_PROMISE_FLAG_PADDED = 0x08, | |
120 }; | |
121 | |
122 // Flags on the SETTINGS control frame. | |
123 enum SpdySettingsControlFlags { | |
124 SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS = 0x01, | |
125 }; | |
126 | |
127 enum Http2SettingsControlFlags { | |
128 SETTINGS_FLAG_ACK = 0x01, | |
129 }; | |
130 | |
131 // Wire values of HTTP/2 setting identifiers. | |
132 enum SpdySettingsIds : uint16_t { | |
133 // HPACK header table maximum size. | |
134 SETTINGS_HEADER_TABLE_SIZE = 0x1, | |
135 SETTINGS_MIN = SETTINGS_HEADER_TABLE_SIZE, | |
136 // Whether or not server push (PUSH_PROMISE) is enabled. | |
137 SETTINGS_ENABLE_PUSH = 0x2, | |
138 // The maximum number of simultaneous live streams in each direction. | |
139 SETTINGS_MAX_CONCURRENT_STREAMS = 0x3, | |
140 // Initial window size in bytes | |
141 SETTINGS_INITIAL_WINDOW_SIZE = 0x4, | |
142 // The size of the largest frame payload that a receiver is willing to accept. | |
143 SETTINGS_MAX_FRAME_SIZE = 0x5, | |
144 // The maximum size of header list that the sender is prepared to accept. | |
145 SETTINGS_MAX_HEADER_LIST_SIZE = 0x6, | |
146 SETTINGS_MAX = SETTINGS_MAX_HEADER_LIST_SIZE | |
147 }; | |
148 | |
149 // This explicit operator is needed, otherwise compiler finds | |
150 // overloaded operator to be ambiguous. | |
151 NET_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, | |
152 SpdySettingsIds id); | |
153 | |
154 // This operator is needed, because SpdyFrameType is an enum class, | |
155 // therefore implicit conversion to underlying integer type is not allowed. | |
156 NET_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, | |
157 SpdyFrameType frame_type); | |
158 | |
159 using SettingsMap = std::map<SpdySettingsIds, uint32_t>; | |
160 | |
161 // HTTP/2 error codes, RFC 7540 Section 7. | |
162 enum SpdyErrorCode : uint32_t { | |
163 ERROR_CODE_NO_ERROR = 0x0, | |
164 ERROR_CODE_PROTOCOL_ERROR = 0x1, | |
165 ERROR_CODE_INTERNAL_ERROR = 0x2, | |
166 ERROR_CODE_FLOW_CONTROL_ERROR = 0x3, | |
167 ERROR_CODE_SETTINGS_TIMEOUT = 0x4, | |
168 ERROR_CODE_STREAM_CLOSED = 0x5, | |
169 ERROR_CODE_FRAME_SIZE_ERROR = 0x6, | |
170 ERROR_CODE_REFUSED_STREAM = 0x7, | |
171 ERROR_CODE_CANCEL = 0x8, | |
172 ERROR_CODE_COMPRESSION_ERROR = 0x9, | |
173 ERROR_CODE_CONNECT_ERROR = 0xa, | |
174 ERROR_CODE_ENHANCE_YOUR_CALM = 0xb, | |
175 ERROR_CODE_INADEQUATE_SECURITY = 0xc, | |
176 ERROR_CODE_HTTP_1_1_REQUIRED = 0xd, | |
177 ERROR_CODE_MAX = ERROR_CODE_HTTP_1_1_REQUIRED | |
178 }; | |
179 | |
180 // A SPDY priority is a number between 0 and 7 (inclusive). | |
181 typedef uint8_t SpdyPriority; | |
182 | |
183 // Lowest and Highest here refer to SPDY priorities as described in | |
184 | |
185 // https://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1#TOC-2.3.3-
Stream-priority | |
186 const SpdyPriority kV3HighestPriority = 0; | |
187 const SpdyPriority kV3LowestPriority = 7; | |
188 | |
189 // Returns SPDY 3.x priority value clamped to the valid range of [0, 7]. | |
190 NET_EXPORT_PRIVATE SpdyPriority ClampSpdy3Priority(SpdyPriority priority); | |
191 | |
192 // HTTP/2 stream weights are integers in range [1, 256], as specified in RFC | |
193 // 7540 section 5.3.2. Default stream weight is defined in section 5.3.5. | |
194 const int kHttp2MinStreamWeight = 1; | |
195 const int kHttp2MaxStreamWeight = 256; | |
196 const int kHttp2DefaultStreamWeight = 16; | |
197 | |
198 // Returns HTTP/2 weight clamped to the valid range of [1, 256]. | |
199 NET_EXPORT_PRIVATE int ClampHttp2Weight(int weight); | |
200 | |
201 // Maps SPDY 3.x priority value in range [0, 7] to HTTP/2 weight value in range | |
202 // [1, 256], where priority 0 (i.e. highest precedence) corresponds to maximum | |
203 // weight 256 and priority 7 (lowest precedence) corresponds to minimum weight | |
204 // 1. | |
205 NET_EXPORT_PRIVATE int Spdy3PriorityToHttp2Weight(SpdyPriority priority); | |
206 | |
207 // Maps HTTP/2 weight value in range [1, 256] to SPDY 3.x priority value in | |
208 // range [0, 7], where minimum weight 1 corresponds to priority 7 (lowest | |
209 // precedence) and maximum weight 256 corresponds to priority 0 (highest | |
210 // precedence). | |
211 NET_EXPORT_PRIVATE SpdyPriority Http2WeightToSpdy3Priority(int weight); | |
212 | |
213 // Reserved ID for root stream of HTTP/2 stream dependency tree, as specified | |
214 // in RFC 7540 section 5.3.1. | |
215 const unsigned int kHttp2RootStreamId = 0; | |
216 | |
217 typedef uint64_t SpdyPingId; | |
218 | |
219 // Returns true if a given on-the-wire enumeration of a frame type is defined | |
220 // in a standardized HTTP/2 specification, false otherwise. | |
221 NET_EXPORT_PRIVATE bool IsDefinedFrameType(uint8_t frame_type_field); | |
222 | |
223 // Parses a frame type from an on-the-wire enumeration. | |
224 // Behavior is undefined for invalid frame type fields; consumers should first | |
225 // use IsValidFrameType() to verify validity of frame type fields. | |
226 NET_EXPORT_PRIVATE SpdyFrameType ParseFrameType(uint8_t frame_type_field); | |
227 | |
228 // Serializes a frame type to the on-the-wire value. | |
229 NET_EXPORT_PRIVATE uint8_t SerializeFrameType(SpdyFrameType frame_type); | |
230 | |
231 // (HTTP/2) All standard frame types except WINDOW_UPDATE are | |
232 // (stream-specific xor connection-level). Returns false iff we know | |
233 // the given frame type does not align with the given streamID. | |
234 NET_EXPORT_PRIVATE bool IsValidHTTP2FrameStreamId( | |
235 SpdyStreamId current_frame_stream_id, | |
236 SpdyFrameType frame_type_field); | |
237 | |
238 // Serialize |frame_type| to string for logging/debugging. | |
239 const char* FrameTypeToString(SpdyFrameType frame_type); | |
240 | |
241 // If |wire_setting_id| is the on-the-wire representation of a defined SETTINGS | |
242 // parameter, parse it to |*setting_id| and return true. | |
243 NET_EXPORT_PRIVATE bool ParseSettingsId(uint16_t wire_setting_id, | |
244 SpdySettingsIds* setting_id); | |
245 | |
246 // Return if |id| corresponds to a defined setting; | |
247 // stringify |id| to |*settings_id_string| regardless. | |
248 NET_EXPORT_PRIVATE bool SettingsIdToString(SpdySettingsIds id, | |
249 const char** settings_id_string); | |
250 | |
251 // Parse |wire_error_code| to a SpdyErrorCode. | |
252 // Treat unrecognized error codes as INTERNAL_ERROR | |
253 // as recommended by the HTTP/2 specification. | |
254 NET_EXPORT_PRIVATE SpdyErrorCode ParseErrorCode(uint32_t wire_error_code); | |
255 | |
256 // Serialize RST_STREAM or GOAWAY frame error code to string | |
257 // for logging/debugging. | |
258 const char* ErrorCodeToString(SpdyErrorCode error_code); | |
259 | |
260 // Number of octets in the frame header. | |
261 const size_t kFrameHeaderSize = 9; | |
262 // Size, in bytes, of the data frame header. | |
263 const size_t kDataFrameMinimumSize = kFrameHeaderSize; | |
264 // Maximum possible configurable size of a frame in octets. | |
265 const size_t kMaxFrameSizeLimit = kSpdyMaxFrameSizeLimit + kFrameHeaderSize; | |
266 // Size of a header block size field. Valid only for SPDY 3. | |
267 const size_t kSizeOfSizeField = sizeof(uint32_t); | |
268 // Per-header overhead for block size accounting in bytes. | |
269 const size_t kPerHeaderOverhead = 32; | |
270 // Initial window size for a stream in bytes. | |
271 const int32_t kInitialStreamWindowSize = 64 * 1024 - 1; | |
272 // Initial window size for a session in bytes. | |
273 const int32_t kInitialSessionWindowSize = 64 * 1024 - 1; | |
274 // The NPN string for HTTP2, "h2". | |
275 extern const char* const kHttp2Npn; | |
276 | |
277 // Variant type (i.e. tagged union) that is either a SPDY 3.x priority value, | |
278 // or else an HTTP/2 stream dependency tuple {parent stream ID, weight, | |
279 // exclusive bit}. Templated to allow for use by QUIC code; SPDY and HTTP/2 | |
280 // code should use the concrete type instantiation SpdyStreamPrecedence. | |
281 template <typename StreamIdType> | |
282 class StreamPrecedence { | |
283 public: | |
284 // Constructs instance that is a SPDY 3.x priority. Clamps priority value to | |
285 // the valid range [0, 7]. | |
286 explicit StreamPrecedence(SpdyPriority priority) | |
287 : is_spdy3_priority_(true), | |
288 spdy3_priority_(ClampSpdy3Priority(priority)) {} | |
289 | |
290 // Constructs instance that is an HTTP/2 stream weight, parent stream ID, and | |
291 // exclusive bit. Clamps stream weight to the valid range [1, 256]. | |
292 StreamPrecedence(StreamIdType parent_id, int weight, bool is_exclusive) | |
293 : is_spdy3_priority_(false), | |
294 http2_stream_dependency_{parent_id, ClampHttp2Weight(weight), | |
295 is_exclusive} {} | |
296 | |
297 // Intentionally copyable, to support pass by value. | |
298 StreamPrecedence(const StreamPrecedence& other) = default; | |
299 StreamPrecedence& operator=(const StreamPrecedence& other) = default; | |
300 | |
301 // Returns true if this instance is a SPDY 3.x priority, or false if this | |
302 // instance is an HTTP/2 stream dependency. | |
303 bool is_spdy3_priority() const { return is_spdy3_priority_; } | |
304 | |
305 // Returns SPDY 3.x priority value. If |is_spdy3_priority()| is true, this is | |
306 // the value provided at construction, clamped to the legal priority | |
307 // range. Otherwise, it is the HTTP/2 stream weight mapped to a SPDY 3.x | |
308 // priority value, where minimum weight 1 corresponds to priority 7 (lowest | |
309 // precedence) and maximum weight 256 corresponds to priority 0 (highest | |
310 // precedence). | |
311 SpdyPriority spdy3_priority() const { | |
312 return is_spdy3_priority_ | |
313 ? spdy3_priority_ | |
314 : Http2WeightToSpdy3Priority(http2_stream_dependency_.weight); | |
315 } | |
316 | |
317 // Returns HTTP/2 parent stream ID. If |is_spdy3_priority()| is false, this is | |
318 // the value provided at construction, otherwise it is |kHttp2RootStreamId|. | |
319 StreamIdType parent_id() const { | |
320 return is_spdy3_priority_ ? kHttp2RootStreamId | |
321 : http2_stream_dependency_.parent_id; | |
322 } | |
323 | |
324 // Returns HTTP/2 stream weight. If |is_spdy3_priority()| is false, this is | |
325 // the value provided at construction, clamped to the legal weight | |
326 // range. Otherwise, it is the SPDY 3.x priority value mapped to an HTTP/2 | |
327 // stream weight, where priority 0 (i.e. highest precedence) corresponds to | |
328 // maximum weight 256 and priority 7 (lowest precedence) corresponds to | |
329 // minimum weight 1. | |
330 int weight() const { | |
331 return is_spdy3_priority_ ? Spdy3PriorityToHttp2Weight(spdy3_priority_) | |
332 : http2_stream_dependency_.weight; | |
333 } | |
334 | |
335 // Returns HTTP/2 parent stream exclusivity. If |is_spdy3_priority()| is | |
336 // false, this is the value provided at construction, otherwise it is false. | |
337 bool is_exclusive() const { | |
338 return !is_spdy3_priority_ && http2_stream_dependency_.is_exclusive; | |
339 } | |
340 | |
341 // Facilitates test assertions. | |
342 bool operator==(const StreamPrecedence& other) const { | |
343 if (is_spdy3_priority()) { | |
344 return other.is_spdy3_priority() && | |
345 (spdy3_priority() == other.spdy3_priority()); | |
346 } else { | |
347 return !other.is_spdy3_priority() && (parent_id() == other.parent_id()) && | |
348 (weight() == other.weight()) && | |
349 (is_exclusive() == other.is_exclusive()); | |
350 } | |
351 } | |
352 | |
353 bool operator!=(const StreamPrecedence& other) const { | |
354 return !(*this == other); | |
355 } | |
356 | |
357 private: | |
358 struct Http2StreamDependency { | |
359 StreamIdType parent_id; | |
360 int weight; | |
361 bool is_exclusive; | |
362 }; | |
363 | |
364 bool is_spdy3_priority_; | |
365 union { | |
366 SpdyPriority spdy3_priority_; | |
367 Http2StreamDependency http2_stream_dependency_; | |
368 }; | |
369 }; | |
370 | |
371 typedef StreamPrecedence<SpdyStreamId> SpdyStreamPrecedence; | |
372 | |
373 class SpdyFrameVisitor; | |
374 | |
375 // Intermediate representation for HTTP2 frames. | |
376 class NET_EXPORT_PRIVATE SpdyFrameIR { | |
377 public: | |
378 virtual ~SpdyFrameIR() {} | |
379 | |
380 virtual void Visit(SpdyFrameVisitor* visitor) const = 0; | |
381 virtual SpdyFrameType frame_type() const = 0; | |
382 | |
383 protected: | |
384 SpdyFrameIR() {} | |
385 | |
386 private: | |
387 DISALLOW_COPY_AND_ASSIGN(SpdyFrameIR); | |
388 }; | |
389 | |
390 // Abstract class intended to be inherited by IRs that have a stream associated | |
391 // to them. | |
392 class NET_EXPORT_PRIVATE SpdyFrameWithStreamIdIR : public SpdyFrameIR { | |
393 public: | |
394 ~SpdyFrameWithStreamIdIR() override {} | |
395 SpdyStreamId stream_id() const { return stream_id_; } | |
396 void set_stream_id(SpdyStreamId stream_id) { | |
397 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); | |
398 stream_id_ = stream_id; | |
399 } | |
400 | |
401 protected: | |
402 explicit SpdyFrameWithStreamIdIR(SpdyStreamId stream_id) { | |
403 set_stream_id(stream_id); | |
404 } | |
405 | |
406 private: | |
407 SpdyStreamId stream_id_; | |
408 | |
409 DISALLOW_COPY_AND_ASSIGN(SpdyFrameWithStreamIdIR); | |
410 }; | |
411 | |
412 // Abstract class intended to be inherited by IRs that have the option of a FIN | |
413 // flag. Implies SpdyFrameWithStreamIdIR. | |
414 class NET_EXPORT_PRIVATE SpdyFrameWithFinIR : public SpdyFrameWithStreamIdIR { | |
415 public: | |
416 ~SpdyFrameWithFinIR() override {} | |
417 bool fin() const { return fin_; } | |
418 void set_fin(bool fin) { fin_ = fin; } | |
419 | |
420 protected: | |
421 explicit SpdyFrameWithFinIR(SpdyStreamId stream_id) | |
422 : SpdyFrameWithStreamIdIR(stream_id), | |
423 fin_(false) {} | |
424 | |
425 private: | |
426 bool fin_; | |
427 | |
428 DISALLOW_COPY_AND_ASSIGN(SpdyFrameWithFinIR); | |
429 }; | |
430 | |
431 // Abstract class intended to be inherited by IRs that contain a header | |
432 // block. Implies SpdyFrameWithFinIR. | |
433 class NET_EXPORT_PRIVATE SpdyFrameWithHeaderBlockIR | |
434 : public NON_EXPORTED_BASE(SpdyFrameWithFinIR) { | |
435 public: | |
436 ~SpdyFrameWithHeaderBlockIR() override; | |
437 | |
438 const SpdyHeaderBlock& header_block() const { return header_block_; } | |
439 void set_header_block(SpdyHeaderBlock header_block) { | |
440 // Deep copy. | |
441 header_block_ = std::move(header_block); | |
442 } | |
443 void SetHeader(SpdyStringPiece name, SpdyStringPiece value) { | |
444 header_block_[name] = value; | |
445 } | |
446 bool end_headers() const { return end_headers_; } | |
447 void set_end_headers(bool end_headers) { end_headers_ = end_headers; } | |
448 | |
449 protected: | |
450 SpdyFrameWithHeaderBlockIR(SpdyStreamId stream_id, | |
451 SpdyHeaderBlock header_block); | |
452 | |
453 private: | |
454 SpdyHeaderBlock header_block_; | |
455 bool end_headers_ = false; | |
456 | |
457 DISALLOW_COPY_AND_ASSIGN(SpdyFrameWithHeaderBlockIR); | |
458 }; | |
459 | |
460 class NET_EXPORT_PRIVATE SpdyDataIR | |
461 : public NON_EXPORTED_BASE(SpdyFrameWithFinIR) { | |
462 public: | |
463 // Performs a deep copy on data. | |
464 SpdyDataIR(SpdyStreamId stream_id, SpdyStringPiece data); | |
465 | |
466 // Performs a deep copy on data. | |
467 SpdyDataIR(SpdyStreamId stream_id, const char* data); | |
468 | |
469 // Moves data into data_store_. Makes a copy if passed a non-movable string. | |
470 SpdyDataIR(SpdyStreamId stream_id, SpdyString data); | |
471 | |
472 // Use in conjunction with SetDataShallow() for shallow-copy on data. | |
473 explicit SpdyDataIR(SpdyStreamId stream_id); | |
474 | |
475 ~SpdyDataIR() override; | |
476 | |
477 const char* data() const { return data_; } | |
478 size_t data_len() const { return data_len_; } | |
479 | |
480 bool padded() const { return padded_; } | |
481 | |
482 int padding_payload_len() const { return padding_payload_len_; } | |
483 | |
484 void set_padding_len(int padding_len) { | |
485 DCHECK_GT(padding_len, 0); | |
486 DCHECK_LE(padding_len, kPaddingSizePerFrame); | |
487 padded_ = true; | |
488 // The pad field takes one octet on the wire. | |
489 padding_payload_len_ = padding_len - 1; | |
490 } | |
491 | |
492 // Deep-copy of data (keep private copy). | |
493 void SetDataDeep(SpdyStringPiece data) { | |
494 data_store_.reset(new SpdyString(data.data(), data.size())); | |
495 data_ = data_store_->data(); | |
496 data_len_ = data.size(); | |
497 } | |
498 | |
499 // Shallow-copy of data (do not keep private copy). | |
500 void SetDataShallow(SpdyStringPiece data) { | |
501 data_store_.reset(); | |
502 data_ = data.data(); | |
503 data_len_ = data.size(); | |
504 } | |
505 | |
506 // Use this method if we don't have a contiguous buffer and only | |
507 // need a length. | |
508 void SetDataShallow(size_t len) { | |
509 data_store_.reset(); | |
510 data_ = nullptr; | |
511 data_len_ = len; | |
512 } | |
513 | |
514 void Visit(SpdyFrameVisitor* visitor) const override; | |
515 | |
516 SpdyFrameType frame_type() const override; | |
517 | |
518 private: | |
519 // Used to store data that this SpdyDataIR should own. | |
520 std::unique_ptr<SpdyString> data_store_; | |
521 const char* data_; | |
522 size_t data_len_; | |
523 | |
524 bool padded_; | |
525 // padding_payload_len_ = desired padding length - len(padding length field). | |
526 int padding_payload_len_; | |
527 | |
528 DISALLOW_COPY_AND_ASSIGN(SpdyDataIR); | |
529 }; | |
530 | |
531 class NET_EXPORT_PRIVATE SpdyRstStreamIR : public SpdyFrameWithStreamIdIR { | |
532 public: | |
533 SpdyRstStreamIR(SpdyStreamId stream_id, SpdyErrorCode error_code); | |
534 | |
535 ~SpdyRstStreamIR() override; | |
536 | |
537 SpdyErrorCode error_code() const { return error_code_; } | |
538 void set_error_code(SpdyErrorCode error_code) { error_code_ = error_code; } | |
539 | |
540 void Visit(SpdyFrameVisitor* visitor) const override; | |
541 | |
542 SpdyFrameType frame_type() const override; | |
543 | |
544 private: | |
545 SpdyErrorCode error_code_; | |
546 | |
547 DISALLOW_COPY_AND_ASSIGN(SpdyRstStreamIR); | |
548 }; | |
549 | |
550 class NET_EXPORT_PRIVATE SpdySettingsIR : public SpdyFrameIR { | |
551 public: | |
552 SpdySettingsIR(); | |
553 ~SpdySettingsIR() override; | |
554 | |
555 // Overwrites as appropriate. | |
556 const SettingsMap& values() const { return values_; } | |
557 void AddSetting(SpdySettingsIds id, int32_t value) { values_[id] = value; } | |
558 | |
559 bool is_ack() const { return is_ack_; } | |
560 void set_is_ack(bool is_ack) { | |
561 is_ack_ = is_ack; | |
562 } | |
563 | |
564 void Visit(SpdyFrameVisitor* visitor) const override; | |
565 | |
566 SpdyFrameType frame_type() const override; | |
567 | |
568 private: | |
569 SettingsMap values_; | |
570 bool is_ack_; | |
571 | |
572 DISALLOW_COPY_AND_ASSIGN(SpdySettingsIR); | |
573 }; | |
574 | |
575 class NET_EXPORT_PRIVATE SpdyPingIR : public SpdyFrameIR { | |
576 public: | |
577 explicit SpdyPingIR(SpdyPingId id) : id_(id), is_ack_(false) {} | |
578 SpdyPingId id() const { return id_; } | |
579 | |
580 bool is_ack() const { return is_ack_; } | |
581 void set_is_ack(bool is_ack) { is_ack_ = is_ack; } | |
582 | |
583 void Visit(SpdyFrameVisitor* visitor) const override; | |
584 | |
585 SpdyFrameType frame_type() const override; | |
586 | |
587 private: | |
588 SpdyPingId id_; | |
589 bool is_ack_; | |
590 | |
591 DISALLOW_COPY_AND_ASSIGN(SpdyPingIR); | |
592 }; | |
593 | |
594 class NET_EXPORT_PRIVATE SpdyGoAwayIR : public SpdyFrameIR { | |
595 public: | |
596 // References description, doesn't copy it, so description must outlast | |
597 // this SpdyGoAwayIR. | |
598 SpdyGoAwayIR(SpdyStreamId last_good_stream_id, | |
599 SpdyErrorCode error_code, | |
600 SpdyStringPiece description); | |
601 | |
602 // References description, doesn't copy it, so description must outlast | |
603 // this SpdyGoAwayIR. | |
604 SpdyGoAwayIR(SpdyStreamId last_good_stream_id, | |
605 SpdyErrorCode error_code, | |
606 const char* description); | |
607 | |
608 // Moves description into description_store_, so caller doesn't need to | |
609 // keep description live after constructing this SpdyGoAwayIR. | |
610 SpdyGoAwayIR(SpdyStreamId last_good_stream_id, | |
611 SpdyErrorCode error_code, | |
612 SpdyString description); | |
613 | |
614 ~SpdyGoAwayIR() override; | |
615 SpdyStreamId last_good_stream_id() const { return last_good_stream_id_; } | |
616 void set_last_good_stream_id(SpdyStreamId last_good_stream_id) { | |
617 DCHECK_EQ(0u, last_good_stream_id & ~kStreamIdMask); | |
618 last_good_stream_id_ = last_good_stream_id; | |
619 } | |
620 SpdyErrorCode error_code() const { return error_code_; } | |
621 void set_error_code(SpdyErrorCode error_code) { | |
622 // TODO(hkhalil): Check valid ranges of error_code? | |
623 error_code_ = error_code; | |
624 } | |
625 | |
626 const SpdyStringPiece& description() const { return description_; } | |
627 | |
628 void Visit(SpdyFrameVisitor* visitor) const override; | |
629 | |
630 SpdyFrameType frame_type() const override; | |
631 | |
632 private: | |
633 SpdyStreamId last_good_stream_id_; | |
634 SpdyErrorCode error_code_; | |
635 const SpdyString description_store_; | |
636 const SpdyStringPiece description_; | |
637 | |
638 DISALLOW_COPY_AND_ASSIGN(SpdyGoAwayIR); | |
639 }; | |
640 | |
641 class NET_EXPORT_PRIVATE SpdyHeadersIR : public SpdyFrameWithHeaderBlockIR { | |
642 public: | |
643 explicit SpdyHeadersIR(SpdyStreamId stream_id) | |
644 : SpdyHeadersIR(stream_id, SpdyHeaderBlock()) {} | |
645 SpdyHeadersIR(SpdyStreamId stream_id, SpdyHeaderBlock header_block) | |
646 : SpdyFrameWithHeaderBlockIR(stream_id, std::move(header_block)) {} | |
647 | |
648 void Visit(SpdyFrameVisitor* visitor) const override; | |
649 | |
650 SpdyFrameType frame_type() const override; | |
651 | |
652 bool has_priority() const { return has_priority_; } | |
653 void set_has_priority(bool has_priority) { has_priority_ = has_priority; } | |
654 int weight() const { return weight_; } | |
655 void set_weight(int weight) { weight_ = weight; } | |
656 SpdyStreamId parent_stream_id() const { return parent_stream_id_; } | |
657 void set_parent_stream_id(SpdyStreamId id) { parent_stream_id_ = id; } | |
658 bool exclusive() const { return exclusive_; } | |
659 void set_exclusive(bool exclusive) { exclusive_ = exclusive; } | |
660 bool padded() const { return padded_; } | |
661 int padding_payload_len() const { return padding_payload_len_; } | |
662 void set_padding_len(int padding_len) { | |
663 DCHECK_GT(padding_len, 0); | |
664 DCHECK_LE(padding_len, kPaddingSizePerFrame); | |
665 padded_ = true; | |
666 // The pad field takes one octet on the wire. | |
667 padding_payload_len_ = padding_len - 1; | |
668 } | |
669 | |
670 private: | |
671 bool has_priority_ = false; | |
672 int weight_ = kHttp2DefaultStreamWeight; | |
673 SpdyStreamId parent_stream_id_ = 0; | |
674 bool exclusive_ = false; | |
675 bool padded_ = false; | |
676 int padding_payload_len_ = 0; | |
677 | |
678 DISALLOW_COPY_AND_ASSIGN(SpdyHeadersIR); | |
679 }; | |
680 | |
681 class NET_EXPORT_PRIVATE SpdyWindowUpdateIR : public SpdyFrameWithStreamIdIR { | |
682 public: | |
683 SpdyWindowUpdateIR(SpdyStreamId stream_id, int32_t delta) | |
684 : SpdyFrameWithStreamIdIR(stream_id) { | |
685 set_delta(delta); | |
686 } | |
687 int32_t delta() const { return delta_; } | |
688 void set_delta(int32_t delta) { | |
689 DCHECK_LE(0, delta); | |
690 DCHECK_LE(delta, kSpdyMaximumWindowSize); | |
691 delta_ = delta; | |
692 } | |
693 | |
694 void Visit(SpdyFrameVisitor* visitor) const override; | |
695 | |
696 SpdyFrameType frame_type() const override; | |
697 | |
698 private: | |
699 int32_t delta_; | |
700 | |
701 DISALLOW_COPY_AND_ASSIGN(SpdyWindowUpdateIR); | |
702 }; | |
703 | |
704 class NET_EXPORT_PRIVATE SpdyPushPromiseIR : public SpdyFrameWithHeaderBlockIR { | |
705 public: | |
706 SpdyPushPromiseIR(SpdyStreamId stream_id, SpdyStreamId promised_stream_id) | |
707 : SpdyPushPromiseIR(stream_id, promised_stream_id, SpdyHeaderBlock()) {} | |
708 SpdyPushPromiseIR(SpdyStreamId stream_id, | |
709 SpdyStreamId promised_stream_id, | |
710 SpdyHeaderBlock header_block) | |
711 : SpdyFrameWithHeaderBlockIR(stream_id, std::move(header_block)), | |
712 promised_stream_id_(promised_stream_id), | |
713 padded_(false), | |
714 padding_payload_len_(0) {} | |
715 SpdyStreamId promised_stream_id() const { return promised_stream_id_; } | |
716 | |
717 void Visit(SpdyFrameVisitor* visitor) const override; | |
718 | |
719 SpdyFrameType frame_type() const override; | |
720 | |
721 bool padded() const { return padded_; } | |
722 int padding_payload_len() const { return padding_payload_len_; } | |
723 void set_padding_len(int padding_len) { | |
724 DCHECK_GT(padding_len, 0); | |
725 DCHECK_LE(padding_len, kPaddingSizePerFrame); | |
726 padded_ = true; | |
727 // The pad field takes one octet on the wire. | |
728 padding_payload_len_ = padding_len - 1; | |
729 } | |
730 | |
731 private: | |
732 SpdyStreamId promised_stream_id_; | |
733 | |
734 bool padded_; | |
735 int padding_payload_len_; | |
736 | |
737 DISALLOW_COPY_AND_ASSIGN(SpdyPushPromiseIR); | |
738 }; | |
739 | |
740 class NET_EXPORT_PRIVATE SpdyContinuationIR : public SpdyFrameWithStreamIdIR { | |
741 public: | |
742 explicit SpdyContinuationIR(SpdyStreamId stream_id); | |
743 ~SpdyContinuationIR() override; | |
744 | |
745 void Visit(SpdyFrameVisitor* visitor) const override; | |
746 | |
747 SpdyFrameType frame_type() const override; | |
748 | |
749 bool end_headers() const { return end_headers_; } | |
750 void set_end_headers(bool end_headers) {end_headers_ = end_headers;} | |
751 const SpdyString& encoding() const { return *encoding_; } | |
752 void take_encoding(std::unique_ptr<SpdyString> encoding) { | |
753 encoding_ = std::move(encoding); | |
754 } | |
755 | |
756 private: | |
757 std::unique_ptr<SpdyString> encoding_; | |
758 bool end_headers_; | |
759 DISALLOW_COPY_AND_ASSIGN(SpdyContinuationIR); | |
760 }; | |
761 | |
762 class NET_EXPORT_PRIVATE SpdyAltSvcIR : public SpdyFrameWithStreamIdIR { | |
763 public: | |
764 explicit SpdyAltSvcIR(SpdyStreamId stream_id); | |
765 ~SpdyAltSvcIR() override; | |
766 | |
767 SpdyString origin() const { return origin_; } | |
768 const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector() const { | |
769 return altsvc_vector_; | |
770 } | |
771 | |
772 void set_origin(SpdyString origin) { origin_ = std::move(origin); } | |
773 void add_altsvc(const SpdyAltSvcWireFormat::AlternativeService& altsvc) { | |
774 altsvc_vector_.push_back(altsvc); | |
775 } | |
776 | |
777 void Visit(SpdyFrameVisitor* visitor) const override; | |
778 | |
779 SpdyFrameType frame_type() const override; | |
780 | |
781 private: | |
782 SpdyString origin_; | |
783 SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector_; | |
784 DISALLOW_COPY_AND_ASSIGN(SpdyAltSvcIR); | |
785 }; | |
786 | |
787 class NET_EXPORT_PRIVATE SpdyPriorityIR : public SpdyFrameWithStreamIdIR { | |
788 public: | |
789 explicit SpdyPriorityIR(SpdyStreamId stream_id) | |
790 : SpdyFrameWithStreamIdIR(stream_id), | |
791 parent_stream_id_(0), | |
792 weight_(1), | |
793 exclusive_(false) {} | |
794 SpdyPriorityIR(SpdyStreamId stream_id, | |
795 SpdyStreamId parent_stream_id, | |
796 int weight, | |
797 bool exclusive) | |
798 : SpdyFrameWithStreamIdIR(stream_id), | |
799 parent_stream_id_(parent_stream_id), | |
800 weight_(weight), | |
801 exclusive_(exclusive) {} | |
802 SpdyStreamId parent_stream_id() const { return parent_stream_id_; } | |
803 void set_parent_stream_id(SpdyStreamId id) { parent_stream_id_ = id; } | |
804 int weight() const { return weight_; } | |
805 void set_weight(uint8_t weight) { weight_ = weight; } | |
806 bool exclusive() const { return exclusive_; } | |
807 void set_exclusive(bool exclusive) { exclusive_ = exclusive; } | |
808 | |
809 void Visit(SpdyFrameVisitor* visitor) const override; | |
810 | |
811 SpdyFrameType frame_type() const override; | |
812 | |
813 private: | |
814 SpdyStreamId parent_stream_id_; | |
815 int weight_; | |
816 bool exclusive_; | |
817 DISALLOW_COPY_AND_ASSIGN(SpdyPriorityIR); | |
818 }; | |
819 | |
820 class SpdySerializedFrame { | |
821 public: | |
822 SpdySerializedFrame() | |
823 : frame_(const_cast<char*>("")), size_(0), owns_buffer_(false) {} | |
824 | |
825 // Create a valid SpdySerializedFrame using a pre-created buffer. | |
826 // If |owns_buffer| is true, this class takes ownership of the buffer and will | |
827 // delete it on cleanup. The buffer must have been created using new char[]. | |
828 // If |owns_buffer| is false, the caller retains ownership of the buffer and | |
829 // is responsible for making sure the buffer outlives this frame. In other | |
830 // words, this class does NOT create a copy of the buffer. | |
831 SpdySerializedFrame(char* data, size_t size, bool owns_buffer) | |
832 : frame_(data), size_(size), owns_buffer_(owns_buffer) {} | |
833 | |
834 SpdySerializedFrame(SpdySerializedFrame&& other) | |
835 : frame_(other.frame_), | |
836 size_(other.size_), | |
837 owns_buffer_(other.owns_buffer_) { | |
838 // |other| is no longer responsible for the buffer. | |
839 other.owns_buffer_ = false; | |
840 } | |
841 | |
842 SpdySerializedFrame& operator=(SpdySerializedFrame&& other) { | |
843 // Free buffer if necessary. | |
844 if (owns_buffer_) { | |
845 delete[] frame_; | |
846 } | |
847 // Take over |other|. | |
848 frame_ = other.frame_; | |
849 size_ = other.size_; | |
850 owns_buffer_ = other.owns_buffer_; | |
851 // |other| is no longer responsible for the buffer. | |
852 other.owns_buffer_ = false; | |
853 return *this; | |
854 } | |
855 | |
856 ~SpdySerializedFrame() { | |
857 if (owns_buffer_) { | |
858 delete[] frame_; | |
859 } | |
860 } | |
861 | |
862 // Provides access to the frame bytes, which is a buffer containing the frame | |
863 // packed as expected for sending over the wire. | |
864 char* data() const { return frame_; } | |
865 | |
866 // Returns the actual size of the underlying buffer. | |
867 size_t size() const { return size_; } | |
868 | |
869 // Returns a buffer containing the contents of the frame, of which the caller | |
870 // takes ownership, and clears this SpdySerializedFrame. | |
871 char* ReleaseBuffer() { | |
872 char* buffer; | |
873 if (owns_buffer_) { | |
874 // If the buffer is owned, relinquish ownership to the caller. | |
875 buffer = frame_; | |
876 owns_buffer_ = false; | |
877 } else { | |
878 // Otherwise, we need to make a copy to give to the caller. | |
879 buffer = new char[size_]; | |
880 memcpy(buffer, frame_, size_); | |
881 } | |
882 *this = SpdySerializedFrame(); | |
883 return buffer; | |
884 } | |
885 | |
886 // Returns the estimate of dynamically allocated memory in bytes. | |
887 size_t EstimateMemoryUsage() const { return owns_buffer_ ? size_ : 0; } | |
888 | |
889 protected: | |
890 char* frame_; | |
891 | |
892 private: | |
893 size_t size_; | |
894 bool owns_buffer_; | |
895 DISALLOW_COPY_AND_ASSIGN(SpdySerializedFrame); | |
896 }; | |
897 | |
898 // This interface is for classes that want to process SpdyFrameIRs without | |
899 // having to know what type they are. An instance of this interface can be | |
900 // passed to a SpdyFrameIR's Visit method, and the appropriate type-specific | |
901 // method of this class will be called. | |
902 class SpdyFrameVisitor { | |
903 public: | |
904 virtual void VisitRstStream(const SpdyRstStreamIR& rst_stream) = 0; | |
905 virtual void VisitSettings(const SpdySettingsIR& settings) = 0; | |
906 virtual void VisitPing(const SpdyPingIR& ping) = 0; | |
907 virtual void VisitGoAway(const SpdyGoAwayIR& goaway) = 0; | |
908 virtual void VisitHeaders(const SpdyHeadersIR& headers) = 0; | |
909 virtual void VisitWindowUpdate(const SpdyWindowUpdateIR& window_update) = 0; | |
910 virtual void VisitPushPromise(const SpdyPushPromiseIR& push_promise) = 0; | |
911 virtual void VisitContinuation(const SpdyContinuationIR& continuation) = 0; | |
912 virtual void VisitAltSvc(const SpdyAltSvcIR& altsvc) = 0; | |
913 virtual void VisitPriority(const SpdyPriorityIR& priority) = 0; | |
914 virtual void VisitData(const SpdyDataIR& data) = 0; | |
915 | |
916 protected: | |
917 SpdyFrameVisitor() {} | |
918 virtual ~SpdyFrameVisitor() {} | |
919 | |
920 private: | |
921 DISALLOW_COPY_AND_ASSIGN(SpdyFrameVisitor); | |
922 }; | |
923 | |
924 } // namespace net | |
925 | |
926 #endif // NET_SPDY_SPDY_PROTOCOL_H_ | |
OLD | NEW |