Home | History | Annotate | Download | only in flip
      1 // Copyright (c) 2009 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_FLIP_FLIP_FRAMER_H_
      6 #define NET_FLIP_FLIP_FRAMER_H_
      7 
      8 #ifdef _WIN32
      9 #include <winsock2.h>
     10 #else
     11 #include <arpa/inet.h>
     12 #endif
     13 #include <map>
     14 #include <string>
     15 
     16 #include "base/basictypes.h"
     17 #include "base/logging.h"
     18 #include "base/scoped_ptr.h"
     19 #include "testing/gtest/include/gtest/gtest_prod.h"
     20 #include "flip_protocol.h"    // cross-google3 directory naming.
     21 
     22 typedef struct z_stream_s z_stream;  // Forward declaration for zlib.
     23 
     24 namespace net {
     25 class FlipNetworkTransactionTest;
     26 class HttpNetworkLayer;
     27 }
     28 
     29 namespace flip {
     30 
     31 class FlipFramer;
     32 class FlipFramerTest;
     33 
     34 namespace test {
     35 class TestFlipVisitor;
     36 void FramerSetEnableCompressionHelper(FlipFramer* framer, bool compress);
     37 }  // namespace test
     38 
     39 // A datastructure for holding a set of headers from either a
     40 // SYN_STREAM or SYN_REPLY frame.
     41 typedef std::map<std::string, std::string> FlipHeaderBlock;
     42 
     43 // FlipFramerVisitorInterface is a set of callbacks for the FlipFramer.
     44 // Implement this interface to receive event callbacks as frames are
     45 // decoded from the framer.
     46 class FlipFramerVisitorInterface {
     47  public:
     48   virtual ~FlipFramerVisitorInterface() {}
     49 
     50   // Called if an error is detected in the FlipFrame protocol.
     51   virtual void OnError(FlipFramer* framer) = 0;
     52 
     53   // Called when a Control Frame is received.
     54   virtual void OnControl(const FlipControlFrame* frame) = 0;
     55 
     56   // Called when data is received.
     57   // |stream_id| The stream receiving data.
     58   // |data| A buffer containing the data received.
     59   // |len| The length of the data buffer.
     60   // When the other side has finished sending data on this stream,
     61   // this method will be called with a zero-length buffer.
     62   virtual void OnStreamFrameData(flip::FlipStreamId stream_id,
     63                                  const char* data,
     64                                  size_t len) = 0;
     65 };
     66 
     67 class FlipFramer {
     68  public:
     69   // Flip states.
     70   // TODO(mbelshe): Can we move these into the implementation
     71   //                and avoid exposing through the header.  (Needed for test)
     72   enum FlipState {
     73     FLIP_ERROR,
     74     FLIP_DONE,
     75     FLIP_RESET,
     76     FLIP_AUTO_RESET,
     77     FLIP_READING_COMMON_HEADER,
     78     FLIP_INTERPRET_CONTROL_FRAME_COMMON_HEADER,
     79     FLIP_CONTROL_FRAME_PAYLOAD,
     80     FLIP_IGNORE_REMAINING_PAYLOAD,
     81     FLIP_FORWARD_STREAM_FRAME
     82   };
     83 
     84   // Flip error codes.
     85   enum FlipError {
     86     FLIP_NO_ERROR,
     87     FLIP_UNKNOWN_CONTROL_TYPE,       // Control frame is an unknown type.
     88     FLIP_INVALID_CONTROL_FRAME,      // Control frame is mal-formatted.
     89     FLIP_CONTROL_PAYLOAD_TOO_LARGE,  // Control frame payload was too large.
     90     FLIP_ZLIB_INIT_FAILURE,          // The Zlib library could not initialize.
     91     FLIP_UNSUPPORTED_VERSION,        // Control frame has unsupported version.
     92     FLIP_DECOMPRESS_FAILURE,         // There was an error decompressing.
     93   };
     94 
     95   // Create a new Framer.
     96   FlipFramer();
     97   virtual ~FlipFramer();
     98 
     99   // Set callbacks to be called from the framer.  A visitor must be set, or
    100   // else the framer will likely crash.  It is acceptable for the visitor
    101   // to do nothing.  If this is called multiple times, only the last visitor
    102   // will be used.
    103   void set_visitor(FlipFramerVisitorInterface* visitor) {
    104     visitor_ = visitor;
    105   }
    106 
    107   // Pass data into the framer for parsing.
    108   // Returns the number of bytes consumed. It is safe to pass more bytes in
    109   // than may be consumed.
    110   size_t ProcessInput(const char* data, size_t len);
    111 
    112   // Resets the framer state after a frame has been successfully decoded.
    113   // TODO(mbelshe): can we make this private?
    114   void Reset();
    115 
    116   // Check the state of the framer.
    117   FlipError error_code() const { return error_code_; }
    118   FlipState state() const { return state_; }
    119 
    120   bool MessageFullyRead() {
    121     return state_ == FLIP_DONE || state_ == FLIP_AUTO_RESET;
    122   }
    123   bool HasError() { return state_ == FLIP_ERROR; }
    124 
    125   // Further parsing utilities.
    126   // Given a control frame, parse out a FlipHeaderBlock.  Only
    127   // valid for SYN_STREAM and SYN_REPLY frames.
    128   // Returns true if successfully parsed, false otherwise.
    129   bool ParseHeaderBlock(const FlipFrame* frame, FlipHeaderBlock* block);
    130 
    131   // Create a FlipSynStreamControlFrame.
    132   // |stream_id| is the stream for this frame.
    133   // |priority| is the priority (0-3) for this frame.
    134   // |flags| is the flags to use with the data.
    135   //    To mark this frame as the last frame, enable CONTROL_FLAG_FIN.
    136   // |compressed| specifies whether the frame should be compressed.
    137   // |headers| is the header block to include in the frame.
    138   FlipSynStreamControlFrame* CreateSynStream(FlipStreamId stream_id,
    139                                              int priority,
    140                                              FlipControlFlags flags,
    141                                              bool compressed,
    142                                              FlipHeaderBlock* headers);
    143 
    144   static FlipFinStreamControlFrame* CreateFinStream(FlipStreamId stream_id,
    145                                                     int status);
    146 
    147   // Create a FlipSynReplyControlFrame.
    148   // |stream_id| is the stream for this frame.
    149   // |flags| is the flags to use with the data.
    150   //    To mark this frame as the last frame, enable CONTROL_FLAG_FIN.
    151   // |compressed| specifies whether the frame should be compressed.
    152   // |headers| is the header block to include in the frame.
    153   FlipSynReplyControlFrame* CreateSynReply(FlipStreamId stream_id,
    154                                            FlipControlFlags flags,
    155                                            bool compressed,
    156                                            FlipHeaderBlock* headers);
    157 
    158   // Create a data frame.
    159   // |stream_id| is the stream  for this frame
    160   // |data| is the data to be included in the frame.
    161   // |len| is the length of the data
    162   // |flags| is the flags to use with the data.
    163   //    To create a compressed frame, enable DATA_FLAG_COMPRESSED.
    164   //    To mark this frame as the last data frame, enable DATA_FLAG_FIN.
    165   FlipDataFrame* CreateDataFrame(FlipStreamId stream_id, const char* data,
    166                                  uint32 len, FlipDataFlags flags);
    167 
    168   static FlipControlFrame* CreateNopFrame();
    169 
    170   // NOTES about frame compression.
    171   // We want flip to compress headers across the entire session.  As long as
    172   // the session is over TCP, frames are sent serially.  The client & server
    173   // can each compress frames in the same order and then compress them in that
    174   // order, and the remote can do the reverse.  However, we ultimately want
    175   // the creation of frames to be less sensitive to order so that they can be
    176   // placed over a UDP based protocol and yet still benefit from some
    177   // compression.  We don't know of any good compression protocol which does
    178   // not build its state in a serial (stream based) manner....  For now, we're
    179   // using zlib anyway.
    180 
    181   // Compresses a FlipFrame.
    182   // On success, returns a new FlipFrame with the payload compressed.
    183   // Compression state is maintained as part of the FlipFramer.
    184   // Returned frame must be freed with free().
    185   // On failure, returns NULL.
    186   FlipFrame* CompressFrame(const FlipFrame* frame);
    187 
    188   // Decompresses a FlipFrame.
    189   // On success, returns a new FlipFrame with the payload decompressed.
    190   // Compression state is maintained as part of the FlipFramer.
    191   // Returned frame must be freed with free().
    192   // On failure, returns NULL.
    193   FlipFrame* DecompressFrame(const FlipFrame* frame);
    194 
    195   // Create a copy of a frame.
    196   FlipFrame* DuplicateFrame(const FlipFrame* frame);
    197 
    198   // For debugging.
    199   static const char* StateToString(int state);
    200   static const char* ErrorCodeToString(int error_code);
    201 
    202  protected:
    203   FRIEND_TEST(FlipFramerTest, HeaderBlockBarfsOnOutOfOrderHeaders);
    204   friend class net::FlipNetworkTransactionTest;
    205   friend class net::HttpNetworkLayer;  // This is temporary for the server.
    206   friend class test::TestFlipVisitor;
    207   friend void test::FramerSetEnableCompressionHelper(FlipFramer* framer,
    208                                                      bool compress);
    209 
    210   // For ease of testing we can tweak compression on/off.
    211   void set_enable_compression(bool value);
    212   static void set_enable_compression_default(bool value);
    213 
    214  private:
    215   // Internal breakout from ProcessInput.  Returns the number of bytes
    216   // consumed from the data.
    217   size_t ProcessCommonHeader(const char* data, size_t len);
    218   void ProcessControlFrameHeader();
    219   size_t ProcessControlFramePayload(const char* data, size_t len);
    220   size_t ProcessDataFramePayload(const char* data, size_t len);
    221 
    222   // Initialize the ZLib state.
    223   bool InitializeCompressor();
    224   bool InitializeDecompressor();
    225 
    226   // Not used (yet)
    227   size_t BytesSafeToRead() const;
    228 
    229   // Set the error code.
    230   void set_error(FlipError error);
    231 
    232   // Expands the control frame buffer to accomodate a particular payload size.
    233   void ExpandControlFrameBuffer(size_t size);
    234 
    235   // Given a frame, breakdown the variable payload length, the static header
    236   // header length, and variable payload pointer.
    237   bool GetFrameBoundaries(const FlipFrame* frame, int* payload_length,
    238                           int* header_length, const char** payload) const;
    239 
    240   FlipState state_;
    241   FlipError error_code_;
    242   size_t remaining_payload_;
    243   size_t remaining_control_payload_;
    244 
    245   char* current_frame_buffer_;
    246   size_t current_frame_len_;  // Number of bytes read into the current_frame_.
    247   size_t current_frame_capacity_;
    248 
    249   bool enable_compression_;
    250   scoped_ptr<z_stream> compressor_;
    251   scoped_ptr<z_stream> decompressor_;
    252   FlipFramerVisitorInterface* visitor_;
    253 
    254   static bool compression_default_;
    255 };
    256 
    257 }  // namespace flip
    258 
    259 #endif  // NET_FLIP_FLIP_FRAMER_H_
    260 
    261