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.
5 #ifndef NET_SPDY_SPDY_FRAMER_H_
6 #define NET_SPDY_SPDY_FRAMER_H_
15 #include "base/basictypes.h"
16 #include "base/gtest_prod_util.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/sys_byteorder.h"
19 #include "net/base/net_export.h"
20 #include "net/spdy/spdy_protocol.h"
22 typedef struct z_stream_s z_stream
; // Forward declaration for zlib.
25 class HttpProxyClientSocketPoolTest
;
26 class HttpNetworkLayer
;
27 class HttpNetworkTransactionTest
;
28 class SpdyHttpStreamTest
;
29 class SpdyNetworkTransactionTest
;
30 class SpdyProxyClientSocketTest
;
31 class SpdySessionTest
;
33 class SpdyWebSocketStreamTest
;
34 class WebSocketJobTest
;
43 class TestSpdyVisitor
;
44 void FramerSetEnableCompressionHelper(SpdyFramer
* framer
, bool compress
);
47 // A datastructure for holding a set of headers from either a
48 // SYN_STREAM or SYN_REPLY frame.
49 typedef std::map
<std::string
, std::string
> SpdyHeaderBlock
;
51 // A datastructure for holding a set of ID/value pairs for a SETTINGS frame.
52 typedef std::pair
<spdy::SettingsFlagsAndId
, uint32
> SpdySetting
;
53 typedef std::list
<SpdySetting
> SpdySettings
;
55 // A datastrcture for holding the contents of a CREDENTIAL frame.
56 struct NET_EXPORT_PRIVATE SpdyCredential
{
62 std::vector
<std::string
> certs
;
66 // SpdyFramerVisitorInterface is a set of callbacks for the SpdyFramer.
67 // Implement this interface to receive event callbacks as frames are
68 // decoded from the framer.
70 // Control frames that contain SPDY header blocks (SYN_STREAM, SYN_REPLY, and
71 // HEADER) are processed in fashion that allows the decompressed header block
72 // to be delivered in chunks to the visitor. The following steps are followed:
73 // 1. OnControl is called, with either a SpdySynStreamControlFrame,
74 // SpdySynReplyControlFrame, or a SpdyHeaderControlFrame argument.
75 // 2. Repeated: OnControlFrameHeaderData is called with chunks of the
76 // decompressed header block. In each call the len parameter is greater
78 // 3. OnControlFrameHeaderData is called with len set to zero, indicating
79 // that the full header block has been delivered for the control frame.
80 // During step 2 the visitor may return false, indicating that the chunk of
81 // header data could not be handled by the visitor (typically this indicates
82 // resource exhaustion). If this occurs the framer will discontinue
83 // delivering chunks to the visitor, set a SPDY_CONTROL_PAYLOAD_TOO_LARGE
84 // error, and clean up appropriately. Note that this will cause the header
85 // decompressor to lose synchronization with the sender's header compressor,
86 // making the SPDY session unusable for future work. The visitor's OnError
87 // function should deal with this condition by closing the SPDY connection.
88 class NET_EXPORT_PRIVATE SpdyFramerVisitorInterface
{
90 virtual ~SpdyFramerVisitorInterface() {}
92 // Called if an error is detected in the SpdyFrame protocol.
93 virtual void OnError(SpdyFramer
* framer
) = 0;
95 // Called when a control frame is received. Note that SYN_STREAM, SYN_REPLY,
96 // and HEADER control frames do not include the header block data.
97 // (See OnControlFrameHeaderData().)
98 virtual void OnControl(const SpdyControlFrame
* frame
) = 0;
100 // Called when a chunk of header data is available. This is called
101 // after OnControl() is called with the control frame associated with the
102 // header data being delivered here.
103 // |stream_id| The stream receiving the header data.
104 // |header_data| A buffer containing the header data chunk received.
105 // |len| The length of the header data buffer. A length of zero indicates
106 // that the header data block has been completely sent.
107 // When this function returns true the visitor indicates that it accepted
108 // all of the data. Returning false indicates that that an unrecoverable
109 // error has occurred, such as bad header data or resource exhaustion.
110 virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id
,
111 const char* header_data
,
114 // Called when a chunk of payload data for a credential frame is available.
115 // This is called after OnControl() is called with the credential frame
116 // associated with the payload being delivered here.
117 // |frame_data| A buffer containing the header data chunk received.
118 // |len| The length of the header data buffer. A length of zero indicates
119 // that the header data block has been completely sent.
120 // When this function returns true the visitor indicates that it accepted
121 // all of the data. Returning false indicates that that an unrecoverable
122 // error has occurred, such as bad header data or resource exhaustion.
123 virtual bool OnCredentialFrameData(const char* frame_data
,
126 // Called when a data frame header is received. The frame's data
127 // payload will be provided via subsequent calls to
128 // OnStreamFrameData().
129 virtual void OnDataFrameHeader(const SpdyDataFrame
* frame
) = 0;
131 // Called when data is received.
132 // |stream_id| The stream receiving data.
133 // |data| A buffer containing the data received.
134 // |len| The length of the data buffer.
135 // When the other side has finished sending data on this stream,
136 // this method will be called with a zero-length buffer.
137 virtual void OnStreamFrameData(SpdyStreamId stream_id
,
142 class NET_EXPORT_PRIVATE SpdyFramer
{
145 // TODO(mbelshe): Can we move these into the implementation
146 // and avoid exposing through the header. (Needed for test)
152 SPDY_READING_COMMON_HEADER
,
153 SPDY_CONTROL_FRAME_PAYLOAD
,
154 SPDY_IGNORE_REMAINING_PAYLOAD
,
155 SPDY_FORWARD_STREAM_FRAME
,
156 SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK
,
157 SPDY_CONTROL_FRAME_HEADER_BLOCK
,
158 SPDY_CREDENTIAL_FRAME_PAYLOAD
,
164 SPDY_INVALID_CONTROL_FRAME
, // Control frame is mal-formatted.
165 SPDY_CONTROL_PAYLOAD_TOO_LARGE
, // Control frame payload was too large.
166 SPDY_ZLIB_INIT_FAILURE
, // The Zlib library could not initialize.
167 SPDY_UNSUPPORTED_VERSION
, // Control frame has unsupported version.
168 SPDY_DECOMPRESS_FAILURE
, // There was an error decompressing.
169 SPDY_COMPRESS_FAILURE
, // There was an error compressing.
170 SPDY_CREDENTIAL_FRAME_CORRUPT
, // CREDENTIAL frame could not be parsed.
172 LAST_ERROR
, // Must be the last entry in the enum.
175 // Constant for invalid (or unknown) stream IDs.
176 static const SpdyStreamId kInvalidStream
;
178 // The maximum size of header data chunks delivered to the framer visitor
179 // through OnControlFrameHeaderData. (It is exposed here for unit test
181 static const size_t kHeaderDataChunkMaxSize
;
183 // Create a new Framer.
185 virtual ~SpdyFramer();
187 // Set callbacks to be called from the framer. A visitor must be set, or
188 // else the framer will likely crash. It is acceptable for the visitor
189 // to do nothing. If this is called multiple times, only the last visitor
191 void set_visitor(SpdyFramerVisitorInterface
* visitor
) {
195 // Pass data into the framer for parsing.
196 // Returns the number of bytes consumed. It is safe to pass more bytes in
197 // than may be consumed.
198 size_t ProcessInput(const char* data
, size_t len
);
200 // Resets the framer state after a frame has been successfully decoded.
201 // TODO(mbelshe): can we make this private?
204 // Check the state of the framer.
205 SpdyError
error_code() const { return error_code_
; }
206 SpdyState
state() const { return state_
; }
208 bool MessageFullyRead() {
209 return state_
== SPDY_DONE
|| state_
== SPDY_AUTO_RESET
;
211 bool HasError() { return state_
== SPDY_ERROR
; }
213 // Further parsing utilities.
214 // Given a control frame, parse out a SpdyHeaderBlock. Only
215 // valid for SYN_STREAM and SYN_REPLY frames.
216 // Returns true if successfully parsed, false otherwise.
217 bool ParseHeaderBlock(const SpdyFrame
* frame
, SpdyHeaderBlock
* block
);
219 // Given a buffer containing a decompressed header block in SPDY
220 // serialized format, parse out a SpdyHeaderBlock, putting the results
221 // in the given header block.
222 // Returns true if successfully parsed, false otherwise.
223 static bool ParseHeaderBlockInBuffer(const char* header_data
,
224 size_t header_length
,
225 SpdyHeaderBlock
* block
);
227 // Create a SpdySynStreamControlFrame.
228 // |stream_id| is the id for this stream.
229 // |associated_stream_id| is the associated stream id for this stream.
230 // |priority| is the priority (0-3) for this stream.
231 // |flags| is the flags to use with the data.
232 // To mark this frame as the last frame, enable CONTROL_FLAG_FIN.
233 // |compressed| specifies whether the frame should be compressed.
234 // |headers| is the header block to include in the frame.
235 SpdySynStreamControlFrame
* CreateSynStream(SpdyStreamId stream_id
,
236 SpdyStreamId associated_stream_id
,
238 SpdyControlFlags flags
,
240 const SpdyHeaderBlock
* headers
);
242 // Create a SpdySynReplyControlFrame.
243 // |stream_id| is the stream for this frame.
244 // |flags| is the flags to use with the data.
245 // To mark this frame as the last frame, enable CONTROL_FLAG_FIN.
246 // |compressed| specifies whether the frame should be compressed.
247 // |headers| is the header block to include in the frame.
248 SpdySynReplyControlFrame
* CreateSynReply(SpdyStreamId stream_id
,
249 SpdyControlFlags flags
,
251 const SpdyHeaderBlock
* headers
);
253 static SpdyRstStreamControlFrame
* CreateRstStream(SpdyStreamId stream_id
,
254 SpdyStatusCodes status
);
256 // Creates an instance of SpdySettingsControlFrame. The SETTINGS frame is
257 // used to communicate name/value pairs relevant to the communication channel.
258 // TODO(mbelshe): add the name/value pairs!!
259 static SpdySettingsControlFrame
* CreateSettings(const SpdySettings
& values
);
261 static SpdyNoOpControlFrame
* CreateNopFrame();
263 // Creates an instance of SpdyPingControlFrame. The unique_id is used to
264 // identify the ping request/response.
265 static SpdyPingControlFrame
* CreatePingFrame(uint32 unique_id
);
267 // Creates an instance of SpdyGoAwayControlFrame. The GOAWAY frame is used
268 // prior to the shutting down of the TCP connection, and includes the
269 // stream_id of the last stream the sender of the frame is willing to process
271 static SpdyGoAwayControlFrame
* CreateGoAway(
272 SpdyStreamId last_accepted_stream_id
);
274 // Creates an instance of SpdyHeadersControlFrame. The HEADERS frame is used
275 // for sending additional headers outside of a SYN_STREAM/SYN_REPLY. The
276 // arguments are the same as for CreateSynReply.
277 SpdyHeadersControlFrame
* CreateHeaders(SpdyStreamId stream_id
,
278 SpdyControlFlags flags
,
280 const SpdyHeaderBlock
* headers
);
282 // Creates an instance of SpdyWindowUpdateControlFrame. The WINDOW_UPDATE
283 // frame is used to implement per stream flow control in SPDY.
284 static SpdyWindowUpdateControlFrame
* CreateWindowUpdate(
285 SpdyStreamId stream_id
,
286 uint32 delta_window_size
);
288 // Creates an instance of SpdyCredentialControlFrame. The CREDENTIAL
289 // frame is used to send a client certificate to the server when
290 // request more than one origin are sent over the same SPDY session.
291 static SpdyCredentialControlFrame
* CreateCredentialFrame(
292 const SpdyCredential
& credential
);
294 // Given a SpdySettingsControlFrame, extract the settings.
295 // Returns true on successful parse, false otherwise.
296 static bool ParseSettings(const SpdySettingsControlFrame
* frame
,
297 SpdySettings
* settings
);
299 // Given a SpdyCredentialControlFrame's payload, extract the credential.
300 // Returns true on successful parse, false otherwise.
301 // TODO(hkhalil): Implement CREDENTIAL frame parsing in SpdyFramer
302 // and eliminate this method.
303 static bool ParseCredentialData(const char* data
, size_t len
,
304 SpdyCredential
* credential
);
306 // Create a data frame.
307 // |stream_id| is the stream for this frame
308 // |data| is the data to be included in the frame.
309 // |len| is the length of the data
310 // |flags| is the flags to use with the data.
311 // To create a compressed frame, enable DATA_FLAG_COMPRESSED.
312 // To mark this frame as the last data frame, enable DATA_FLAG_FIN.
313 SpdyDataFrame
* CreateDataFrame(SpdyStreamId stream_id
, const char* data
,
314 uint32 len
, SpdyDataFlags flags
);
316 // NOTES about frame compression.
317 // We want spdy to compress headers across the entire session. As long as
318 // the session is over TCP, frames are sent serially. The client & server
319 // can each compress frames in the same order and then compress them in that
320 // order, and the remote can do the reverse. However, we ultimately want
321 // the creation of frames to be less sensitive to order so that they can be
322 // placed over a UDP based protocol and yet still benefit from some
323 // compression. We don't know of any good compression protocol which does
324 // not build its state in a serial (stream based) manner.... For now, we're
325 // using zlib anyway.
327 // Compresses a SpdyFrame.
328 // On success, returns a new SpdyFrame with the payload compressed.
329 // Compression state is maintained as part of the SpdyFramer.
330 // Returned frame must be freed with "delete".
331 // On failure, returns NULL.
332 SpdyFrame
* CompressFrame(const SpdyFrame
& frame
);
334 // Decompresses a SpdyFrame.
335 // On success, returns a new SpdyFrame with the payload decompressed.
336 // Compression state is maintained as part of the SpdyFramer.
337 // Returned frame must be freed with "delete".
338 // On failure, returns NULL.
339 SpdyFrame
* DecompressFrame(const SpdyFrame
& frame
);
341 // Create a copy of a frame.
342 // Returned frame must be freed with "delete".
343 SpdyFrame
* DuplicateFrame(const SpdyFrame
& frame
);
345 // Returns true if a frame could be compressed.
346 bool IsCompressible(const SpdyFrame
& frame
) const;
348 // Get the minimum size of the control frame for the given control frame
349 // type. This is useful for validating frame blocks.
350 static size_t GetMinimumControlFrameSize(SpdyControlType type
);
352 // Get the stream ID for the given control frame (SYN_STREAM, SYN_REPLY, and
353 // HEADERS). If the control frame is NULL or of another type, this
354 // function returns kInvalidStream.
355 static SpdyStreamId
GetControlFrameStreamId(
356 const SpdyControlFrame
* control_frame
);
358 // For ease of testing and experimentation we can tweak compression on/off.
359 void set_enable_compression(bool value
);
361 // SPDY will by default validate the length of incoming control
362 // frames. Set validation to false if you do not want this behavior.
363 void set_validate_control_frame_sizes(bool value
);
364 static void set_enable_compression_default(bool value
);
366 // Used only in log messages.
367 void set_display_protocol(const std::string
& protocol
) {
368 display_protocol_
= protocol
;
372 static const char* StateToString(int state
);
373 static const char* ErrorCodeToString(int error_code
);
374 static const char* StatusCodeToString(int status_code
);
375 static const char* ControlTypeToString(SpdyControlType type
);
377 static void set_protocol_version(int version
) { spdy_version_
= version
; }
378 static int protocol_version() { return spdy_version_
; }
380 // Export the compression dictionary
381 static const char kDictionary
[];
382 static const int kDictionarySize
;
385 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest
, HeaderCompression
);
386 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest
, ExpandBuffer_HeapSmash
);
387 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest
, HugeHeaderBlock
);
388 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest
, UnclosedStreamDataCompressors
);
389 friend class net::HttpNetworkLayer
; // This is temporary for the server.
390 friend class net::HttpNetworkTransactionTest
;
391 friend class net::HttpProxyClientSocketPoolTest
;
392 friend class net::SpdyHttpStreamTest
;
393 friend class net::SpdyNetworkTransactionTest
;
394 friend class net::SpdyProxyClientSocketTest
;
395 friend class net::SpdySessionTest
;
396 friend class net::SpdyStreamTest
;
397 friend class net::SpdyWebSocketStreamTest
;
398 friend class net::WebSocketJobTest
;
399 friend class test::TestSpdyVisitor
;
400 friend void test::FramerSetEnableCompressionHelper(SpdyFramer
* framer
,
404 typedef std::map
<SpdyStreamId
, z_stream
*> CompressorMap
;
406 // Internal breakout from ProcessInput. Returns the number of bytes
407 // consumed from the data.
408 size_t ProcessCommonHeader(const char* data
, size_t len
);
409 void ProcessControlFrameHeader();
410 size_t ProcessControlFramePayload(const char* data
, size_t len
);
411 size_t ProcessCredentialFramePayload(const char* data
, size_t len
);
412 size_t ProcessControlFrameBeforeHeaderBlock(const char* data
, size_t len
);
413 size_t ProcessControlFrameHeaderBlock(const char* data
, size_t len
);
414 size_t ProcessDataFramePayload(const char* data
, size_t len
);
416 // Get (and lazily initialize) the ZLib state.
417 z_stream
* GetHeaderCompressor();
418 z_stream
* GetHeaderDecompressor();
419 z_stream
* GetStreamCompressor(SpdyStreamId id
);
420 z_stream
* GetStreamDecompressor(SpdyStreamId id
);
422 // Compression helpers
423 SpdyControlFrame
* CompressControlFrame(const SpdyControlFrame
& frame
);
424 SpdyDataFrame
* CompressDataFrame(const SpdyDataFrame
& frame
);
425 SpdyControlFrame
* DecompressControlFrame(const SpdyControlFrame
& frame
);
426 SpdyDataFrame
* DecompressDataFrame(const SpdyDataFrame
& frame
);
427 SpdyFrame
* CompressFrameWithZStream(const SpdyFrame
& frame
,
428 z_stream
* compressor
);
429 SpdyFrame
* DecompressFrameWithZStream(const SpdyFrame
& frame
,
430 z_stream
* decompressor
);
431 void CleanupCompressorForStream(SpdyStreamId id
);
432 void CleanupDecompressorForStream(SpdyStreamId id
);
433 void CleanupStreamCompressorsAndDecompressors();
436 size_t BytesSafeToRead() const;
438 // Deliver the given control frame's compressed headers block to the visitor
439 // in decompressed form, in chunks. Returns true if the visitor has
440 // accepted all of the chunks.
441 bool IncrementallyDecompressControlFrameHeaderData(
442 const SpdyControlFrame
* frame
,
446 // Deliver the given control frame's uncompressed headers block to the
447 // visitor in chunks. Returns true if the visitor has accepted all of the
449 bool IncrementallyDeliverControlFrameHeaderData(const SpdyControlFrame
* frame
,
453 // Utility to copy the given data block to the current frame buffer, up
454 // to the given maximum number of bytes, and update the buffer
455 // data (pointer and length). Returns the number of bytes
457 // *data is advanced the number of bytes read.
458 // *len is reduced by the number of bytes read.
459 size_t UpdateCurrentFrameBuffer(const char** data
, size_t* len
,
462 // Set the error code and moves the framer into the error state.
463 void set_error(SpdyError error
);
465 // Expands the control frame buffer to accomodate a particular payload size.
466 void ExpandControlFrameBuffer(size_t size
);
468 // Given a frame, breakdown the variable payload length, the static header
469 // header length, and variable payload pointer.
470 bool GetFrameBoundaries(const SpdyFrame
& frame
, int* payload_length
,
471 int* header_length
, const char** payload
) const;
473 int num_stream_compressors() const { return stream_compressors_
.size(); }
474 int num_stream_decompressors() const { return stream_decompressors_
.size(); }
476 // The initial size of the control frame buffer; this is used internally
477 // as we parse through control frames. (It is exposed here for unit test
479 // This is only used when compression is enabled; otherwise,
480 // kUncompressedControlFrameBufferInitialSize is used.
481 static size_t kControlFrameBufferInitialSize
;
483 // The initial size of the control frame buffer when compression is disabled.
484 // This exists because we don't do stream (de)compressed control frame data to
485 // our visitor; we instead buffer the entirety of the control frame and then
486 // decompress in one fell swoop.
487 // Since this is only used for control frame headers, the maximum control
488 // frame header size (18B) is sufficient; all remaining control frame data is
489 // streamed to the visitor.
490 // In addition to the maximum control frame header size, we account for any
491 // LOAS checksumming (16B) that may occur in the VTL case.
492 // TODO(hkhalil): Remove post code-yellow once streamed inflate is properly
494 static const size_t kUncompressedControlFrameBufferInitialSize
= 18 + 16;
496 // The maximum size of the control frame buffer that we support.
497 // TODO(mbelshe): We should make this stream-based so there are no limits.
498 static size_t kControlFrameBufferMaxSize
;
500 // The size of the buffer into which compressed frames are inflated.
501 static const size_t kDecompressionBufferSize
= 8 * 1024;
504 SpdyError error_code_
;
505 size_t remaining_data_
;
507 // The number of bytes remaining to read from the current control frame's
509 size_t remaining_control_payload_
;
511 // The number of bytes remaining to read from the current control frame's
512 // headers. Note that header data blocks (for control types that have them)
513 // are part of the frame's payload, and not the frame's headers.
514 size_t remaining_control_header_
;
516 char* current_frame_buffer_
;
517 size_t current_frame_len_
; // Number of bytes read into the current_frame_.
518 size_t current_frame_capacity_
;
520 bool validate_control_frame_sizes_
;
521 bool enable_compression_
; // Controls all compression
522 // SPDY header compressors.
523 scoped_ptr
<z_stream
> header_compressor_
;
524 scoped_ptr
<z_stream
> header_decompressor_
;
526 // Per-stream data compressors.
527 CompressorMap stream_compressors_
;
528 CompressorMap stream_decompressors_
;
530 SpdyFramerVisitorInterface
* visitor_
;
532 std::string display_protocol_
;
534 static bool compression_default_
;
535 static int spdy_version_
;
540 #endif // NET_SPDY_SPDY_FRAMER_H_