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