• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 #pragma once
8 
9 #include <list>
10 #include <map>
11 #include <string>
12 #include <utility>
13 
14 #include "base/basictypes.h"
15 #include "base/gtest_prod_util.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "net/base/sys_byteorder.h"
18 #include "net/spdy/spdy_protocol.h"
19 
20 typedef struct z_stream_s z_stream;  // Forward declaration for zlib.
21 
22 namespace net {
23 class HttpProxyClientSocketPoolTest;
24 class HttpNetworkLayer;
25 class HttpNetworkTransactionTest;
26 class SpdyHttpStreamTest;
27 class SpdyNetworkTransactionTest;
28 class SpdyProxyClientSocketTest;
29 class SpdySessionTest;
30 class SpdyStreamTest;
31 }
32 
33 namespace spdy {
34 
35 class SpdyFramer;
36 class SpdyFramerTest;
37 
38 namespace test {
39 class TestSpdyVisitor;
40 void FramerSetEnableCompressionHelper(SpdyFramer* framer, bool compress);
41 }  // namespace test
42 
43 // A datastructure for holding a set of headers from either a
44 // SYN_STREAM or SYN_REPLY frame.
45 typedef std::map<std::string, std::string> SpdyHeaderBlock;
46 
47 // A datastructure for holding a set of ID/value pairs for a SETTINGS frame.
48 typedef std::pair<spdy::SettingsFlagsAndId, uint32> SpdySetting;
49 typedef std::list<SpdySetting> SpdySettings;
50 
51 // SpdyFramerVisitorInterface is a set of callbacks for the SpdyFramer.
52 // Implement this interface to receive event callbacks as frames are
53 // decoded from the framer.
54 class SpdyFramerVisitorInterface {
55  public:
~SpdyFramerVisitorInterface()56   virtual ~SpdyFramerVisitorInterface() {}
57 
58   // Called if an error is detected in the SpdyFrame protocol.
59   virtual void OnError(SpdyFramer* framer) = 0;
60 
61   // Called when a control frame is received.
62   virtual void OnControl(const SpdyControlFrame* frame) = 0;
63 
64   // Called when a chunk of header data is available. This is called
65   // after OnControl() is called with the control frame associated with the
66   // header data being delivered here.
67   // |stream_id| The stream receiving the header data.
68   // |header_data| A buffer containing the header data chunk received.
69   // |len| The length of the header data buffer. A length of zero indicates
70   //       that the header data block has been completely sent.
71   // When this function returns true the visitor indicates that it accepted
72   // all of the data. Returning false indicates that that an unrecoverable
73   // error has occurred, such as bad header data or resource exhaustion.
74   virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id,
75                                         const char* header_data,
76                                         size_t len) = 0;
77 
78   // Called when a data frame header is received. The frame's data
79   // payload will be provided via subsequent calls to
80   // OnStreamFrameData().
81   virtual void OnDataFrameHeader(const SpdyDataFrame* frame) = 0;
82 
83   // Called when data is received.
84   // |stream_id| The stream receiving data.
85   // |data| A buffer containing the data received.
86   // |len| The length of the data buffer.
87   // When the other side has finished sending data on this stream,
88   // this method will be called with a zero-length buffer.
89   virtual void OnStreamFrameData(SpdyStreamId stream_id,
90                                  const char* data,
91                                  size_t len) = 0;
92 };
93 
94 class SpdyFramer {
95  public:
96   // SPDY states.
97   // TODO(mbelshe): Can we move these into the implementation
98   //                and avoid exposing through the header.  (Needed for test)
99   enum SpdyState {
100     SPDY_ERROR,
101     SPDY_DONE,
102     SPDY_RESET,
103     SPDY_AUTO_RESET,
104     SPDY_READING_COMMON_HEADER,
105     SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER,
106     SPDY_CONTROL_FRAME_PAYLOAD,
107     SPDY_IGNORE_REMAINING_PAYLOAD,
108     SPDY_FORWARD_STREAM_FRAME,
109     SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK,
110     SPDY_CONTROL_FRAME_HEADER_BLOCK,
111   };
112 
113   // SPDY error codes.
114   enum SpdyError {
115     SPDY_NO_ERROR,
116     SPDY_INVALID_CONTROL_FRAME,      // Control frame is mal-formatted.
117     SPDY_CONTROL_PAYLOAD_TOO_LARGE,  // Control frame payload was too large.
118     SPDY_ZLIB_INIT_FAILURE,          // The Zlib library could not initialize.
119     SPDY_UNSUPPORTED_VERSION,        // Control frame has unsupported version.
120     SPDY_DECOMPRESS_FAILURE,         // There was an error decompressing.
121     SPDY_COMPRESS_FAILURE,           // There was an error compressing.
122 
123     LAST_ERROR,  // Must be the last entry in the enum.
124   };
125 
126   // Constant for invalid (or unknown) stream IDs.
127   static const SpdyStreamId kInvalidStream;
128 
129   // The maximum size of header data chunks delivered to the framer visitor
130   // through OnControlFrameHeaderData. (It is exposed here for unit test
131   // purposes.)
132   static const size_t kHeaderDataChunkMaxSize;
133 
134   // Create a new Framer.
135   SpdyFramer();
136   virtual ~SpdyFramer();
137 
138   // Set callbacks to be called from the framer.  A visitor must be set, or
139   // else the framer will likely crash.  It is acceptable for the visitor
140   // to do nothing.  If this is called multiple times, only the last visitor
141   // will be used.
set_visitor(SpdyFramerVisitorInterface * visitor)142   void set_visitor(SpdyFramerVisitorInterface* visitor) {
143     visitor_ = visitor;
144   }
145 
146   // Pass data into the framer for parsing.
147   // Returns the number of bytes consumed. It is safe to pass more bytes in
148   // than may be consumed.
149   size_t ProcessInput(const char* data, size_t len);
150 
151   // Resets the framer state after a frame has been successfully decoded.
152   // TODO(mbelshe): can we make this private?
153   void Reset();
154 
155   // Check the state of the framer.
error_code()156   SpdyError error_code() const { return error_code_; }
state()157   SpdyState state() const { return state_; }
158 
MessageFullyRead()159   bool MessageFullyRead() {
160     return state_ == SPDY_DONE || state_ == SPDY_AUTO_RESET;
161   }
HasError()162   bool HasError() { return state_ == SPDY_ERROR; }
163 
164   // Further parsing utilities.
165   // Given a control frame, parse out a SpdyHeaderBlock.  Only
166   // valid for SYN_STREAM and SYN_REPLY frames.
167   // Returns true if successfully parsed, false otherwise.
168   bool ParseHeaderBlock(const SpdyFrame* frame, SpdyHeaderBlock* block);
169 
170   // Given a buffer containing a decompressed header block in SPDY
171   // serialized format, parse out a SpdyHeaderBlock, putting the results
172   // in the given header block.
173   // Returns true if successfully parsed, false otherwise.
174   static bool ParseHeaderBlockInBuffer(const char* header_data,
175                                        size_t header_length,
176                                        SpdyHeaderBlock* block);
177 
178   // Create a SpdySynStreamControlFrame.
179   // |stream_id| is the id for this stream.
180   // |associated_stream_id| is the associated stream id for this stream.
181   // |priority| is the priority (0-3) for this stream.
182   // |flags| is the flags to use with the data.
183   //    To mark this frame as the last frame, enable CONTROL_FLAG_FIN.
184   // |compressed| specifies whether the frame should be compressed.
185   // |headers| is the header block to include in the frame.
186   SpdySynStreamControlFrame* CreateSynStream(SpdyStreamId stream_id,
187                                              SpdyStreamId associated_stream_id,
188                                              int priority,
189                                              SpdyControlFlags flags,
190                                              bool compressed,
191                                              const SpdyHeaderBlock* headers);
192 
193   // Create a SpdySynReplyControlFrame.
194   // |stream_id| is the stream for this frame.
195   // |flags| is the flags to use with the data.
196   //    To mark this frame as the last frame, enable CONTROL_FLAG_FIN.
197   // |compressed| specifies whether the frame should be compressed.
198   // |headers| is the header block to include in the frame.
199   SpdySynReplyControlFrame* CreateSynReply(SpdyStreamId stream_id,
200                                            SpdyControlFlags flags,
201                                            bool compressed,
202                                            const SpdyHeaderBlock* headers);
203 
204   static SpdyRstStreamControlFrame* CreateRstStream(SpdyStreamId stream_id,
205                                                     SpdyStatusCodes status);
206 
207   // Creates an instance of SpdySettingsControlFrame. The SETTINGS frame is
208   // used to communicate name/value pairs relevant to the communication channel.
209   // TODO(mbelshe): add the name/value pairs!!
210   static SpdySettingsControlFrame* CreateSettings(const SpdySettings& values);
211 
212   static SpdyNoOpControlFrame* CreateNopFrame();
213 
214   // Creates an instance of SpdyPingControlFrame. The unique_id is used to
215   // identify the ping request/response.
216   static SpdyPingControlFrame* CreatePingFrame(uint32 unique_id);
217 
218   // Creates an instance of SpdyGoAwayControlFrame. The GOAWAY frame is used
219   // prior to the shutting down of the TCP connection, and includes the
220   // stream_id of the last stream the sender of the frame is willing to process
221   // to completion.
222   static SpdyGoAwayControlFrame* CreateGoAway(
223       SpdyStreamId last_accepted_stream_id);
224 
225   // Creates an instance of SpdyHeadersControlFrame. The HEADERS frame is used
226   // for sending additional headers outside of a SYN_STREAM/SYN_REPLY. The
227   // arguments are the same as for CreateSynReply.
228   SpdyHeadersControlFrame* CreateHeaders(SpdyStreamId stream_id,
229                                          SpdyControlFlags flags,
230                                          bool compressed,
231                                          const SpdyHeaderBlock* headers);
232 
233   // Creates an instance of SpdyWindowUpdateControlFrame. The WINDOW_UPDATE
234   // frame is used to implement per stream flow control in SPDY.
235   static SpdyWindowUpdateControlFrame* CreateWindowUpdate(
236       SpdyStreamId stream_id,
237       uint32 delta_window_size);
238 
239   // Given a SpdySettingsControlFrame, extract the settings.
240   // Returns true on successful parse, false otherwise.
241   static bool ParseSettings(const SpdySettingsControlFrame* frame,
242       SpdySettings* settings);
243 
244   // Create a data frame.
245   // |stream_id| is the stream  for this frame
246   // |data| is the data to be included in the frame.
247   // |len| is the length of the data
248   // |flags| is the flags to use with the data.
249   //    To create a compressed frame, enable DATA_FLAG_COMPRESSED.
250   //    To mark this frame as the last data frame, enable DATA_FLAG_FIN.
251   SpdyDataFrame* CreateDataFrame(SpdyStreamId stream_id, const char* data,
252                                  uint32 len, SpdyDataFlags flags);
253 
254   // NOTES about frame compression.
255   // We want spdy to compress headers across the entire session.  As long as
256   // the session is over TCP, frames are sent serially.  The client & server
257   // can each compress frames in the same order and then compress them in that
258   // order, and the remote can do the reverse.  However, we ultimately want
259   // the creation of frames to be less sensitive to order so that they can be
260   // placed over a UDP based protocol and yet still benefit from some
261   // compression.  We don't know of any good compression protocol which does
262   // not build its state in a serial (stream based) manner....  For now, we're
263   // using zlib anyway.
264 
265   // Compresses a SpdyFrame.
266   // On success, returns a new SpdyFrame with the payload compressed.
267   // Compression state is maintained as part of the SpdyFramer.
268   // Returned frame must be freed with "delete".
269   // On failure, returns NULL.
270   SpdyFrame* CompressFrame(const SpdyFrame& frame);
271 
272   // Decompresses a SpdyFrame.
273   // On success, returns a new SpdyFrame with the payload decompressed.
274   // Compression state is maintained as part of the SpdyFramer.
275   // Returned frame must be freed with "delete".
276   // On failure, returns NULL.
277   SpdyFrame* DecompressFrame(const SpdyFrame& frame);
278 
279   // Create a copy of a frame.
280   // Returned frame must be freed with "delete".
281   SpdyFrame* DuplicateFrame(const SpdyFrame& frame);
282 
283   // Returns true if a frame could be compressed.
284   bool IsCompressible(const SpdyFrame& frame) const;
285 
286   // Get the minimum size of the control frame for the given control frame
287   // type. This is useful for validating frame blocks.
288   static size_t GetMinimumControlFrameSize(SpdyControlType type);
289 
290   // Get the stream ID for the given control frame (SYN_STREAM, SYN_REPLY, and
291   // HEADERS). If the control frame is NULL or of another type, this
292   // function returns kInvalidStream.
293   static SpdyStreamId GetControlFrameStreamId(
294       const SpdyControlFrame* control_frame);
295 
296   // For ease of testing and experimentation we can tweak compression on/off.
297   void set_enable_compression(bool value);
298 
299   // SPDY will by default validate the length of incoming control
300   // frames. Set validation to false if you do not want this behavior.
301   void set_validate_control_frame_sizes(bool value);
302   static void set_enable_compression_default(bool value);
303 
304   // For debugging.
305   static const char* StateToString(int state);
306   static const char* ErrorCodeToString(int error_code);
307   static const char* StatusCodeToString(int status_code);
308   static const char* ControlTypeToString(SpdyControlType type);
set_protocol_version(int version)309   static void set_protocol_version(int version) { spdy_version_= version; }
protocol_version()310   static int protocol_version() { return spdy_version_; }
311 
312   // Export the compression dictionary
313   static const char kDictionary[];
314   static const int kDictionarySize;
315 
316  protected:
317   FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, DataCompression);
318   FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ExpandBuffer_HeapSmash);
319   FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, HugeHeaderBlock);
320   FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, UnclosedStreamDataCompressors);
321   FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest,
322                            UncompressLargerThanFrameBufferInitialSize);
323   friend class net::HttpNetworkLayer;  // This is temporary for the server.
324   friend class net::HttpNetworkTransactionTest;
325   friend class net::HttpProxyClientSocketPoolTest;
326   friend class net::SpdyHttpStreamTest;
327   friend class net::SpdyNetworkTransactionTest;
328   friend class net::SpdyProxyClientSocketTest;
329   friend class net::SpdySessionTest;
330   friend class net::SpdyStreamTest;
331   friend class test::TestSpdyVisitor;
332   friend void test::FramerSetEnableCompressionHelper(SpdyFramer* framer,
333                                                      bool compress);
334 
335   // The initial size of the control frame buffer; this is used internally
336   // as we parse through control frames. (It is exposed here for unit test
337   // purposes.)
338   // This is only used when compression is enabled; otherwise,
339   // kUncompressedControlFrameBufferInitialSize is used.
340   static size_t kControlFrameBufferInitialSize;
341 
342   // The maximum size of the control frame buffer that we support.
343   // TODO(mbelshe): We should make this stream-based so there are no limits.
344   static size_t kControlFrameBufferMaxSize;
345 
346  private:
347   typedef std::map<SpdyStreamId, z_stream*> CompressorMap;
348 
349   // Internal breakout from ProcessInput.  Returns the number of bytes
350   // consumed from the data.
351   size_t ProcessCommonHeader(const char* data, size_t len);
352   void ProcessControlFrameHeader();
353   size_t ProcessControlFramePayload(const char* data, size_t len);
354   size_t ProcessControlFrameBeforeHeaderBlock(const char* data, size_t len);
355   // TODO(hkhalil): Rename to ProcessControlFrameHeaderBlock once said flag is
356   // removed, replacing the old method.
357   size_t NewProcessControlFrameHeaderBlock(const char* data, size_t len);
358   size_t ProcessControlFrameHeaderBlock(const char* data, size_t len);
359   size_t ProcessDataFramePayload(const char* data, size_t len);
360 
361   // Get (and lazily initialize) the ZLib state.
362   z_stream* GetHeaderCompressor();
363   z_stream* GetHeaderDecompressor();
364   z_stream* GetStreamCompressor(SpdyStreamId id);
365   z_stream* GetStreamDecompressor(SpdyStreamId id);
366 
367   // Compression helpers
368   SpdyControlFrame* CompressControlFrame(const SpdyControlFrame& frame);
369   SpdyDataFrame* CompressDataFrame(const SpdyDataFrame& frame);
370   SpdyControlFrame* DecompressControlFrame(const SpdyControlFrame& frame);
371   SpdyDataFrame* DecompressDataFrame(const SpdyDataFrame& frame);
372   SpdyFrame* CompressFrameWithZStream(const SpdyFrame& frame,
373                                       z_stream* compressor);
374   SpdyFrame* DecompressFrameWithZStream(const SpdyFrame& frame,
375                                         z_stream* decompressor);
376   void CleanupCompressorForStream(SpdyStreamId id);
377   void CleanupDecompressorForStream(SpdyStreamId id);
378   void CleanupStreamCompressorsAndDecompressors();
379 
380   // Not used (yet)
381   size_t BytesSafeToRead() const;
382 
383   // Deliver the given control frame's compressed headers block to the visitor
384   // in decompressed form, in chunks. Returns true if the visitor has
385   // accepted all of the chunks.
386   bool IncrementallyDecompressControlFrameHeaderData(
387       const SpdyControlFrame* frame);
388 
389   // Deliver the given control frame's compressed headers block to the visitor
390   // in decompressed form, in chunks. Returns true if the visitor has
391   // accepted all of the chunks.
392   bool IncrementallyDecompressControlFrameHeaderData(
393       const SpdyControlFrame* frame,
394       const char* data,
395       size_t len);
396 
397   // Deliver the given control frame's uncompressed headers block to the
398   // visitor in chunks. Returns true if the visitor has accepted all of the
399   // chunks.
400   bool IncrementallyDeliverControlFrameHeaderData(const SpdyControlFrame* frame,
401                                                   const char* data,
402                                                   size_t len);
403 
404   // Utility to copy the given data block to the current frame buffer, up
405   // to the given maximum number of bytes, and update the buffer
406   // data (pointer and length). Returns the number of bytes
407   // read, and:
408   //   *data is advanced the number of bytes read.
409   //   *len is reduced by the number of bytes read.
410   size_t UpdateCurrentFrameBuffer(const char** data, size_t* len,
411                                   size_t max_bytes);
412 
413   // Set the error code and moves the framer into the error state.
414   void set_error(SpdyError error);
415 
416   // Expands the control frame buffer to accomodate a particular payload size.
417   void ExpandControlFrameBuffer(size_t size);
418 
419   // Given a frame, breakdown the variable payload length, the static header
420   // header length, and variable payload pointer.
421   bool GetFrameBoundaries(const SpdyFrame& frame, int* payload_length,
422                           int* header_length, const char** payload) const;
423 
num_stream_compressors()424   int num_stream_compressors() const { return stream_compressors_.size(); }
num_stream_decompressors()425   int num_stream_decompressors() const { return stream_decompressors_.size(); }
426 
427   // The initial size of the control frame buffer when compression is disabled.
428   // This exists because we don't do stream (de)compressed control frame data to
429   // our visitor; we instead buffer the entirety of the control frame and then
430   // decompress in one fell swoop.
431   // Since this is only used for control frame headers, the maximum control
432   // frame header size (18B) is sufficient; all remaining control frame data is
433   // streamed to the visitor.
434   // In addition to the maximum control frame header size, we account for any
435   // LOAS checksumming (16B) that may occur in the VTL case.
436   static const size_t kUncompressedControlFrameBufferInitialSize = 18 + 16;
437 
438   // The size of the buffer into which compressed frames are inflated.
439   static const size_t kDecompressionBufferSize = 8 * 1024;
440 
441   SpdyState state_;
442   SpdyError error_code_;
443   size_t remaining_data_;
444 
445   // The number of bytes remaining to read from the current control frame's
446   // payload.
447   size_t remaining_control_payload_;
448 
449   // The number of bytes remaining to read from the current control frame's
450   // headers. Note that header data blocks (for control types that have them)
451   // are part of the frame's payload, and not the frame's headers.
452   size_t remaining_control_header_;
453 
454   char* current_frame_buffer_;
455   size_t current_frame_len_;  // Number of bytes read into the current_frame_.
456   size_t current_frame_capacity_;
457 
458   bool validate_control_frame_sizes_;
459   bool enable_compression_;  // Controls all compression
460   // SPDY header compressors.
461   scoped_ptr<z_stream> header_compressor_;
462   scoped_ptr<z_stream> header_decompressor_;
463 
464   // Per-stream data compressors.
465   CompressorMap stream_compressors_;
466   CompressorMap stream_decompressors_;
467 
468   SpdyFramerVisitorInterface* visitor_;
469 
470   static bool compression_default_;
471   static int spdy_version_;
472 };
473 
474 }  // namespace spdy
475 
476 #endif  // NET_SPDY_SPDY_FRAMER_H_
477