• 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 data is received.
65   // |stream_id| The stream receiving data.
66   // |data| A buffer containing the data received.
67   // |len| The length of the data buffer.
68   // When the other side has finished sending data on this stream,
69   // this method will be called with a zero-length buffer.
70   virtual void OnStreamFrameData(SpdyStreamId stream_id,
71                                  const char* data,
72                                  size_t len) = 0;
73 };
74 
75 class SpdyFramer {
76  public:
77   // SPDY states.
78   // TODO(mbelshe): Can we move these into the implementation
79   //                and avoid exposing through the header.  (Needed for test)
80   enum SpdyState {
81     SPDY_ERROR,
82     SPDY_DONE,
83     SPDY_RESET,
84     SPDY_AUTO_RESET,
85     SPDY_READING_COMMON_HEADER,
86     SPDY_INTERPRET_CONTROL_FRAME_COMMON_HEADER,
87     SPDY_CONTROL_FRAME_PAYLOAD,
88     SPDY_IGNORE_REMAINING_PAYLOAD,
89     SPDY_FORWARD_STREAM_FRAME
90   };
91 
92   // SPDY error codes.
93   enum SpdyError {
94     SPDY_NO_ERROR,
95     SPDY_INVALID_CONTROL_FRAME,      // Control frame is mal-formatted.
96     SPDY_CONTROL_PAYLOAD_TOO_LARGE,  // Control frame payload was too large.
97     SPDY_ZLIB_INIT_FAILURE,          // The Zlib library could not initialize.
98     SPDY_UNSUPPORTED_VERSION,        // Control frame has unsupported version.
99     SPDY_DECOMPRESS_FAILURE,         // There was an error decompressing.
100     SPDY_COMPRESS_FAILURE,           // There was an error compressing.
101 
102     LAST_ERROR,  // Must be the last entry in the enum.
103   };
104 
105   // Create a new Framer.
106   SpdyFramer();
107   virtual ~SpdyFramer();
108 
109   // Set callbacks to be called from the framer.  A visitor must be set, or
110   // else the framer will likely crash.  It is acceptable for the visitor
111   // to do nothing.  If this is called multiple times, only the last visitor
112   // will be used.
set_visitor(SpdyFramerVisitorInterface * visitor)113   void set_visitor(SpdyFramerVisitorInterface* visitor) {
114     visitor_ = visitor;
115   }
116 
117   // Pass data into the framer for parsing.
118   // Returns the number of bytes consumed. It is safe to pass more bytes in
119   // than may be consumed.
120   size_t ProcessInput(const char* data, size_t len);
121 
122   // Resets the framer state after a frame has been successfully decoded.
123   // TODO(mbelshe): can we make this private?
124   void Reset();
125 
126   // Check the state of the framer.
error_code()127   SpdyError error_code() const { return error_code_; }
state()128   SpdyState state() const { return state_; }
129 
MessageFullyRead()130   bool MessageFullyRead() {
131     return state_ == SPDY_DONE || state_ == SPDY_AUTO_RESET;
132   }
HasError()133   bool HasError() { return state_ == SPDY_ERROR; }
134 
135   // Further parsing utilities.
136   // Given a control frame, parse out a SpdyHeaderBlock.  Only
137   // valid for SYN_STREAM and SYN_REPLY frames.
138   // Returns true if successfully parsed, false otherwise.
139   bool ParseHeaderBlock(const SpdyFrame* frame, SpdyHeaderBlock* block);
140 
141   // Create a SpdySynStreamControlFrame.
142   // |stream_id| is the id for this stream.
143   // |associated_stream_id| is the associated stream id for this stream.
144   // |priority| is the priority (0-3) for this stream.
145   // |flags| is the flags to use with the data.
146   //    To mark this frame as the last frame, enable CONTROL_FLAG_FIN.
147   // |compressed| specifies whether the frame should be compressed.
148   // |headers| is the header block to include in the frame.
149   SpdySynStreamControlFrame* CreateSynStream(SpdyStreamId stream_id,
150                                              SpdyStreamId associated_stream_id,
151                                              int priority,
152                                              SpdyControlFlags flags,
153                                              bool compressed,
154                                              SpdyHeaderBlock* headers);
155 
156   // Create a SpdySynReplyControlFrame.
157   // |stream_id| is the stream for this frame.
158   // |flags| is the flags to use with the data.
159   //    To mark this frame as the last frame, enable CONTROL_FLAG_FIN.
160   // |compressed| specifies whether the frame should be compressed.
161   // |headers| is the header block to include in the frame.
162   SpdySynReplyControlFrame* CreateSynReply(SpdyStreamId stream_id,
163                                            SpdyControlFlags flags,
164                                            bool compressed,
165                                            SpdyHeaderBlock* headers);
166 
167   static SpdyRstStreamControlFrame* CreateRstStream(SpdyStreamId stream_id,
168                                                     SpdyStatusCodes status);
169 
170   // Creates an instance of SpdySettingsControlFrame. The SETTINGS frame is
171   // used to communicate name/value pairs relevant to the communication channel.
172   // TODO(mbelshe): add the name/value pairs!!
173   static SpdySettingsControlFrame* CreateSettings(const SpdySettings& values);
174 
175   static SpdyControlFrame* CreateNopFrame();
176 
177   // Creates an instance of SpdyGoAwayControlFrame. The GOAWAY frame is used
178   // prior to the shutting down of the TCP connection, and includes the
179   // stream_id of the last stream the sender of the frame is willing to process
180   // to completion.
181   static SpdyGoAwayControlFrame* CreateGoAway(
182       SpdyStreamId last_accepted_stream_id);
183 
184   // Creates an instance of SpdyHeadersControlFrame. The HEADERS frame is used
185   // for sending additional headers outside of a SYN_STREAM/SYN_REPLY. The
186   // arguments are the same as for CreateSynReply.
187   SpdyHeadersControlFrame* CreateHeaders(SpdyStreamId stream_id,
188                                          SpdyControlFlags flags,
189                                          bool compressed,
190                                          SpdyHeaderBlock* headers);
191 
192   // Creates an instance of SpdyWindowUpdateControlFrame. The WINDOW_UPDATE
193   // frame is used to implement per stream flow control in SPDY.
194   static SpdyWindowUpdateControlFrame* CreateWindowUpdate(
195       SpdyStreamId stream_id,
196       uint32 delta_window_size);
197 
198   // Given a SpdySettingsControlFrame, extract the settings.
199   // Returns true on successful parse, false otherwise.
200   static bool ParseSettings(const SpdySettingsControlFrame* frame,
201       SpdySettings* settings);
202 
203   // Create a data frame.
204   // |stream_id| is the stream  for this frame
205   // |data| is the data to be included in the frame.
206   // |len| is the length of the data
207   // |flags| is the flags to use with the data.
208   //    To create a compressed frame, enable DATA_FLAG_COMPRESSED.
209   //    To mark this frame as the last data frame, enable DATA_FLAG_FIN.
210   SpdyDataFrame* CreateDataFrame(SpdyStreamId stream_id, const char* data,
211                                  uint32 len, SpdyDataFlags flags);
212 
213   // NOTES about frame compression.
214   // We want spdy to compress headers across the entire session.  As long as
215   // the session is over TCP, frames are sent serially.  The client & server
216   // can each compress frames in the same order and then compress them in that
217   // order, and the remote can do the reverse.  However, we ultimately want
218   // the creation of frames to be less sensitive to order so that they can be
219   // placed over a UDP based protocol and yet still benefit from some
220   // compression.  We don't know of any good compression protocol which does
221   // not build its state in a serial (stream based) manner....  For now, we're
222   // using zlib anyway.
223 
224   // Compresses a SpdyFrame.
225   // On success, returns a new SpdyFrame with the payload compressed.
226   // Compression state is maintained as part of the SpdyFramer.
227   // Returned frame must be freed with "delete".
228   // On failure, returns NULL.
229   SpdyFrame* CompressFrame(const SpdyFrame& frame);
230 
231   // Decompresses a SpdyFrame.
232   // On success, returns a new SpdyFrame with the payload decompressed.
233   // Compression state is maintained as part of the SpdyFramer.
234   // Returned frame must be freed with "delete".
235   // On failure, returns NULL.
236   SpdyFrame* DecompressFrame(const SpdyFrame& frame);
237 
238   // Create a copy of a frame.
239   // Returned frame must be freed with "delete".
240   SpdyFrame* DuplicateFrame(const SpdyFrame& frame);
241 
242   // Returns true if a frame could be compressed.
243   bool IsCompressible(const SpdyFrame& frame) const;
244 
245   // For debugging.
246   static const char* StateToString(int state);
247   static const char* ErrorCodeToString(int error_code);
set_protocol_version(int version)248   static void set_protocol_version(int version) { spdy_version_= version; }
protocol_version()249   static int protocol_version() { return spdy_version_; }
250 
251   // Export the compression dictionary
252   static const char kDictionary[];
253   static const int kDictionarySize;
254 
255  protected:
256   FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, DataCompression);
257   FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ExpandBuffer_HeapSmash);
258   FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, HugeHeaderBlock);
259   FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, UnclosedStreamDataCompressors);
260   FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest,
261                            UncompressLargerThanFrameBufferInitialSize);
262   friend class net::HttpNetworkLayer;  // This is temporary for the server.
263   friend class net::HttpNetworkTransactionTest;
264   friend class net::HttpProxyClientSocketPoolTest;
265   friend class net::SpdyHttpStreamTest;
266   friend class net::SpdyNetworkTransactionTest;
267   friend class net::SpdyProxyClientSocketTest;
268   friend class net::SpdySessionTest;
269   friend class net::SpdyStreamTest;
270   friend class test::TestSpdyVisitor;
271   friend void test::FramerSetEnableCompressionHelper(SpdyFramer* framer,
272                                                      bool compress);
273 
274   // For ease of testing we can tweak compression on/off.
275   void set_enable_compression(bool value);
276   static void set_enable_compression_default(bool value);
277 
278 
279   // The initial size of the control frame buffer; this is used internally
280   // as we parse through control frames. (It is exposed here for unit test
281   // purposes.)
282   static size_t kControlFrameBufferInitialSize;
283 
284   // The maximum size of the control frame buffer that we support.
285   // TODO(mbelshe): We should make this stream-based so there are no limits.
286   static size_t kControlFrameBufferMaxSize;
287 
288  private:
289   typedef std::map<SpdyStreamId, z_stream*> CompressorMap;
290 
291   // Internal breakout from ProcessInput.  Returns the number of bytes
292   // consumed from the data.
293   size_t ProcessCommonHeader(const char* data, size_t len);
294   void ProcessControlFrameHeader();
295   size_t ProcessControlFramePayload(const char* data, size_t len);
296   size_t ProcessDataFramePayload(const char* data, size_t len);
297 
298   // Get (and lazily initialize) the ZLib state.
299   z_stream* GetHeaderCompressor();
300   z_stream* GetHeaderDecompressor();
301   z_stream* GetStreamCompressor(SpdyStreamId id);
302   z_stream* GetStreamDecompressor(SpdyStreamId id);
303 
304   // Compression helpers
305   SpdyControlFrame* CompressControlFrame(const SpdyControlFrame& frame);
306   SpdyDataFrame* CompressDataFrame(const SpdyDataFrame& frame);
307   SpdyControlFrame* DecompressControlFrame(const SpdyControlFrame& frame);
308   SpdyDataFrame* DecompressDataFrame(const SpdyDataFrame& frame);
309   SpdyFrame* CompressFrameWithZStream(const SpdyFrame& frame,
310                                       z_stream* compressor);
311   SpdyFrame* DecompressFrameWithZStream(const SpdyFrame& frame,
312                                         z_stream* decompressor);
313   void CleanupCompressorForStream(SpdyStreamId id);
314   void CleanupDecompressorForStream(SpdyStreamId id);
315   void CleanupStreamCompressorsAndDecompressors();
316 
317   // Not used (yet)
318   size_t BytesSafeToRead() const;
319 
320   // Set the error code and moves the framer into the error state.
321   void set_error(SpdyError error);
322 
323   // Expands the control frame buffer to accomodate a particular payload size.
324   void ExpandControlFrameBuffer(size_t size);
325 
326   // Given a frame, breakdown the variable payload length, the static header
327   // header length, and variable payload pointer.
328   bool GetFrameBoundaries(const SpdyFrame& frame, int* payload_length,
329                           int* header_length, const char** payload) const;
330 
num_stream_compressors()331   int num_stream_compressors() const { return stream_compressors_.size(); }
num_stream_decompressors()332   int num_stream_decompressors() const { return stream_decompressors_.size(); }
333 
334   SpdyState state_;
335   SpdyError error_code_;
336   size_t remaining_payload_;
337   size_t remaining_control_payload_;
338 
339   char* current_frame_buffer_;
340   size_t current_frame_len_;  // Number of bytes read into the current_frame_.
341   size_t current_frame_capacity_;
342 
343   bool enable_compression_;  // Controls all compression
344   // SPDY header compressors.
345   scoped_ptr<z_stream> header_compressor_;
346   scoped_ptr<z_stream> header_decompressor_;
347 
348   // Per-stream data compressors.
349   CompressorMap stream_compressors_;
350   CompressorMap stream_decompressors_;
351 
352   SpdyFramerVisitorInterface* visitor_;
353 
354   static bool compression_default_;
355   static int spdy_version_;
356 };
357 
358 }  // namespace spdy
359 
360 #endif  // NET_SPDY_SPDY_FRAMER_H_
361