Home | History | Annotate | Download | only in websockets
      1 // Copyright 2013 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_WEBSOCKETS_WEBSOCKET_CHANNEL_H_
      6 #define NET_WEBSOCKETS_WEBSOCKET_CHANNEL_H_
      7 
      8 #include <queue>
      9 #include <string>
     10 #include <vector>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/callback.h"
     14 #include "base/compiler_specific.h"  // for WARN_UNUSED_RESULT
     15 #include "base/i18n/streaming_utf8_validator.h"
     16 #include "base/memory/ref_counted.h"
     17 #include "base/memory/scoped_ptr.h"
     18 #include "base/memory/scoped_vector.h"
     19 #include "base/time/time.h"
     20 #include "base/timer/timer.h"
     21 #include "net/base/net_export.h"
     22 #include "net/websockets/websocket_event_interface.h"
     23 #include "net/websockets/websocket_frame.h"
     24 #include "net/websockets/websocket_stream.h"
     25 #include "url/gurl.h"
     26 
     27 namespace url {
     28 class Origin;
     29 }  // namespace url
     30 
     31 namespace net {
     32 
     33 class BoundNetLog;
     34 class IOBuffer;
     35 class URLRequestContext;
     36 struct WebSocketHandshakeRequestInfo;
     37 struct WebSocketHandshakeResponseInfo;
     38 
     39 // Transport-independent implementation of WebSockets. Implements protocol
     40 // semantics that do not depend on the underlying transport. Provides the
     41 // interface to the content layer. Some WebSocket concepts are used here without
     42 // definition; please see the RFC at http://tools.ietf.org/html/rfc6455 for
     43 // clarification.
     44 class NET_EXPORT WebSocketChannel {
     45  public:
     46   // The type of a WebSocketStream creator callback. Must match the signature of
     47   // WebSocketStream::CreateAndConnectStream().
     48   typedef base::Callback<scoped_ptr<WebSocketStreamRequest>(
     49       const GURL&,
     50       const std::vector<std::string>&,
     51       const url::Origin&,
     52       URLRequestContext*,
     53       const BoundNetLog&,
     54       scoped_ptr<WebSocketStream::ConnectDelegate>)> WebSocketStreamCreator;
     55 
     56   // Creates a new WebSocketChannel in an idle state.
     57   // SendAddChannelRequest() must be called immediately afterwards to start the
     58   // connection process.
     59   WebSocketChannel(scoped_ptr<WebSocketEventInterface> event_interface,
     60                    URLRequestContext* url_request_context);
     61   virtual ~WebSocketChannel();
     62 
     63   // Starts the connection process.
     64   void SendAddChannelRequest(
     65       const GURL& socket_url,
     66       const std::vector<std::string>& requested_protocols,
     67       const url::Origin& origin);
     68 
     69   // Sends a data frame to the remote side. The frame should usually be no
     70   // larger than 32KB to prevent the time required to copy the buffers from from
     71   // unduly delaying other tasks that need to run on the IO thread. This method
     72   // has a hard limit of 2GB. It is the responsibility of the caller to ensure
     73   // that they have sufficient send quota to send this data, otherwise the
     74   // connection will be closed without sending. |fin| indicates the last frame
     75   // in a message, equivalent to "FIN" as specified in section 5.2 of
     76   // RFC6455. |data| is the "Payload Data". If |op_code| is kOpCodeText, or it
     77   // is kOpCodeContinuation and the type the message is Text, then |data| must
     78   // be a chunk of a valid UTF-8 message, however there is no requirement for
     79   // |data| to be split on character boundaries.
     80   void SendFrame(bool fin,
     81                  WebSocketFrameHeader::OpCode op_code,
     82                  const std::vector<char>& data);
     83 
     84   // Sends |quota| units of flow control to the remote side. If the underlying
     85   // transport has a concept of |quota|, then it permits the remote server to
     86   // send up to |quota| units of data.
     87   void SendFlowControl(int64 quota);
     88 
     89   // Starts the closing handshake for a client-initiated shutdown of the
     90   // connection. There is no API to close the connection without a closing
     91   // handshake, but destroying the WebSocketChannel object while connected will
     92   // effectively do that. |code| must be in the range 1000-4999. |reason| should
     93   // be a valid UTF-8 string or empty.
     94   //
     95   // This does *not* trigger the event OnClosingHandshake(). The caller should
     96   // assume that the closing handshake has started and perform the equivalent
     97   // processing to OnClosingHandshake() if necessary.
     98   void StartClosingHandshake(uint16 code, const std::string& reason);
     99 
    100   // Starts the connection process, using a specified creator callback rather
    101   // than the default. This is exposed for testing.
    102   void SendAddChannelRequestForTesting(
    103       const GURL& socket_url,
    104       const std::vector<std::string>& requested_protocols,
    105       const url::Origin& origin,
    106       const WebSocketStreamCreator& creator);
    107 
    108   // The default timout for the closing handshake is a sensible value (see
    109   // kClosingHandshakeTimeoutSeconds in websocket_channel.cc). However, we can
    110   // set it to a very small value for testing purposes.
    111   void SetClosingHandshakeTimeoutForTesting(base::TimeDelta delay);
    112 
    113   // Called when the stream starts the WebSocket Opening Handshake.
    114   // This method is public for testing.
    115   void OnStartOpeningHandshake(
    116       scoped_ptr<WebSocketHandshakeRequestInfo> request);
    117 
    118   // Called when the stream ends the WebSocket Opening Handshake.
    119   // This method is public for testing.
    120   void OnFinishOpeningHandshake(
    121       scoped_ptr<WebSocketHandshakeResponseInfo> response);
    122 
    123  private:
    124   class HandshakeNotificationSender;
    125 
    126   // The Windows implementation of std::queue requires that this declaration be
    127   // visible in the header.
    128   class PendingReceivedFrame {
    129    public:
    130     PendingReceivedFrame(bool final,
    131                          WebSocketFrameHeader::OpCode opcode,
    132                          const scoped_refptr<IOBuffer>& data,
    133                          size_t offset,
    134                          size_t size);
    135     ~PendingReceivedFrame();
    136 
    137     bool final() const { return final_; }
    138     WebSocketFrameHeader::OpCode opcode() const { return opcode_; }
    139     // ResetOpcode() to Continuation.
    140     void ResetOpcode();
    141     const scoped_refptr<IOBuffer>& data() const { return data_; }
    142     size_t offset() const { return offset_; }
    143     size_t size() const { return size_; }
    144     // Increase |offset_| by |bytes|.
    145     void DidConsume(size_t bytes);
    146 
    147     // This object needs to be copyable and assignable, since it will be placed
    148     // in a std::queue. The compiler-generated copy constructor and assignment
    149     // operator will do the right thing.
    150 
    151    private:
    152     bool final_;
    153     WebSocketFrameHeader::OpCode opcode_;
    154     scoped_refptr<IOBuffer> data_;
    155     // Where to start reading from data_. Everything prior to offset_ has
    156     // already been sent to the browser.
    157     size_t offset_;
    158     // The size of data_.
    159     size_t size_;
    160   };
    161 
    162   // Methods which return a value of type ChannelState may delete |this|. If the
    163   // return value is CHANNEL_DELETED, then the caller must return without making
    164   // any further access to member variables or methods.
    165   typedef WebSocketEventInterface::ChannelState ChannelState;
    166 
    167   // The object passes through a linear progression of states from
    168   // FRESHLY_CONSTRUCTED to CLOSED, except that the SEND_CLOSED and RECV_CLOSED
    169   // states may be skipped in case of error.
    170   enum State {
    171     FRESHLY_CONSTRUCTED,
    172     CONNECTING,
    173     CONNECTED,
    174     SEND_CLOSED,  // A Close frame has been sent but not received.
    175     RECV_CLOSED,  // Used briefly between receiving a Close frame and sending
    176                   // the response. Once the response is sent, the state changes
    177                   // to CLOSED.
    178     CLOSE_WAIT,   // The Closing Handshake has completed, but the remote server
    179                   // has not yet closed the connection.
    180     CLOSED,       // The Closing Handshake has completed and the connection
    181                   // has been closed; or the connection is failed.
    182   };
    183 
    184   // Implementation of WebSocketStream::ConnectDelegate for
    185   // WebSocketChannel. WebSocketChannel does not inherit from
    186   // WebSocketStream::ConnectDelegate directly to avoid cluttering the public
    187   // interface with the implementation of those methods, and because the
    188   // lifetime of a WebSocketChannel is longer than the lifetime of the
    189   // connection process.
    190   class ConnectDelegate;
    191 
    192   // Starts the connection process, using the supplied creator callback.
    193   void SendAddChannelRequestWithSuppliedCreator(
    194       const GURL& socket_url,
    195       const std::vector<std::string>& requested_protocols,
    196       const url::Origin& origin,
    197       const WebSocketStreamCreator& creator);
    198 
    199   // Success callback from WebSocketStream::CreateAndConnectStream(). Reports
    200   // success to the event interface. May delete |this|.
    201   void OnConnectSuccess(scoped_ptr<WebSocketStream> stream);
    202 
    203   // Failure callback from WebSocketStream::CreateAndConnectStream(). Reports
    204   // failure to the event interface. May delete |this|.
    205   void OnConnectFailure(const std::string& message);
    206 
    207   // SSL certificate error callback from
    208   // WebSocketStream::CreateAndConnectStream(). Forwards the request to the
    209   // event interface.
    210   void OnSSLCertificateError(
    211       scoped_ptr<WebSocketEventInterface::SSLErrorCallbacks>
    212           ssl_error_callbacks,
    213       const SSLInfo& ssl_info,
    214       bool fatal);
    215 
    216   // Posts a task that sends pending notifications relating WebSocket Opening
    217   // Handshake to the renderer.
    218   void ScheduleOpeningHandshakeNotification();
    219 
    220   // Sets |state_| to |new_state| and updates UMA if necessary.
    221   void SetState(State new_state);
    222 
    223   // Returns true if state_ is SEND_CLOSED, CLOSE_WAIT or CLOSED.
    224   bool InClosingState() const;
    225 
    226   // Calls WebSocketStream::WriteFrames() with the appropriate arguments
    227   ChannelState WriteFrames() WARN_UNUSED_RESULT;
    228 
    229   // Callback from WebSocketStream::WriteFrames. Sends pending data or adjusts
    230   // the send quota of the renderer channel as appropriate. |result| is a net
    231   // error code, usually OK. If |synchronous| is true, then OnWriteDone() is
    232   // being called from within the WriteFrames() loop and does not need to call
    233   // WriteFrames() itself.
    234   ChannelState OnWriteDone(bool synchronous, int result) WARN_UNUSED_RESULT;
    235 
    236   // Calls WebSocketStream::ReadFrames() with the appropriate arguments. Stops
    237   // calling ReadFrames if current_receive_quota_ is 0.
    238   ChannelState ReadFrames() WARN_UNUSED_RESULT;
    239 
    240   // Callback from WebSocketStream::ReadFrames. Handles any errors and processes
    241   // the returned chunks appropriately to their type. |result| is a net error
    242   // code. If |synchronous| is true, then OnReadDone() is being called from
    243   // within the ReadFrames() loop and does not need to call ReadFrames() itself.
    244   ChannelState OnReadDone(bool synchronous, int result) WARN_UNUSED_RESULT;
    245 
    246   // Handles a single frame that the object has received enough of to process.
    247   // May call |event_interface_| methods, send responses to the server, and
    248   // change the value of |state_|.
    249   //
    250   // This method performs sanity checks on the frame that are needed regardless
    251   // of the current state. Then, calls the HandleFrameByState() method below
    252   // which performs the appropriate action(s) depending on the current state.
    253   ChannelState HandleFrame(
    254       scoped_ptr<WebSocketFrame> frame) WARN_UNUSED_RESULT;
    255 
    256   // Handles a single frame depending on the current state. It's used by the
    257   // HandleFrame() method.
    258   ChannelState HandleFrameByState(
    259       const WebSocketFrameHeader::OpCode opcode,
    260       bool final,
    261       const scoped_refptr<IOBuffer>& data_buffer,
    262       size_t size) WARN_UNUSED_RESULT;
    263 
    264   // Forward a received data frame to the renderer, if connected. If
    265   // |expecting_continuation| is not equal to |expecting_to_read_continuation_|,
    266   // will fail the channel. Also checks the UTF-8 validity of text frames.
    267   ChannelState HandleDataFrame(WebSocketFrameHeader::OpCode opcode,
    268                                bool final,
    269                                const scoped_refptr<IOBuffer>& data_buffer,
    270                                size_t size) WARN_UNUSED_RESULT;
    271 
    272   // Low-level method to send a single frame. Used for both data and control
    273   // frames. Either sends the frame immediately or buffers it to be scheduled
    274   // when the current write finishes. |fin| and |op_code| are defined as for
    275   // SendFrame() above, except that |op_code| may also be a control frame
    276   // opcode.
    277   ChannelState SendFrameFromIOBuffer(bool fin,
    278                                      WebSocketFrameHeader::OpCode op_code,
    279                                      const scoped_refptr<IOBuffer>& buffer,
    280                                      size_t size) WARN_UNUSED_RESULT;
    281 
    282   // Performs the "Fail the WebSocket Connection" operation as defined in
    283   // RFC6455. A NotifyFailure message is sent to the renderer with |message|.
    284   // The renderer will log the message to the console but not expose it to
    285   // Javascript. Javascript will see a Close code of AbnormalClosure (1006) with
    286   // an empty reason string. If state_ is CONNECTED then a Close message is sent
    287   // to the remote host containing the supplied |code| and |reason|. If the
    288   // stream is open, closes it and sets state_ to CLOSED.  FailChannel() always
    289   // returns CHANNEL_DELETED. It is not valid to access any member variables or
    290   // methods after calling FailChannel().
    291   ChannelState FailChannel(const std::string& message,
    292                            uint16 code,
    293                            const std::string& reason) WARN_UNUSED_RESULT;
    294 
    295   // Sends a Close frame to Start the WebSocket Closing Handshake, or to respond
    296   // to a Close frame from the server. As a special case, setting |code| to
    297   // kWebSocketErrorNoStatusReceived will create a Close frame with no payload;
    298   // this is symmetric with the behaviour of ParseClose.
    299   ChannelState SendClose(uint16 code,
    300                          const std::string& reason) WARN_UNUSED_RESULT;
    301 
    302   // Parses a Close frame payload. If no status code is supplied, then |code| is
    303   // set to 1005 (No status code) with empty |reason|. If the reason text is not
    304   // valid UTF-8, then |reason| is set to an empty string. If the payload size
    305   // is 1, or the supplied code is not permitted to be sent over the network,
    306   // then false is returned and |message| is set to an appropriate console
    307   // message.
    308   bool ParseClose(const scoped_refptr<IOBuffer>& buffer,
    309                   size_t size,
    310                   uint16* code,
    311                   std::string* reason,
    312                   std::string* message);
    313 
    314   // Drop this channel.
    315   // If there are pending opening handshake notifications, notify them
    316   // before dropping.
    317   //
    318   // Always returns CHANNEL_DELETED.
    319   ChannelState DoDropChannel(bool was_clean,
    320                              uint16 code,
    321                              const std::string& reason);
    322 
    323   // Called if the closing handshake times out. Closes the connection and
    324   // informs the |event_interface_| if appropriate.
    325   void CloseTimeout();
    326 
    327   // The URL of the remote server.
    328   GURL socket_url_;
    329 
    330   // The object receiving events.
    331   const scoped_ptr<WebSocketEventInterface> event_interface_;
    332 
    333   // The URLRequestContext to pass to the WebSocketStream creator.
    334   URLRequestContext* const url_request_context_;
    335 
    336   // The WebSocketStream on which to send and receive data.
    337   scoped_ptr<WebSocketStream> stream_;
    338 
    339   // A data structure containing a vector of frames to be sent and the total
    340   // number of bytes contained in the vector.
    341   class SendBuffer;
    342   // Data that is currently pending write, or NULL if no write is pending.
    343   scoped_ptr<SendBuffer> data_being_sent_;
    344   // Data that is queued up to write after the current write completes.
    345   // Only non-NULL when such data actually exists.
    346   scoped_ptr<SendBuffer> data_to_send_next_;
    347 
    348   // Destination for the current call to WebSocketStream::ReadFrames
    349   ScopedVector<WebSocketFrame> read_frames_;
    350 
    351   // Frames that have been read but not yet forwarded to the renderer due to
    352   // lack of quota.
    353   std::queue<PendingReceivedFrame> pending_received_frames_;
    354 
    355   // Handle to an in-progress WebSocketStream creation request. Only non-NULL
    356   // during the connection process.
    357   scoped_ptr<WebSocketStreamRequest> stream_request_;
    358 
    359   // If the renderer's send quota reaches this level, it is sent a quota
    360   // refresh. "quota units" are currently bytes. TODO(ricea): Update the
    361   // definition of quota units when necessary.
    362   int send_quota_low_water_mark_;
    363   // The level the quota is refreshed to when it reaches the low_water_mark
    364   // (quota units).
    365   int send_quota_high_water_mark_;
    366   // The current amount of quota that the renderer has available for sending
    367   // on this logical channel (quota units).
    368   int current_send_quota_;
    369   // The remaining amount of quota that the renderer will allow us to send on
    370   // this logical channel (quota units).
    371   int current_receive_quota_;
    372 
    373   // Timer for the closing handshake.
    374   base::OneShotTimer<WebSocketChannel> timer_;
    375 
    376   // Timeout for the closing handshake.
    377   base::TimeDelta timeout_;
    378 
    379   // Storage for the status code and reason from the time the Close frame
    380   // arrives until the connection is closed and they are passed to
    381   // OnDropChannel().
    382   uint16 received_close_code_;
    383   std::string received_close_reason_;
    384 
    385   // The current state of the channel. Mainly used for sanity checking, but also
    386   // used to track the close state.
    387   State state_;
    388 
    389   // |notification_sender_| is owned by this object.
    390   scoped_ptr<HandshakeNotificationSender> notification_sender_;
    391 
    392   // UTF-8 validator for outgoing Text messages.
    393   base::StreamingUtf8Validator outgoing_utf8_validator_;
    394   bool sending_text_message_;
    395 
    396   // UTF-8 validator for incoming Text messages.
    397   base::StreamingUtf8Validator incoming_utf8_validator_;
    398   bool receiving_text_message_;
    399 
    400   // True if we are in the middle of receiving a message.
    401   bool expecting_to_handle_continuation_;
    402 
    403   // True if we have already sent the type (Text or Binary) of the current
    404   // message to the renderer. This can be false if the message is empty so far.
    405   bool initial_frame_forwarded_;
    406 
    407   // For UMA. The time when OnConnectSuccess() method was called and |stream_|
    408   // was set.
    409   base::TimeTicks established_on_;
    410 
    411   DISALLOW_COPY_AND_ASSIGN(WebSocketChannel);
    412 };
    413 
    414 }  // namespace net
    415 
    416 #endif  // NET_WEBSOCKETS_WEBSOCKET_CHANNEL_H_
    417