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_
14 #include "base/basictypes.h"
15 #include "base/gtest_prod_util.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/sys_byteorder.h"
18 #include "net/base/net_export.h"
19 #include "net/spdy/spdy_header_block.h"
20 #include "net/spdy/spdy_protocol.h"
22 // TODO(akalin): Remove support for CREDENTIAL frames.
24 typedef struct z_stream_s z_stream; // Forward declaration for zlib.
28 class HttpProxyClientSocketPoolTest;
29 class HttpNetworkLayer;
30 class HttpNetworkTransactionTest;
31 class SpdyHttpStreamTest;
32 class SpdyNetworkTransactionTest;
33 class SpdyProxyClientSocketTest;
34 class SpdySessionTest;
36 class SpdyWebSocketStreamTest;
37 class WebSocketJobTest;
40 class SpdyFrameBuilder;
45 class TestSpdyVisitor;
49 // A datastructure for holding a set of headers from a HEADERS, PUSH_PROMISE,
50 // SYN_STREAM, or SYN_REPLY frame.
51 typedef std::map<std::string, std::string> SpdyHeaderBlock;
53 // A datastructure for holding the ID and flag fields for SETTINGS.
54 // Conveniently handles converstion to/from wire format.
55 class NET_EXPORT_PRIVATE SettingsFlagsAndId {
57 static SettingsFlagsAndId FromWireFormat(int version, uint32 wire);
59 SettingsFlagsAndId() : flags_(0), id_(0) {}
61 // TODO(hkhalil): restrict to enums instead of free-form ints.
62 SettingsFlagsAndId(uint8 flags, uint32 id);
64 uint32 GetWireFormat(int version) const;
66 uint32 id() const { return id_; }
67 uint8 flags() const { return flags_; }
70 static void ConvertFlagsAndIdForSpdy2(uint32* val);
76 // SettingsMap has unique (flags, value) pair for given SpdySettingsIds ID.
77 typedef std::pair<SpdySettingsFlags, uint32> SettingsFlagsAndValue;
78 typedef std::map<SpdySettingsIds, SettingsFlagsAndValue> SettingsMap;
80 // A datastrcture for holding the contents of a CREDENTIAL frame.
81 // TODO(hkhalil): Remove, use SpdyCredentialIR instead.
82 struct NET_EXPORT_PRIVATE SpdyCredential {
87 std::vector<std::string> certs;
91 // Scratch space necessary for processing SETTINGS frames.
92 struct NET_EXPORT_PRIVATE SpdySettingsScratch {
93 SpdySettingsScratch() { Reset(); }
100 // Buffer contains up to one complete key/value pair.
103 // The amount of the buffer that is filled with valid data.
104 size_t setting_buf_len;
106 // The ID of the last setting that was processed in the current SETTINGS
107 // frame. Used for detecting out-of-order or duplicate keys within a settings
108 // frame. Set to 0 before first key/value pair is processed.
109 uint32 last_setting_id;
112 // SpdyFramerVisitorInterface is a set of callbacks for the SpdyFramer.
113 // Implement this interface to receive event callbacks as frames are
114 // decoded from the framer.
116 // Control frames that contain SPDY header blocks (SYN_STREAM, SYN_REPLY,
117 // HEADER, and PUSH_PROMISE) are processed in fashion that allows the
118 // decompressed header block to be delivered in chunks to the visitor.
119 // The following steps are followed:
120 // 1. OnSynStream, OnSynReply, OnHeaders, or OnPushPromise is called.
121 // 2. Repeated: OnControlFrameHeaderData is called with chunks of the
122 // decompressed header block. In each call the len parameter is greater
124 // 3. OnControlFrameHeaderData is called with len set to zero, indicating
125 // that the full header block has been delivered for the control frame.
126 // During step 2 the visitor may return false, indicating that the chunk of
127 // header data could not be handled by the visitor (typically this indicates
128 // resource exhaustion). If this occurs the framer will discontinue
129 // delivering chunks to the visitor, set a SPDY_CONTROL_PAYLOAD_TOO_LARGE
130 // error, and clean up appropriately. Note that this will cause the header
131 // decompressor to lose synchronization with the sender's header compressor,
132 // making the SPDY session unusable for future work. The visitor's OnError
133 // function should deal with this condition by closing the SPDY connection.
134 class NET_EXPORT_PRIVATE SpdyFramerVisitorInterface {
136 virtual ~SpdyFramerVisitorInterface() {}
138 // Called if an error is detected in the SpdyFrame protocol.
139 virtual void OnError(SpdyFramer* framer) = 0;
141 // Called when a data frame header is received. The frame's data
142 // payload will be provided via subsequent calls to
143 // OnStreamFrameData().
144 virtual void OnDataFrameHeader(SpdyStreamId stream_id,
148 // Called when data is received.
149 // |stream_id| The stream receiving data.
150 // |data| A buffer containing the data received.
151 // |len| The length of the data buffer.
152 // When the other side has finished sending data on this stream,
153 // this method will be called with a zero-length buffer.
154 virtual void OnStreamFrameData(SpdyStreamId stream_id,
159 // Called when a chunk of header data is available. This is called
160 // after OnSynStream, OnSynReply, OnHeaders(), or OnPushPromise.
161 // |stream_id| The stream receiving the header data.
162 // |header_data| A buffer containing the header data chunk received.
163 // |len| The length of the header data buffer. A length of zero indicates
164 // that the header data block has been completely sent.
165 // When this function returns true the visitor indicates that it accepted
166 // all of the data. Returning false indicates that that an unrecoverable
167 // error has occurred, such as bad header data or resource exhaustion.
168 virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id,
169 const char* header_data,
172 // Called when a SYN_STREAM frame is received.
173 // Note that header block data is not included. See
174 // OnControlFrameHeaderData().
175 virtual void OnSynStream(SpdyStreamId stream_id,
176 SpdyStreamId associated_stream_id,
177 SpdyPriority priority,
178 uint8 credential_slot,
180 bool unidirectional) = 0;
182 // Called when a SYN_REPLY frame is received.
183 // Note that header block data is not included. See
184 // OnControlFrameHeaderData().
185 virtual void OnSynReply(SpdyStreamId stream_id, bool fin) = 0;
187 // Called when a RST_STREAM frame has been parsed.
188 virtual void OnRstStream(SpdyStreamId stream_id,
189 SpdyRstStreamStatus status) = 0;
191 // Called when a SETTINGS frame is received.
192 // |clear_persisted| True if the respective flag is set on the SETTINGS frame.
193 virtual void OnSettings(bool clear_persisted) {}
195 // Called when a complete setting within a SETTINGS frame has been parsed and
197 virtual void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) = 0;
199 // Called when a PING frame has been parsed.
200 virtual void OnPing(uint32 unique_id) = 0;
202 // Called when a GOAWAY frame has been parsed.
203 virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
204 SpdyGoAwayStatus status) = 0;
206 // Called when a HEADERS frame is received.
207 // Note that header block data is not included. See
208 // OnControlFrameHeaderData().
209 virtual void OnHeaders(SpdyStreamId stream_id, bool fin) = 0;
211 // Called when a WINDOW_UPDATE frame has been parsed.
212 virtual void OnWindowUpdate(SpdyStreamId stream_id,
213 uint32 delta_window_size) = 0;
215 // Called when a chunk of payload data for a credential frame is available.
216 // |header_data| A buffer containing the header data chunk received.
217 // |len| The length of the header data buffer. A length of zero indicates
218 // that the header data block has been completely sent.
219 // When this function returns true the visitor indicates that it accepted
220 // all of the data. Returning false indicates that that an unrecoverable
221 // error has occurred, such as bad header data or resource exhaustion.
222 virtual bool OnCredentialFrameData(const char* credential_data,
225 // Called when a BLOCKED frame has been parsed.
226 virtual void OnBlocked(SpdyStreamId stream_id) {}
228 // Called when a PUSH_PROMISE frame is received.
229 // Note that header block data is not included. See
230 // OnControlFrameHeaderData().
231 virtual void OnPushPromise(SpdyStreamId stream_id,
232 SpdyStreamId promised_stream_id) = 0;
235 // Optionally, and in addition to SpdyFramerVisitorInterface, a class supporting
236 // SpdyFramerDebugVisitorInterface may be used in conjunction with SpdyFramer in
237 // order to extract debug/internal information about the SpdyFramer as it
240 // Most SPDY implementations need not bother with this interface at all.
241 class NET_EXPORT_PRIVATE SpdyFramerDebugVisitorInterface {
243 virtual ~SpdyFramerDebugVisitorInterface() {}
245 // Called after compressing a frame with a payload of
246 // a list of name-value pairs.
247 // |payload_len| is the uncompressed payload size.
248 // |frame_len| is the compressed frame size.
249 virtual void OnSendCompressedFrame(SpdyStreamId stream_id,
254 // Called when a frame containing a compressed payload of
255 // name-value pairs is received.
256 // |frame_len| is the compressed frame size.
257 virtual void OnReceiveCompressedFrame(SpdyStreamId stream_id,
262 class NET_EXPORT_PRIVATE SpdyFramer {
265 // TODO(mbelshe): Can we move these into the implementation
266 // and avoid exposing through the header. (Needed for test)
271 SPDY_READING_COMMON_HEADER,
272 SPDY_CONTROL_FRAME_PAYLOAD,
273 SPDY_IGNORE_REMAINING_PAYLOAD,
274 SPDY_FORWARD_STREAM_FRAME,
275 SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK,
276 SPDY_CONTROL_FRAME_HEADER_BLOCK,
277 SPDY_CREDENTIAL_FRAME_PAYLOAD,
278 SPDY_SETTINGS_FRAME_PAYLOAD,
284 SPDY_INVALID_CONTROL_FRAME, // Control frame is mal-formatted.
285 SPDY_CONTROL_PAYLOAD_TOO_LARGE, // Control frame payload was too large.
286 SPDY_ZLIB_INIT_FAILURE, // The Zlib library could not initialize.
287 SPDY_UNSUPPORTED_VERSION, // Control frame has unsupported version.
288 SPDY_DECOMPRESS_FAILURE, // There was an error decompressing.
289 SPDY_COMPRESS_FAILURE, // There was an error compressing.
290 SPDY_CREDENTIAL_FRAME_CORRUPT, // CREDENTIAL frame could not be parsed.
291 SPDY_INVALID_DATA_FRAME_FLAGS, // Data frame has invalid flags.
292 SPDY_INVALID_CONTROL_FRAME_FLAGS, // Control frame has invalid flags.
294 LAST_ERROR, // Must be the last entry in the enum.
297 // Constant for invalid (or unknown) stream IDs.
298 static const SpdyStreamId kInvalidStream;
300 // The maximum size of header data chunks delivered to the framer visitor
301 // through OnControlFrameHeaderData. (It is exposed here for unit test
303 static const size_t kHeaderDataChunkMaxSize;
305 // Serializes a SpdyHeaderBlock.
306 static void WriteHeaderBlock(SpdyFrameBuilder* frame,
307 const int spdy_version,
308 const SpdyHeaderBlock* headers);
310 // Retrieve serialized length of SpdyHeaderBlock.
311 // TODO(hkhalil): Remove, or move to quic code.
312 static size_t GetSerializedLength(const int spdy_version,
313 const SpdyHeaderBlock* headers);
315 // Create a new Framer, provided a SPDY version.
316 explicit SpdyFramer(SpdyMajorVersion version);
317 virtual ~SpdyFramer();
319 // Set callbacks to be called from the framer. A visitor must be set, or
320 // else the framer will likely crash. It is acceptable for the visitor
321 // to do nothing. If this is called multiple times, only the last visitor
323 void set_visitor(SpdyFramerVisitorInterface* visitor) {
327 // Set debug callbacks to be called from the framer. The debug visitor is
328 // completely optional and need not be set in order for normal operation.
329 // If this is called multiple times, only the last visitor will be used.
330 void set_debug_visitor(SpdyFramerDebugVisitorInterface* debug_visitor) {
331 debug_visitor_ = debug_visitor;
334 // Pass data into the framer for parsing.
335 // Returns the number of bytes consumed. It is safe to pass more bytes in
336 // than may be consumed.
337 size_t ProcessInput(const char* data, size_t len);
339 // Resets the framer state after a frame has been successfully decoded.
340 // TODO(mbelshe): can we make this private?
343 // Check the state of the framer.
344 SpdyError error_code() const { return error_code_; }
345 SpdyState state() const { return state_; }
346 bool HasError() const { return state_ == SPDY_ERROR; }
348 // Given a buffer containing a decompressed header block in SPDY
349 // serialized format, parse out a SpdyHeaderBlock, putting the results
350 // in the given header block.
351 // Returns number of bytes consumed if successfully parsed, 0 otherwise.
352 size_t ParseHeaderBlockInBuffer(const char* header_data,
353 size_t header_length,
354 SpdyHeaderBlock* block) const;
356 // Create a data frame.
357 // |stream_id| is the stream for this frame
358 // |data| is the data to be included in the frame.
359 // |len| is the length of the data
360 // |flags| is the flags to use with the data.
361 // To mark this frame as the last data frame, enable DATA_FLAG_FIN.
362 SpdyFrame* CreateDataFrame(SpdyStreamId stream_id, const char* data,
363 uint32 len, SpdyDataFlags flags) const;
364 SpdySerializedFrame* SerializeData(const SpdyDataIR& data) const;
365 // Serializes just the data frame header, excluding actual data payload.
366 SpdySerializedFrame* SerializeDataFrameHeader(const SpdyDataIR& data) const;
368 // Creates and serializes a SYN_STREAM frame.
369 // |stream_id| is the id for this stream.
370 // |associated_stream_id| is the associated stream id for this stream.
371 // |priority| is the priority (GetHighestPriority()-GetLowestPriority) for
373 // |credential_slot| is the CREDENTIAL slot to be used for this request.
374 // |flags| is the flags to use with the data.
375 // To mark this frame as the last frame, enable CONTROL_FLAG_FIN.
376 // |compressed| specifies whether the frame should be compressed.
377 // |headers| is the header block to include in the frame.
378 SpdyFrame* CreateSynStream(SpdyStreamId stream_id,
379 SpdyStreamId associated_stream_id,
380 SpdyPriority priority,
381 uint8 credential_slot,
382 SpdyControlFlags flags,
384 const SpdyHeaderBlock* headers);
385 SpdySerializedFrame* SerializeSynStream(const SpdySynStreamIR& syn_stream);
387 // Create a SYN_REPLY SpdyFrame.
388 // |stream_id| is the stream for this frame.
389 // |flags| is the flags to use with the data.
390 // To mark this frame as the last frame, enable CONTROL_FLAG_FIN.
391 // |compressed| specifies whether the frame should be compressed.
392 // |headers| is the header block to include in the frame.
393 SpdyFrame* CreateSynReply(SpdyStreamId stream_id,
394 SpdyControlFlags flags,
396 const SpdyHeaderBlock* headers);
397 SpdySerializedFrame* SerializeSynReply(const SpdySynReplyIR& syn_reply);
399 SpdyFrame* CreateRstStream(SpdyStreamId stream_id,
400 SpdyRstStreamStatus status) const;
401 SpdySerializedFrame* SerializeRstStream(
402 const SpdyRstStreamIR& rst_stream) const;
404 // Creates and serializes a SETTINGS frame. The SETTINGS frame is
405 // used to communicate name/value pairs relevant to the communication channel.
406 SpdyFrame* CreateSettings(const SettingsMap& values) const;
407 SpdySerializedFrame* SerializeSettings(const SpdySettingsIR& settings) const;
409 // Creates and serializes a PING frame. The unique_id is used to
410 // identify the ping request/response.
411 SpdyFrame* CreatePingFrame(uint32 unique_id) const;
412 SpdySerializedFrame* SerializePing(const SpdyPingIR& ping) const;
414 // Creates and serializes a GOAWAY frame. The GOAWAY frame is used
415 // prior to the shutting down of the TCP connection, and includes the
416 // stream_id of the last stream the sender of the frame is willing to process
418 SpdyFrame* CreateGoAway(SpdyStreamId last_accepted_stream_id,
419 SpdyGoAwayStatus status) const;
420 SpdySerializedFrame* SerializeGoAway(const SpdyGoAwayIR& goaway) const;
422 // Creates and serializes a HEADERS frame. The HEADERS frame is used
423 // for sending additional headers outside of a SYN_STREAM/SYN_REPLY. The
424 // arguments are the same as for CreateSynReply.
425 SpdyFrame* CreateHeaders(SpdyStreamId stream_id,
426 SpdyControlFlags flags,
428 const SpdyHeaderBlock* headers);
429 SpdySerializedFrame* SerializeHeaders(const SpdyHeadersIR& headers);
431 // Creates and serializes a WINDOW_UPDATE frame. The WINDOW_UPDATE
432 // frame is used to implement per stream flow control in SPDY.
433 SpdyFrame* CreateWindowUpdate(
434 SpdyStreamId stream_id,
435 uint32 delta_window_size) const;
436 SpdySerializedFrame* SerializeWindowUpdate(
437 const SpdyWindowUpdateIR& window_update) const;
439 // Creates and serializes a CREDENTIAL frame. The CREDENTIAL
440 // frame is used to send a client certificate to the server when
441 // request more than one origin are sent over the same SPDY session.
442 SpdyFrame* CreateCredentialFrame(const SpdyCredential& credential) const;
443 SpdySerializedFrame* SerializeCredential(
444 const SpdyCredentialIR& credential) const;
446 // Serializes a BLOCKED frame. The BLOCKED frame is used to indicate to the
447 // remote endpoint that this endpoint believes itself to be flow-control
448 // blocked but otherwise ready to send data. The BLOCKED frame is purely
449 // advisory and optional.
450 SpdySerializedFrame* SerializeBlocked(const SpdyBlockedIR& blocked) const;
452 // Creates and serializes a PUSH_PROMISE frame. The PUSH_PROMISE frame is used
453 // to inform the client that it will be receiving an additional stream
454 // in response to the original request. The frame includes synthesized
455 // headers to explain the upcoming data.
456 SpdyFrame* CreatePushPromise(SpdyStreamId stream_id,
457 SpdyStreamId promised_stream_id,
458 const SpdyHeaderBlock* headers);
459 SpdySerializedFrame* SerializePushPromise(
460 const SpdyPushPromiseIR& push_promise);
462 // Given a CREDENTIAL frame's payload, extract the credential.
463 // Returns true on successful parse, false otherwise.
464 // TODO(hkhalil): Implement CREDENTIAL frame parsing in SpdyFramer
465 // and eliminate this method.
466 static bool ParseCredentialData(const char* data, size_t len,
467 SpdyCredential* credential);
469 // Serialize a frame of unknown type.
470 SpdySerializedFrame* SerializeFrame(const SpdyFrameIR& frame);
472 // NOTES about frame compression.
473 // We want spdy to compress headers across the entire session. As long as
474 // the session is over TCP, frames are sent serially. The client & server
475 // can each compress frames in the same order and then compress them in that
476 // order, and the remote can do the reverse. However, we ultimately want
477 // the creation of frames to be less sensitive to order so that they can be
478 // placed over a UDP based protocol and yet still benefit from some
479 // compression. We don't know of any good compression protocol which does
480 // not build its state in a serial (stream based) manner.... For now, we're
481 // using zlib anyway.
483 // Compresses a SpdyFrame.
484 // On success, returns a new SpdyFrame with the payload compressed.
485 // Compression state is maintained as part of the SpdyFramer.
486 // Returned frame must be freed with "delete".
487 // On failure, returns NULL.
488 SpdyFrame* CompressFrame(const SpdyFrame& frame);
490 // For ease of testing and experimentation we can tweak compression on/off.
491 void set_enable_compression(bool value) {
492 enable_compression_ = value;
495 // Used only in log messages.
496 void set_display_protocol(const std::string& protocol) {
497 display_protocol_ = protocol;
500 // Returns the (minimum) size of frames (sans variable-length portions).
501 size_t GetDataFrameMinimumSize() const;
502 size_t GetControlFrameHeaderSize() const;
503 size_t GetSynStreamMinimumSize() const;
504 size_t GetSynReplyMinimumSize() const;
505 size_t GetRstStreamSize() const;
506 size_t GetSettingsMinimumSize() const;
507 size_t GetPingSize() const;
508 size_t GetGoAwaySize() const;
509 size_t GetHeadersMinimumSize() const;
510 size_t GetWindowUpdateSize() const;
511 size_t GetCredentialMinimumSize() const;
512 size_t GetBlockedSize() const;
513 size_t GetPushPromiseMinimumSize() const;
515 // Returns the minimum size a frame can be (data or control).
516 size_t GetFrameMinimumSize() const;
518 // Returns the maximum size a frame can be (data or control).
519 size_t GetFrameMaximumSize() const;
521 // Returns the maximum payload size of a DATA frame.
522 size_t GetDataFrameMaximumPayload() const;
525 static const char* StateToString(int state);
526 static const char* ErrorCodeToString(int error_code);
527 static const char* StatusCodeToString(int status_code);
528 static const char* FrameTypeToString(SpdyFrameType type);
530 SpdyMajorVersion protocol_version() const { return spdy_version_; }
532 bool probable_http_response() const { return probable_http_response_; }
534 SpdyPriority GetLowestPriority() const { return spdy_version_ < 3 ? 3 : 7; }
535 SpdyPriority GetHighestPriority() const { return 0; }
537 // Deliver the given control frame's compressed headers block to the visitor
538 // in decompressed form, in chunks. Returns true if the visitor has
539 // accepted all of the chunks.
540 bool IncrementallyDecompressControlFrameHeaderData(
541 SpdyStreamId stream_id,
546 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, BasicCompression);
547 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ControlFrameSizesAreValidated);
548 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, HeaderCompression);
549 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, DecompressUncompressedFrame);
550 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ExpandBuffer_HeapSmash);
551 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, HugeHeaderBlock);
552 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, UnclosedStreamDataCompressors);
553 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest,
554 UnclosedStreamDataCompressorsOneByteAtATime);
555 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest,
556 UncompressLargerThanFrameBufferInitialSize);
557 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ReadLargeSettingsFrame);
558 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest,
559 ReadLargeSettingsFrameInSmallChunks);
560 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ControlFrameAtMaxSizeLimit);
561 FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ControlFrameTooLarge);
562 friend class net::HttpNetworkLayer; // This is temporary for the server.
563 friend class net::HttpNetworkTransactionTest;
564 friend class net::HttpProxyClientSocketPoolTest;
565 friend class net::SpdyHttpStreamTest;
566 friend class net::SpdyNetworkTransactionTest;
567 friend class net::SpdyProxyClientSocketTest;
568 friend class net::SpdySessionTest;
569 friend class net::SpdyStreamTest;
570 friend class net::SpdyWebSocketStreamTest;
571 friend class net::WebSocketJobTest;
572 friend class test::TestSpdyVisitor;
575 // Internal breakouts from ProcessInput. Each returns the number of bytes
576 // consumed from the data.
577 size_t ProcessCommonHeader(const char* data, size_t len);
578 size_t ProcessControlFramePayload(const char* data, size_t len);
579 size_t ProcessCredentialFramePayload(const char* data, size_t len);
580 size_t ProcessControlFrameBeforeHeaderBlock(const char* data, size_t len);
581 size_t ProcessControlFrameHeaderBlock(const char* data, size_t len);
582 size_t ProcessSettingsFramePayload(const char* data, size_t len);
583 size_t ProcessDataFramePayload(const char* data, size_t len);
585 // Helpers for above internal breakouts from ProcessInput.
586 void ProcessControlFrameHeader(uint16 control_frame_type_field);
587 bool ProcessSetting(const char* data); // Always passed exactly 8 bytes.
589 // Retrieve serialized length of SpdyHeaderBlock. If compression is enabled, a
590 // maximum estimate is returned.
591 size_t GetSerializedLength(const SpdyHeaderBlock& headers);
593 // Get (and lazily initialize) the ZLib state.
594 z_stream* GetHeaderCompressor();
595 z_stream* GetHeaderDecompressor();
598 // Deliver the given control frame's uncompressed headers block to the
599 // visitor in chunks. Returns true if the visitor has accepted all of the
601 bool IncrementallyDeliverControlFrameHeaderData(SpdyStreamId stream_id,
605 // Utility to copy the given data block to the current frame buffer, up
606 // to the given maximum number of bytes, and update the buffer
607 // data (pointer and length). Returns the number of bytes
609 // *data is advanced the number of bytes read.
610 // *len is reduced by the number of bytes read.
611 size_t UpdateCurrentFrameBuffer(const char** data, size_t* len,
614 void WriteHeaderBlockToZ(const SpdyHeaderBlock* headers,
615 z_stream* out) const;
617 void SerializeNameValueBlockWithoutCompression(
618 SpdyFrameBuilder* builder,
619 const SpdyNameValueBlock& name_value_block) const;
621 // Compresses automatically according to enable_compression_.
622 void SerializeNameValueBlock(
623 SpdyFrameBuilder* builder,
624 const SpdyFrameWithNameValueBlockIR& frame);
626 // Set the error code and moves the framer into the error state.
627 void set_error(SpdyError error);
629 // The maximum size of the control frames that we support.
630 // This limit is arbitrary. We can enforce it here or at the application
631 // layer. We chose the framing layer, but this can be changed (or removed)
632 // if necessary later down the line.
633 size_t GetControlFrameBufferMaxSize() const {
634 // The theoretical maximum for SPDY3 and earlier is (2^24 - 1) +
635 // 8, since the length field does not count the size of the
637 if (spdy_version_ == SPDY2) {
640 if (spdy_version_ == SPDY3) {
641 return 16 * 1024 * 1024;
643 // The theoretical maximum for SPDY4 is 2^16 - 1, as the length
644 // field does count the size of the header.
648 // The size of the control frame buffer.
649 // Since this is only used for control frame headers, the maximum control
650 // frame header size (SYN_STREAM) is sufficient; all remaining control
651 // frame data is streamed to the visitor.
652 static const size_t kControlFrameBufferSize;
655 SpdyState previous_state_;
656 SpdyError error_code_;
657 size_t remaining_data_length_;
659 // The number of bytes remaining to read from the current control frame's
660 // headers. Note that header data blocks (for control types that have them)
661 // are part of the frame's payload, and not the frame's headers.
662 size_t remaining_control_header_;
664 scoped_ptr<char[]> current_frame_buffer_;
665 // Number of bytes read into the current_frame_buffer_.
666 size_t current_frame_buffer_length_;
668 // The type of the frame currently being read.
669 SpdyFrameType current_frame_type_;
671 // The flags field of the frame currently being read.
672 uint8 current_frame_flags_;
674 // The total length of the frame currently being read, including frame header.
675 uint32 current_frame_length_;
677 // The stream ID field of the frame currently being read, if applicable.
678 SpdyStreamId current_frame_stream_id_;
680 // Scratch space for handling SETTINGS frames.
681 // TODO(hkhalil): Unify memory for this scratch space with
682 // current_frame_buffer_.
683 SpdySettingsScratch settings_scratch_;
685 bool enable_compression_; // Controls all compression
686 // SPDY header compressors.
687 scoped_ptr<z_stream> header_compressor_;
688 scoped_ptr<z_stream> header_decompressor_;
690 SpdyFramerVisitorInterface* visitor_;
691 SpdyFramerDebugVisitorInterface* debug_visitor_;
693 std::string display_protocol_;
695 // The major SPDY version to be spoken/understood by this framer.
696 const SpdyMajorVersion spdy_version_;
698 // Tracks if we've ever gotten far enough in framing to see a control frame of
699 // type SYN_STREAM or SYN_REPLY.
701 // If we ever get something which looks like a data frame before we've had a
702 // SYN, we explicitly check to see if it looks like we got an HTTP response to
703 // a SPDY request. This boolean lets us do that.
704 bool syn_frame_processed_;
706 // If we ever get a data frame before a SYN frame, we check to see if it
707 // starts with HTTP. If it does, we likely have an HTTP response. This
708 // isn't guaranteed though: we could have gotten a settings frame and then
709 // corrupt data that just looks like HTTP, but deterministic checking requires
711 bool probable_http_response_;
716 #endif // NET_SPDY_SPDY_FRAMER_H_