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
27namespace url {
28class Origin;
29}  // namespace url
30
31namespace net {
32
33class BoundNetLog;
34class IOBuffer;
35class URLRequestContext;
36struct WebSocketHandshakeRequestInfo;
37struct 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.
44class 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