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