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 #ifndef NET_SPDY_SPDY_FRAMER_H_ | |
6 #define NET_SPDY_SPDY_FRAMER_H_ | |
7 | |
8 #include <list> | |
9 #include <map> | |
10 #include <memory> | |
11 #include <string> | |
12 #include <utility> | |
13 #include <vector> | |
14 | |
15 #include "base/basictypes.h" | |
16 #include "base/gtest_prod_util.h" | |
17 #include "base/memory/scoped_ptr.h" | |
18 #include "base/strings/string_piece.h" | |
19 #include "base/sys_byteorder.h" | |
20 #include "net/base/net_export.h" | |
21 #include "net/spdy/hpack_decoder.h" | |
22 #include "net/spdy/hpack_encoder.h" | |
23 #include "net/spdy/spdy_header_block.h" | |
24 #include "net/spdy/spdy_protocol.h" | |
25 | |
26 // TODO(akalin): Remove support for CREDENTIAL frames. | |
27 | |
28 typedef struct z_stream_s z_stream; // Forward declaration for zlib. | |
29 | |
30 namespace net { | |
31 | |
32 class HttpProxyClientSocketPoolTest; | |
33 class HttpNetworkLayer; | |
34 class HttpNetworkTransactionTest; | |
35 class SpdyHttpStreamTest; | |
36 class SpdyNetworkTransactionTest; | |
37 class SpdyProxyClientSocketTest; | |
38 class SpdySessionTest; | |
39 class SpdyStreamTest; | |
40 | |
41 class SpdyFramer; | |
42 class SpdyFrameBuilder; | |
43 class SpdyFramerTest; | |
44 | |
45 namespace test { | |
46 | |
47 class TestSpdyVisitor; | |
48 | |
49 } // namespace test | |
50 | |
51 // A datastructure for holding a set of headers from a HEADERS, PUSH_PROMISE, | |
52 // SYN_STREAM, or SYN_REPLY frame. | |
53 typedef std::map<std::string, std::string> SpdyHeaderBlock; | |
54 | |
55 // A datastructure for holding the ID and flag fields for SETTINGS. | |
56 // Conveniently handles converstion to/from wire format. | |
57 class NET_EXPORT_PRIVATE SettingsFlagsAndId { | |
58 public: | |
59 static SettingsFlagsAndId FromWireFormat(SpdyMajorVersion version, | |
60 uint32 wire); | |
61 | |
62 SettingsFlagsAndId() : flags_(0), id_(0) {} | |
63 | |
64 // TODO(hkhalil): restrict to enums instead of free-form ints. | |
65 SettingsFlagsAndId(uint8 flags, uint32 id); | |
66 | |
67 uint32 GetWireFormat(SpdyMajorVersion version) const; | |
68 | |
69 uint32 id() const { return id_; } | |
70 uint8 flags() const { return flags_; } | |
71 | |
72 private: | |
73 static void ConvertFlagsAndIdForSpdy2(uint32* val); | |
74 | |
75 uint8 flags_; | |
76 uint32 id_; | |
77 }; | |
78 | |
79 // SettingsMap has unique (flags, value) pair for given SpdySettingsIds ID. | |
80 typedef std::pair<SpdySettingsFlags, uint32> SettingsFlagsAndValue; | |
81 typedef std::map<SpdySettingsIds, SettingsFlagsAndValue> SettingsMap; | |
82 | |
83 // Scratch space necessary for processing SETTINGS frames. | |
84 struct NET_EXPORT_PRIVATE SpdySettingsScratch { | |
85 SpdySettingsScratch() { Reset(); } | |
86 | |
87 void Reset() { | |
88 setting_buf_len = 0; | |
89 last_setting_id = -1; | |
90 } | |
91 | |
92 // Buffer contains up to one complete key/value pair. | |
93 char setting_buf[8]; | |
94 | |
95 // The amount of the buffer that is filled with valid data. | |
96 size_t setting_buf_len; | |
97 | |
98 // The ID of the last setting that was processed in the current SETTINGS | |
99 // frame. Used for detecting out-of-order or duplicate keys within a settings | |
100 // frame. Set to -1 before first key/value pair is processed. | |
101 int last_setting_id; | |
102 }; | |
103 | |
104 // Scratch space necessary for processing ALTSVC frames. | |
105 struct NET_EXPORT_PRIVATE SpdyAltSvcScratch { | |
106 SpdyAltSvcScratch(); | |
107 ~SpdyAltSvcScratch(); | |
108 | |
109 void Reset() { | |
110 max_age = 0; | |
111 port = 0; | |
112 pid_len = 0; | |
113 host_len = 0; | |
114 origin_len = 0; | |
115 pid_buf_len = 0; | |
116 host_buf_len = 0; | |
117 origin_buf_len = 0; | |
118 protocol_id.reset(); | |
119 host.reset(); | |
120 origin.reset(); | |
121 } | |
122 | |
123 uint32 max_age; | |
124 uint16 port; | |
125 uint8 pid_len; | |
126 uint8 host_len; | |
127 size_t origin_len; | |
128 size_t pid_buf_len; | |
129 size_t host_buf_len; | |
130 size_t origin_buf_len; | |
131 scoped_ptr<char[]> protocol_id; | |
132 scoped_ptr<char[]> host; | |
133 scoped_ptr<char[]> origin; | |
134 }; | |
135 | |
136 // SpdyFramerVisitorInterface is a set of callbacks for the SpdyFramer. | |
137 // Implement this interface to receive event callbacks as frames are | |
138 // decoded from the framer. | |
139 // | |
140 // Control frames that contain SPDY header blocks (SYN_STREAM, SYN_REPLY, | |
141 // HEADER, and PUSH_PROMISE) are processed in fashion that allows the | |
142 // decompressed header block to be delivered in chunks to the visitor. | |
143 // The following steps are followed: | |
144 // 1. OnSynStream, OnSynReply, OnHeaders, or OnPushPromise is called. | |
145 // 2. Repeated: OnControlFrameHeaderData is called with chunks of the | |
146 // decompressed header block. In each call the len parameter is greater | |
147 // than zero. | |
148 // 3. OnControlFrameHeaderData is called with len set to zero, indicating | |
149 // that the full header block has been delivered for the control frame. | |
150 // During step 2 the visitor may return false, indicating that the chunk of | |
151 // header data could not be handled by the visitor (typically this indicates | |
152 // resource exhaustion). If this occurs the framer will discontinue | |
153 // delivering chunks to the visitor, set a SPDY_CONTROL_PAYLOAD_TOO_LARGE | |
154 // error, and clean up appropriately. Note that this will cause the header | |
155 // decompressor to lose synchronization with the sender's header compressor, | |
156 // making the SPDY session unusable for future work. The visitor's OnError | |
157 // function should deal with this condition by closing the SPDY connection. | |
158 class NET_EXPORT_PRIVATE SpdyFramerVisitorInterface { | |
159 public: | |
160 virtual ~SpdyFramerVisitorInterface() {} | |
161 | |
162 // Called if an error is detected in the SpdyFrame protocol. | |
163 virtual void OnError(SpdyFramer* framer) = 0; | |
164 | |
165 // Called when a data frame header is received. The frame's data | |
166 // payload will be provided via subsequent calls to | |
167 // OnStreamFrameData(). | |
168 virtual void OnDataFrameHeader(SpdyStreamId stream_id, | |
169 size_t length, | |
170 bool fin) = 0; | |
171 | |
172 // Called when data is received. | |
173 // |stream_id| The stream receiving data. | |
174 // |data| A buffer containing the data received. | |
175 // |len| The length of the data buffer. | |
176 // When the other side has finished sending data on this stream, | |
177 // this method will be called with a zero-length buffer. | |
178 virtual void OnStreamFrameData(SpdyStreamId stream_id, | |
179 const char* data, | |
180 size_t len, | |
181 bool fin) = 0; | |
182 | |
183 // Called when a chunk of header data is available. This is called | |
184 // after OnSynStream, OnSynReply, OnHeaders(), or OnPushPromise. | |
185 // |stream_id| The stream receiving the header data. | |
186 // |header_data| A buffer containing the header data chunk received. | |
187 // |len| The length of the header data buffer. A length of zero indicates | |
188 // that the header data block has been completely sent. | |
189 // When this function returns true the visitor indicates that it accepted | |
190 // all of the data. Returning false indicates that that an unrecoverable | |
191 // error has occurred, such as bad header data or resource exhaustion. | |
192 virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id, | |
193 const char* header_data, | |
194 size_t len) = 0; | |
195 | |
196 // Called when a SYN_STREAM frame is received. | |
197 // Note that header block data is not included. See | |
198 // OnControlFrameHeaderData(). | |
199 virtual void OnSynStream(SpdyStreamId stream_id, | |
200 SpdyStreamId associated_stream_id, | |
201 SpdyPriority priority, | |
202 bool fin, | |
203 bool unidirectional) = 0; | |
204 | |
205 // Called when a SYN_REPLY frame is received. | |
206 // Note that header block data is not included. See | |
207 // OnControlFrameHeaderData(). | |
208 virtual void OnSynReply(SpdyStreamId stream_id, bool fin) = 0; | |
209 | |
210 // Called when a RST_STREAM frame has been parsed. | |
211 virtual void OnRstStream(SpdyStreamId stream_id, | |
212 SpdyRstStreamStatus status) = 0; | |
213 | |
214 // Called when a SETTINGS frame is received. | |
215 // |clear_persisted| True if the respective flag is set on the SETTINGS frame. | |
216 virtual void OnSettings(bool clear_persisted) {} | |
217 | |
218 // Called when a complete setting within a SETTINGS frame has been parsed and | |
219 // validated. | |
220 virtual void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) = 0; | |
221 | |
222 // Called when a SETTINGS frame is received with the ACK flag set. | |
223 virtual void OnSettingsAck() {} | |
224 | |
225 // Called before and after parsing SETTINGS id and value tuples. | |
226 virtual void OnSettingsEnd() = 0; | |
227 | |
228 // Called when a PING frame has been parsed. | |
229 virtual void OnPing(SpdyPingId unique_id, bool is_ack) = 0; | |
230 | |
231 // Called when a GOAWAY frame has been parsed. | |
232 virtual void OnGoAway(SpdyStreamId last_accepted_stream_id, | |
233 SpdyGoAwayStatus status) = 0; | |
234 | |
235 // Called when a HEADERS frame is received. | |
236 // Note that header block data is not included. See | |
237 // OnControlFrameHeaderData(). | |
238 virtual void OnHeaders(SpdyStreamId stream_id, | |
239 bool has_priority, | |
240 SpdyPriority priority, | |
241 bool fin, | |
242 bool end) = 0; | |
243 | |
244 // Called when a WINDOW_UPDATE frame has been parsed. | |
245 virtual void OnWindowUpdate(SpdyStreamId stream_id, | |
246 uint32 delta_window_size) = 0; | |
247 | |
248 // Called when a goaway frame opaque data is available. | |
249 // |goaway_data| A buffer containing the opaque GOAWAY data chunk received. | |
250 // |len| The length of the header data buffer. A length of zero indicates | |
251 // that the header data block has been completely sent. | |
252 // When this function returns true the visitor indicates that it accepted | |
253 // all of the data. Returning false indicates that that an error has | |
254 // occurred while processing the data. Default implementation returns true. | |
255 virtual bool OnGoAwayFrameData(const char* goaway_data, size_t len); | |
256 | |
257 // Called when rst_stream frame opaque data is available. | |
258 // |rst_stream_data| A buffer containing the opaque RST_STREAM | |
259 // data chunk received. | |
260 // |len| The length of the header data buffer. A length of zero indicates | |
261 // that the opaque data has been completely sent. | |
262 // When this function returns true the visitor indicates that it accepted | |
263 // all of the data. Returning false indicates that that an error has | |
264 // occurred while processing the data. Default implementation returns true. | |
265 virtual bool OnRstStreamFrameData(const char* rst_stream_data, size_t len); | |
266 | |
267 // Called when a BLOCKED frame has been parsed. | |
268 virtual void OnBlocked(SpdyStreamId stream_id) {} | |
269 | |
270 // Called when a PUSH_PROMISE frame is received. | |
271 // Note that header block data is not included. See | |
272 // OnControlFrameHeaderData(). | |
273 virtual void OnPushPromise(SpdyStreamId stream_id, | |
274 SpdyStreamId promised_stream_id, | |
275 bool end) = 0; | |
276 | |
277 // Called when a CONTINUATION frame is received. | |
278 // Note that header block data is not included. See | |
279 // OnControlFrameHeaderData(). | |
280 virtual void OnContinuation(SpdyStreamId stream_id, bool end) = 0; | |
281 | |
282 // Called when an ALTSVC frame has been parsed. | |
283 virtual void OnAltSvc(SpdyStreamId stream_id, | |
284 uint32 max_age, | |
285 uint16 port, | |
286 base::StringPiece protocol_id, | |
287 base::StringPiece host, | |
288 base::StringPiece origin) {} | |
289 | |
290 // Called when a PRIORITY frame is received. | |
291 virtual void OnPriority(SpdyStreamId stream_id, | |
292 SpdyStreamId parent_stream_id, | |
293 uint8 weight, | |
294 bool exclusive) {} | |
295 | |
296 // Called when a frame type we don't recognize is received. | |
297 // Return true if this appears to be a valid extension frame, false otherwise. | |
298 // We distinguish between extension frames and nonsense by checking | |
299 // whether the stream id is valid. | |
300 virtual bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) = 0; | |
301 }; | |
302 | |
303 // Optionally, and in addition to SpdyFramerVisitorInterface, a class supporting | |
304 // SpdyFramerDebugVisitorInterface may be used in conjunction with SpdyFramer in | |
305 // order to extract debug/internal information about the SpdyFramer as it | |
306 // operates. | |
307 // | |
308 // Most SPDY implementations need not bother with this interface at all. | |
309 class NET_EXPORT_PRIVATE SpdyFramerDebugVisitorInterface { | |
310 public: | |
311 virtual ~SpdyFramerDebugVisitorInterface() {} | |
312 | |
313 // Called after compressing a frame with a payload of | |
314 // a list of name-value pairs. | |
315 // |payload_len| is the uncompressed payload size. | |
316 // |frame_len| is the compressed frame size. | |
317 virtual void OnSendCompressedFrame(SpdyStreamId stream_id, | |
318 SpdyFrameType type, | |
319 size_t payload_len, | |
320 size_t frame_len) {} | |
321 | |
322 // Called when a frame containing a compressed payload of | |
323 // name-value pairs is received. | |
324 // |frame_len| is the compressed frame size. | |
325 virtual void OnReceiveCompressedFrame(SpdyStreamId stream_id, | |
326 SpdyFrameType type, | |
327 size_t frame_len) {} | |
328 }; | |
329 | |
330 class NET_EXPORT_PRIVATE SpdyFramer { | |
331 public: | |
332 // SPDY states. | |
333 // TODO(mbelshe): Can we move these into the implementation | |
334 // and avoid exposing through the header. (Needed for test) | |
335 enum SpdyState { | |
336 SPDY_ERROR, | |
337 SPDY_RESET, | |
338 SPDY_AUTO_RESET, | |
339 SPDY_READING_COMMON_HEADER, | |
340 SPDY_CONTROL_FRAME_PAYLOAD, | |
341 SPDY_READ_DATA_FRAME_PADDING_LENGTH, | |
342 SPDY_CONSUME_PADDING, | |
343 SPDY_IGNORE_REMAINING_PAYLOAD, | |
344 SPDY_FORWARD_STREAM_FRAME, | |
345 SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK, | |
346 SPDY_CONTROL_FRAME_HEADER_BLOCK, | |
347 SPDY_GOAWAY_FRAME_PAYLOAD, | |
348 SPDY_RST_STREAM_FRAME_PAYLOAD, | |
349 SPDY_SETTINGS_FRAME_PAYLOAD, | |
350 SPDY_ALTSVC_FRAME_PAYLOAD, | |
351 }; | |
352 | |
353 // SPDY error codes. | |
354 enum SpdyError { | |
355 SPDY_NO_ERROR, | |
356 SPDY_INVALID_CONTROL_FRAME, // Control frame is mal-formatted. | |
357 SPDY_CONTROL_PAYLOAD_TOO_LARGE, // Control frame payload was too large. | |
358 SPDY_ZLIB_INIT_FAILURE, // The Zlib library could not initialize. | |
359 SPDY_UNSUPPORTED_VERSION, // Control frame has unsupported version. | |
360 SPDY_DECOMPRESS_FAILURE, // There was an error decompressing. | |
361 SPDY_COMPRESS_FAILURE, // There was an error compressing. | |
362 SPDY_GOAWAY_FRAME_CORRUPT, // GOAWAY frame could not be parsed. | |
363 SPDY_RST_STREAM_FRAME_CORRUPT, // RST_STREAM frame could not be parsed. | |
364 SPDY_INVALID_DATA_FRAME_FLAGS, // Data frame has invalid flags. | |
365 SPDY_INVALID_CONTROL_FRAME_FLAGS, // Control frame has invalid flags. | |
366 SPDY_UNEXPECTED_FRAME, // Frame received out of order. | |
367 | |
368 LAST_ERROR, // Must be the last entry in the enum. | |
369 }; | |
370 | |
371 // Constant for invalid (or unknown) stream IDs. | |
372 static const SpdyStreamId kInvalidStream; | |
373 | |
374 // The maximum size of header data chunks delivered to the framer visitor | |
375 // through OnControlFrameHeaderData. (It is exposed here for unit test | |
376 // purposes.) | |
377 static const size_t kHeaderDataChunkMaxSize; | |
378 | |
379 // Serializes a SpdyHeaderBlock. | |
380 static void WriteHeaderBlock(SpdyFrameBuilder* frame, | |
381 const SpdyMajorVersion spdy_version, | |
382 const SpdyHeaderBlock* headers); | |
383 | |
384 // Retrieve serialized length of SpdyHeaderBlock. | |
385 // TODO(hkhalil): Remove, or move to quic code. | |
386 static size_t GetSerializedLength( | |
387 const SpdyMajorVersion spdy_version, | |
388 const SpdyHeaderBlock* headers); | |
389 | |
390 // Create a new Framer, provided a SPDY version. | |
391 explicit SpdyFramer(SpdyMajorVersion version); | |
392 virtual ~SpdyFramer(); | |
393 | |
394 // Set callbacks to be called from the framer. A visitor must be set, or | |
395 // else the framer will likely crash. It is acceptable for the visitor | |
396 // to do nothing. If this is called multiple times, only the last visitor | |
397 // will be used. | |
398 void set_visitor(SpdyFramerVisitorInterface* visitor) { | |
399 visitor_ = visitor; | |
400 } | |
401 | |
402 // Set debug callbacks to be called from the framer. The debug visitor is | |
403 // completely optional and need not be set in order for normal operation. | |
404 // If this is called multiple times, only the last visitor will be used. | |
405 void set_debug_visitor(SpdyFramerDebugVisitorInterface* debug_visitor) { | |
406 debug_visitor_ = debug_visitor; | |
407 } | |
408 | |
409 // Pass data into the framer for parsing. | |
410 // Returns the number of bytes consumed. It is safe to pass more bytes in | |
411 // than may be consumed. | |
412 size_t ProcessInput(const char* data, size_t len); | |
413 | |
414 // Resets the framer state after a frame has been successfully decoded. | |
415 // TODO(mbelshe): can we make this private? | |
416 void Reset(); | |
417 | |
418 // Check the state of the framer. | |
419 SpdyError error_code() const { return error_code_; } | |
420 SpdyState state() const { return state_; } | |
421 bool HasError() const { return state_ == SPDY_ERROR; } | |
422 | |
423 // Given a buffer containing a decompressed header block in SPDY | |
424 // serialized format, parse out a SpdyHeaderBlock, putting the results | |
425 // in the given header block. | |
426 // Returns number of bytes consumed if successfully parsed, 0 otherwise. | |
427 size_t ParseHeaderBlockInBuffer(const char* header_data, | |
428 size_t header_length, | |
429 SpdyHeaderBlock* block) const; | |
430 | |
431 // Serialize a data frame. | |
432 SpdySerializedFrame* SerializeData(const SpdyDataIR& data) const; | |
433 // Serializes the data frame header and optionally padding length fields, | |
434 // excluding actual data payload and padding. | |
435 SpdySerializedFrame* SerializeDataFrameHeaderWithPaddingLengthField( | |
436 const SpdyDataIR& data) const; | |
437 | |
438 // Serializes a SYN_STREAM frame. | |
439 SpdySerializedFrame* SerializeSynStream(const SpdySynStreamIR& syn_stream); | |
440 | |
441 // Serialize a SYN_REPLY SpdyFrame. | |
442 SpdySerializedFrame* SerializeSynReply(const SpdySynReplyIR& syn_reply); | |
443 | |
444 SpdySerializedFrame* SerializeRstStream( | |
445 const SpdyRstStreamIR& rst_stream) const; | |
446 | |
447 // Serializes a SETTINGS frame. The SETTINGS frame is | |
448 // used to communicate name/value pairs relevant to the communication channel. | |
449 SpdySerializedFrame* SerializeSettings(const SpdySettingsIR& settings) const; | |
450 | |
451 // Serializes a PING frame. The unique_id is used to | |
452 // identify the ping request/response. | |
453 SpdySerializedFrame* SerializePing(const SpdyPingIR& ping) const; | |
454 | |
455 // Serializes a GOAWAY frame. The GOAWAY frame is used | |
456 // prior to the shutting down of the TCP connection, and includes the | |
457 // stream_id of the last stream the sender of the frame is willing to process | |
458 // to completion. | |
459 SpdySerializedFrame* SerializeGoAway(const SpdyGoAwayIR& goaway) const; | |
460 | |
461 // Serializes a HEADERS frame. The HEADERS frame is used | |
462 // for sending additional headers outside of a SYN_STREAM/SYN_REPLY. | |
463 SpdySerializedFrame* SerializeHeaders(const SpdyHeadersIR& headers); | |
464 | |
465 // Serializes a WINDOW_UPDATE frame. The WINDOW_UPDATE | |
466 // frame is used to implement per stream flow control in SPDY. | |
467 SpdySerializedFrame* SerializeWindowUpdate( | |
468 const SpdyWindowUpdateIR& window_update) const; | |
469 | |
470 // Serializes a BLOCKED frame. The BLOCKED frame is used to | |
471 // indicate to the remote endpoint that this endpoint believes itself to be | |
472 // flow-control blocked but otherwise ready to send data. The BLOCKED frame | |
473 // is purely advisory and optional. | |
474 SpdySerializedFrame* SerializeBlocked(const SpdyBlockedIR& blocked) const; | |
475 | |
476 // Serializes a PUSH_PROMISE frame. The PUSH_PROMISE frame is used | |
477 // to inform the client that it will be receiving an additional stream | |
478 // in response to the original request. The frame includes synthesized | |
479 // headers to explain the upcoming data. | |
480 SpdySerializedFrame* SerializePushPromise( | |
481 const SpdyPushPromiseIR& push_promise); | |
482 | |
483 // Serializes a CONTINUATION frame. The CONTINUATION frame is used | |
484 // to continue a sequence of header block fragments. | |
485 // TODO(jgraettinger): This implementation is incorrect. The continuation | |
486 // frame continues a previously-begun HPACK encoding; it doesn't begin a | |
487 // new one. Figure out whether it makes sense to keep SerializeContinuation(). | |
488 SpdySerializedFrame* SerializeContinuation( | |
489 const SpdyContinuationIR& continuation); | |
490 | |
491 // Serializes an ALTSVC frame. The ALTSVC frame advertises the | |
492 // availability of an alternative service to the client. | |
493 SpdySerializedFrame* SerializeAltSvc(const SpdyAltSvcIR& altsvc); | |
494 | |
495 // Serializes a PRIORITY frame. The PRIORITY frame advises a change in | |
496 // the relative priority of the given stream. | |
497 SpdySerializedFrame* SerializePriority(const SpdyPriorityIR& priority) const; | |
498 | |
499 // Serialize a frame of unknown type. | |
500 SpdySerializedFrame* SerializeFrame(const SpdyFrameIR& frame); | |
501 | |
502 // NOTES about frame compression. | |
503 // We want spdy to compress headers across the entire session. As long as | |
504 // the session is over TCP, frames are sent serially. The client & server | |
505 // can each compress frames in the same order and then compress them in that | |
506 // order, and the remote can do the reverse. However, we ultimately want | |
507 // the creation of frames to be less sensitive to order so that they can be | |
508 // placed over a UDP based protocol and yet still benefit from some | |
509 // compression. We don't know of any good compression protocol which does | |
510 // not build its state in a serial (stream based) manner.... For now, we're | |
511 // using zlib anyway. | |
512 | |
513 // Compresses a SpdyFrame. | |
514 // On success, returns a new SpdyFrame with the payload compressed. | |
515 // Compression state is maintained as part of the SpdyFramer. | |
516 // Returned frame must be freed with "delete". | |
517 // On failure, returns NULL. | |
518 SpdyFrame* CompressFrame(const SpdyFrame& frame); | |
519 | |
520 // For ease of testing and experimentation we can tweak compression on/off. | |
521 void set_enable_compression(bool value) { | |
522 enable_compression_ = value; | |
523 } | |
524 | |
525 // Used only in log messages. | |
526 void set_display_protocol(const std::string& protocol) { | |
527 display_protocol_ = protocol; | |
528 } | |
529 | |
530 // Returns the (minimum) size of frames (sans variable-length portions). | |
531 size_t GetDataFrameMinimumSize() const; | |
532 size_t GetControlFrameHeaderSize() const; | |
533 size_t GetSynStreamMinimumSize() const; | |
534 size_t GetSynReplyMinimumSize() const; | |
535 size_t GetRstStreamMinimumSize() const; | |
536 size_t GetSettingsMinimumSize() const; | |
537 size_t GetPingSize() const; | |
538 size_t GetGoAwayMinimumSize() const; | |
539 size_t GetHeadersMinimumSize() const; | |
540 size_t GetWindowUpdateSize() const; | |
541 size_t GetBlockedSize() const; | |
542 size_t GetPushPromiseMinimumSize() const; | |
543 size_t GetContinuationMinimumSize() const; | |
544 size_t GetAltSvcMinimumSize() const; | |
545 size_t GetPrioritySize() const; | |
546 | |
547 // Returns the minimum size a frame can be (data or control). | |
548 size_t GetFrameMinimumSize() const; | |
549 | |
550 // Returns the maximum size a frame can be (data or control). | |
551 size_t GetFrameMaximumSize() const; | |
552 | |
553 // Returns the maximum size that a control frame can be. | |
554 size_t GetControlFrameMaximumSize() const; | |
555 | |
556 // Returns the maximum payload size of a DATA frame. | |
557 size_t GetDataFrameMaximumPayload() const; | |
558 | |
559 // Returns the prefix length for the given frame type. | |
560 size_t GetPrefixLength(SpdyFrameType type) const; | |
561 | |
562 // For debugging. | |
563 static const char* StateToString(int state); | |
564 static const char* ErrorCodeToString(int error_code); | |
565 static const char* StatusCodeToString(int status_code); | |
566 static const char* FrameTypeToString(SpdyFrameType type); | |
567 | |
568 SpdyMajorVersion protocol_version() const { return protocol_version_; } | |
569 | |
570 bool probable_http_response() const { return probable_http_response_; } | |
571 | |
572 SpdyStreamId expect_continuation() const { return expect_continuation_; } | |
573 | |
574 SpdyPriority GetLowestPriority() const { | |
575 return protocol_version_ < SPDY3 ? 3 : 7; | |
576 } | |
577 | |
578 SpdyPriority GetHighestPriority() const { return 0; } | |
579 | |
580 // Interpolates SpdyPriority values into SPDY4/HTTP2 priority weights, | |
581 // and vice versa. | |
582 static uint8 MapPriorityToWeight(SpdyPriority priority); | |
583 static SpdyPriority MapWeightToPriority(uint8 weight); | |
584 | |
585 // Deliver the given control frame's compressed headers block to the visitor | |
586 // in decompressed form, in chunks. Returns true if the visitor has | |
587 // accepted all of the chunks. | |
588 bool IncrementallyDecompressControlFrameHeaderData( | |
589 SpdyStreamId stream_id, | |
590 const char* data, | |
591 size_t len); | |
592 | |
593 protected: | |
594 // TODO(jgraettinger): Switch to test peer pattern. | |
595 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, BasicCompression); | |
596 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ControlFrameSizesAreValidated); | |
597 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, HeaderCompression); | |
598 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, DecompressUncompressedFrame); | |
599 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ExpandBuffer_HeapSmash); | |
600 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, HugeHeaderBlock); | |
601 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, UnclosedStreamDataCompressors); | |
602 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, | |
603 UnclosedStreamDataCompressorsOneByteAtATime); | |
604 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, | |
605 UncompressLargerThanFrameBufferInitialSize); | |
606 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, | |
607 CreatePushPromiseThenContinuationUncompressed); | |
608 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ReadLargeSettingsFrame); | |
609 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, | |
610 ReadLargeSettingsFrameInSmallChunks); | |
611 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ControlFrameAtMaxSizeLimit); | |
612 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ControlFrameTooLarge); | |
613 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, | |
614 TooLargeHeadersFrameUsesContinuation); | |
615 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, | |
616 TooLargePushPromiseFrameUsesContinuation); | |
617 friend class HttpNetworkLayer; // This is temporary for the server. | |
618 friend class HttpNetworkTransactionTest; | |
619 friend class HttpProxyClientSocketPoolTest; | |
620 friend class SpdyHttpStreamTest; | |
621 friend class SpdyNetworkTransactionTest; | |
622 friend class SpdyProxyClientSocketTest; | |
623 friend class SpdySessionTest; | |
624 friend class SpdyStreamTest; | |
625 friend class test::TestSpdyVisitor; | |
626 | |
627 private: | |
628 // Internal breakouts from ProcessInput. Each returns the number of bytes | |
629 // consumed from the data. | |
630 size_t ProcessCommonHeader(const char* data, size_t len); | |
631 size_t ProcessControlFramePayload(const char* data, size_t len); | |
632 size_t ProcessControlFrameBeforeHeaderBlock(const char* data, size_t len); | |
633 // HPACK data is re-encoded as SPDY3 and re-entrantly delivered through | |
634 // |ProcessControlFrameHeaderBlock()|. |is_hpack_header_block| controls | |
635 // whether data is treated as HPACK- vs SPDY3-encoded. | |
636 size_t ProcessControlFrameHeaderBlock(const char* data, | |
637 size_t len, | |
638 bool is_hpack_header_block); | |
639 size_t ProcessDataFramePaddingLength(const char* data, size_t len); | |
640 size_t ProcessFramePadding(const char* data, size_t len); | |
641 size_t ProcessDataFramePayload(const char* data, size_t len); | |
642 size_t ProcessGoAwayFramePayload(const char* data, size_t len); | |
643 size_t ProcessRstStreamFramePayload(const char* data, size_t len); | |
644 size_t ProcessSettingsFramePayload(const char* data, size_t len); | |
645 size_t ProcessAltSvcFramePayload(const char* data, size_t len); | |
646 size_t ProcessIgnoredControlFramePayload(/*const char* data,*/ size_t len); | |
647 | |
648 // TODO(jgraettinger): To be removed with migration to | |
649 // SpdyHeadersHandlerInterface. | |
650 // Serializes the last-processed header block of |hpack_decoder_| as | |
651 // a SPDY3 format block, and delivers it to the visitor via reentrant | |
652 // call to ProcessControlFrameHeaderBlock(). | |
653 void DeliverHpackBlockAsSpdy3Block(); | |
654 | |
655 // Helpers for above internal breakouts from ProcessInput. | |
656 void ProcessControlFrameHeader(int control_frame_type_field); | |
657 // Always passed exactly 1 setting's worth of data. | |
658 bool ProcessSetting(const char* data); | |
659 | |
660 // Retrieve serialized length of SpdyHeaderBlock. If compression is enabled, a | |
661 // maximum estimate is returned. | |
662 size_t GetSerializedLength(const SpdyHeaderBlock& headers); | |
663 | |
664 // Get (and lazily initialize) the ZLib state. | |
665 z_stream* GetHeaderCompressor(); | |
666 z_stream* GetHeaderDecompressor(); | |
667 | |
668 // Get (and lazily initialize) the HPACK state. | |
669 HpackEncoder* GetHpackEncoder(); | |
670 HpackDecoder* GetHpackDecoder(); | |
671 | |
672 size_t GetNumberRequiredContinuationFrames(size_t size); | |
673 | |
674 void WritePayloadWithContinuation(SpdyFrameBuilder* builder, | |
675 const std::string& hpack_encoding, | |
676 SpdyStreamId stream_id, | |
677 SpdyFrameType type, | |
678 int padding_payload_len); | |
679 | |
680 private: | |
681 // Deliver the given control frame's uncompressed headers block to the | |
682 // visitor in chunks. Returns true if the visitor has accepted all of the | |
683 // chunks. | |
684 bool IncrementallyDeliverControlFrameHeaderData(SpdyStreamId stream_id, | |
685 const char* data, | |
686 size_t len); | |
687 | |
688 // Utility to copy the given data block to the current frame buffer, up | |
689 // to the given maximum number of bytes, and update the buffer | |
690 // data (pointer and length). Returns the number of bytes | |
691 // read, and: | |
692 // *data is advanced the number of bytes read. | |
693 // *len is reduced by the number of bytes read. | |
694 size_t UpdateCurrentFrameBuffer(const char** data, size_t* len, | |
695 size_t max_bytes); | |
696 | |
697 void WriteHeaderBlockToZ(const SpdyHeaderBlock* headers, | |
698 z_stream* out) const; | |
699 | |
700 void SerializeNameValueBlockWithoutCompression( | |
701 SpdyFrameBuilder* builder, | |
702 const SpdyNameValueBlock& name_value_block) const; | |
703 | |
704 // Compresses automatically according to enable_compression_. | |
705 void SerializeNameValueBlock( | |
706 SpdyFrameBuilder* builder, | |
707 const SpdyFrameWithNameValueBlockIR& frame); | |
708 | |
709 // Set the error code and moves the framer into the error state. | |
710 void set_error(SpdyError error); | |
711 | |
712 // The size of the control frame buffer. | |
713 // Since this is only used for control frame headers, the maximum control | |
714 // frame header size (SYN_STREAM) is sufficient; all remaining control | |
715 // frame data is streamed to the visitor. | |
716 static const size_t kControlFrameBufferSize; | |
717 | |
718 // The maximum size of the control frames that we support. | |
719 // This limit is arbitrary. We can enforce it here or at the application | |
720 // layer. We chose the framing layer, but this can be changed (or removed) | |
721 // if necessary later down the line. | |
722 static const size_t kMaxControlFrameSize; | |
723 | |
724 SpdyState state_; | |
725 SpdyState previous_state_; | |
726 SpdyError error_code_; | |
727 | |
728 // Note that for DATA frame, remaining_data_length_ is sum of lengths of | |
729 // frame header, padding length field (optional), data payload (optional) and | |
730 // padding payload (optional). | |
731 size_t remaining_data_length_; | |
732 | |
733 // The length (in bytes) of the padding payload to be processed. | |
734 size_t remaining_padding_payload_length_; | |
735 | |
736 // The number of bytes remaining to read from the current control frame's | |
737 // headers. Note that header data blocks (for control types that have them) | |
738 // are part of the frame's payload, and not the frame's headers. | |
739 size_t remaining_control_header_; | |
740 | |
741 scoped_ptr<char[]> current_frame_buffer_; | |
742 // Number of bytes read into the current_frame_buffer_. | |
743 size_t current_frame_buffer_length_; | |
744 | |
745 // The type of the frame currently being read. | |
746 SpdyFrameType current_frame_type_; | |
747 | |
748 // The flags field of the frame currently being read. | |
749 uint8 current_frame_flags_; | |
750 | |
751 // The total length of the frame currently being read, including frame header. | |
752 uint32 current_frame_length_; | |
753 | |
754 // The stream ID field of the frame currently being read, if applicable. | |
755 SpdyStreamId current_frame_stream_id_; | |
756 | |
757 // Scratch space for handling SETTINGS frames. | |
758 // TODO(hkhalil): Unify memory for this scratch space with | |
759 // current_frame_buffer_. | |
760 SpdySettingsScratch settings_scratch_; | |
761 | |
762 SpdyAltSvcScratch altsvc_scratch_; | |
763 | |
764 bool enable_compression_; // Controls all compression | |
765 // SPDY header compressors. | |
766 scoped_ptr<z_stream> header_compressor_; | |
767 scoped_ptr<z_stream> header_decompressor_; | |
768 | |
769 scoped_ptr<HpackEncoder> hpack_encoder_; | |
770 scoped_ptr<HpackDecoder> hpack_decoder_; | |
771 | |
772 SpdyFramerVisitorInterface* visitor_; | |
773 SpdyFramerDebugVisitorInterface* debug_visitor_; | |
774 | |
775 std::string display_protocol_; | |
776 | |
777 // The protocol version to be spoken/understood by this framer. | |
778 const SpdyMajorVersion protocol_version_; | |
779 | |
780 // Tracks if we've ever gotten far enough in framing to see a control frame of | |
781 // type SYN_STREAM or SYN_REPLY. | |
782 // | |
783 // If we ever get something which looks like a data frame before we've had a | |
784 // SYN, we explicitly check to see if it looks like we got an HTTP response | |
785 // to a SPDY request. This boolean lets us do that. | |
786 bool syn_frame_processed_; | |
787 | |
788 // If we ever get a data frame before a SYN frame, we check to see if it | |
789 // starts with HTTP. If it does, we likely have an HTTP response. This | |
790 // isn't guaranteed though: we could have gotten a settings frame and then | |
791 // corrupt data that just looks like HTTP, but deterministic checking requires | |
792 // a lot more state. | |
793 bool probable_http_response_; | |
794 | |
795 // Set this to the current stream when we receive a HEADERS, PUSH_PROMISE, or | |
796 // CONTINUATION frame without the END_HEADERS(0x4) bit set. These frames must | |
797 // be followed by a CONTINUATION frame, or else we throw a PROTOCOL_ERROR. | |
798 // A value of 0 indicates that we are not expecting a CONTINUATION frame. | |
799 SpdyStreamId expect_continuation_; | |
800 | |
801 // If a HEADERS frame is followed by a CONTINUATION frame, the FIN/END_STREAM | |
802 // flag is still carried in the HEADERS frame. If it's set, flip this so that | |
803 // we know to terminate the stream when the entire header block has been | |
804 // processed. | |
805 bool end_stream_when_done_; | |
806 }; | |
807 | |
808 } // namespace net | |
809 | |
810 #endif // NET_SPDY_SPDY_FRAMER_H_ | |
OLD | NEW |