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 <string>
9#include <vector>
10
11#include "base/basictypes.h"
12#include "base/callback.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/memory/scoped_vector.h"
15#include "net/base/net_export.h"
16#include "net/websockets/websocket_frame.h"
17#include "net/websockets/websocket_stream.h"
18#include "url/gurl.h"
19
20namespace net {
21
22class URLRequestContext;
23class WebSocketEventInterface;
24
25// Transport-independent implementation of WebSockets. Implements protocol
26// semantics that do not depend on the underlying transport. Provides the
27// interface to the content layer. Some WebSocket concepts are used here without
28// definition; please see the RFC at http://tools.ietf.org/html/rfc6455 for
29// clarification.
30class NET_EXPORT WebSocketChannel {
31 public:
32  // The type of a WebSocketStream factory callback. Must match the signature of
33  // WebSocketStream::CreateAndConnectStream().
34  typedef base::Callback<scoped_ptr<WebSocketStreamRequest>(
35      const GURL&,
36      const std::vector<std::string>&,
37      const GURL&,
38      URLRequestContext*,
39      const BoundNetLog&,
40      scoped_ptr<WebSocketStream::ConnectDelegate>)> WebSocketStreamFactory;
41
42  // Creates a new WebSocketChannel with the specified parameters.
43  // SendAddChannelRequest() must be called immediately afterwards to start the
44  // connection process.
45  WebSocketChannel(const GURL& socket_url,
46                   scoped_ptr<WebSocketEventInterface> event_interface);
47  virtual ~WebSocketChannel();
48
49  // Starts the connection process.
50  void SendAddChannelRequest(
51      const std::vector<std::string>& requested_protocols,
52      const GURL& origin,
53      URLRequestContext* url_request_context);
54
55  // Sends a data frame to the remote side. The frame should usually be no
56  // larger than 32KB to prevent the time required to copy the buffers from from
57  // unduly delaying other tasks that need to run on the IO thread. This method
58  // has a hard limit of 2GB. It is the responsibility of the caller to ensure
59  // that they have sufficient send quota to send this data, otherwise the
60  // connection will be closed without sending. |fin| indicates the last frame
61  // in a message, equivalent to "FIN" as specified in section 5.2 of
62  // RFC6455. |data| is the "Payload Data". If |op_code| is kOpCodeText, or it
63  // is kOpCodeContinuation and the type the message is Text, then |data| must
64  // be a chunk of a valid UTF-8 message, however there is no requirement for
65  // |data| to be split on character boundaries.
66  void SendFrame(bool fin,
67                 WebSocketFrameHeader::OpCode op_code,
68                 const std::vector<char>& data);
69
70  // Sends |quota| units of flow control to the remote side. If the underlying
71  // transport has a concept of |quota|, then it permits the remote server to
72  // send up to |quota| units of data.
73  void SendFlowControl(int64 quota);
74
75  // Start the closing handshake for a client-initiated shutdown of the
76  // connection. There is no API to close the connection without a closing
77  // handshake, but destroying the WebSocketChannel object while connected will
78  // effectively do that. |code| must be in the range 1000-4999. |reason| should
79  // be a valid UTF-8 string or empty.
80  //
81  // This does *not* trigger the event OnClosingHandshake(). The caller should
82  // assume that the closing handshake has started and perform the equivalent
83  // processing to OnClosingHandshake() if necessary.
84  void StartClosingHandshake(uint16 code, const std::string& reason);
85
86  // Starts the connection process, using a specified factory function rather
87  // than the default. This is exposed for testing.
88  void SendAddChannelRequestForTesting(
89      const std::vector<std::string>& requested_protocols,
90      const GURL& origin,
91      URLRequestContext* url_request_context,
92      const WebSocketStreamFactory& factory);
93
94 private:
95  // We have a simple linear progression of states from FRESHLY_CONSTRUCTED to
96  // CLOSED, except that the SEND_CLOSED and RECV_CLOSED states may be skipped
97  // in case of error.
98  enum State {
99    FRESHLY_CONSTRUCTED,
100    CONNECTING,
101    CONNECTED,
102    SEND_CLOSED,  // We have sent a Close frame but not received a Close frame.
103    RECV_CLOSED,  // Used briefly between receiving a Close frame and sending
104                  // the response. Once we have responded, the state changes
105                  // to CLOSED.
106    CLOSE_WAIT,   // The Closing Handshake has completed, but the remote server
107                  // has not yet closed the connection.
108    CLOSED,       // The Closing Handshake has completed and the connection
109                  // has been closed; or the connection is failed.
110  };
111
112  // When failing a channel, we may or may not want to send the real reason for
113  // failing to the remote server. This enum is used by FailChannel() to
114  // choose.
115  enum ExposeError {
116    SEND_REAL_ERROR,
117    SEND_GOING_AWAY,
118  };
119
120  // Our implementation of WebSocketStream::ConnectDelegate. We do not inherit
121  // from WebSocketStream::ConnectDelegate directly to avoid cluttering our
122  // public interface with the implementation of those methods, and because the
123  // lifetime of a WebSocketChannel is longer than the lifetime of the
124  // connection process.
125  class ConnectDelegate;
126
127  // Starts the connection progress, using a specified factory function.
128  void SendAddChannelRequestWithFactory(
129      const std::vector<std::string>& requested_protocols,
130      const GURL& origin,
131      URLRequestContext* url_request_context,
132      const WebSocketStreamFactory& factory);
133
134  // Success callback from WebSocketStream::CreateAndConnectStream(). Reports
135  // success to the event interface.
136  void OnConnectSuccess(scoped_ptr<WebSocketStream> stream);
137
138  // Failure callback from WebSocketStream::CreateAndConnectStream(). Reports
139  // failure to the event interface.
140  void OnConnectFailure(uint16 websocket_error);
141
142  // Returns true if state_ is SEND_CLOSED, CLOSE_WAIT or CLOSED.
143  bool InClosingState() const;
144
145  // Calls WebSocketStream::WriteFrames() with the appropriate arguments
146  void WriteFrames();
147
148  // Callback from WebSocketStream::WriteFrames. Sends pending data or adjusts
149  // the send quota of the renderer channel as appropriate. |result| is a net
150  // error code, usually OK. If |synchronous| is true, then OnWriteDone() is
151  // being called from within the WriteFrames() loop and does not need to call
152  // WriteFrames() itself.
153  void OnWriteDone(bool synchronous, int result);
154
155  // Calls WebSocketStream::ReadFrames() with the appropriate arguments.
156  void ReadFrames();
157
158  // Callback from WebSocketStream::ReadFrames. Handles any errors and processes
159  // the returned chunks appropriately to their type. |result| is a net error
160  // code. If |synchronous| is true, then OnReadDone() is being called from
161  // within the ReadFrames() loop and does not need to call ReadFrames() itself.
162  void OnReadDone(bool synchronous, int result);
163
164  // Processes a single chunk that has been read from the stream.
165  void ProcessFrameChunk(scoped_ptr<WebSocketFrameChunk> chunk);
166
167  // Handle a frame that we have received enough of to process. May call
168  // event_interface_ methods, send responses to the server, and change the
169  // value of state_.
170  void HandleFrame(const WebSocketFrameHeader::OpCode opcode,
171                   bool is_first_chunk,
172                   bool is_final_chunk,
173                   const scoped_refptr<IOBufferWithSize>& data_buffer);
174
175  // Low-level method to send a single frame. Used for both data and control
176  // frames. Either sends the frame immediately or buffers it to be scheduled
177  // when the current write finishes. |fin| and |op_code| are defined as for
178  // SendFrame() above, except that |op_code| may also be a control frame
179  // opcode.
180  void SendIOBufferWithSize(bool fin,
181                            WebSocketFrameHeader::OpCode op_code,
182                            const scoped_refptr<IOBufferWithSize>& buffer);
183
184  // Perform the "Fail the WebSocket Connection" operation as defined in
185  // RFC6455. The supplied code and reason are sent back to the renderer in an
186  // OnDropChannel message. If state_ is CONNECTED then a Close message is sent
187  // to the remote host. If |expose| is SEND_REAL_ERROR then the remote host is
188  // given the same status code we gave the renderer; otherwise it is sent a
189  // fixed "Going Away" code.  Resets current_frame_header_, closes the
190  // stream_, and sets state_ to CLOSED.
191  void FailChannel(ExposeError expose, uint16 code, const std::string& reason);
192
193  // Sends a Close frame to Start the WebSocket Closing Handshake, or to respond
194  // to a Close frame from the server. As a special case, setting |code| to
195  // kWebSocketErrorNoStatusReceived will create a Close frame with no payload;
196  // this is symmetric with the behaviour of ParseClose.
197  void SendClose(uint16 code, const std::string& reason);
198
199  // Parses a Close frame. If no status code is supplied, then |code| is set to
200  // 1005 (No status code) with empty |reason|. If the supplied code is
201  // outside the valid range, then 1002 (Protocol error) is set instead. If the
202  // reason text is not valid UTF-8, then |reason| is set to an empty string
203  // instead.
204  void ParseClose(const scoped_refptr<IOBufferWithSize>& buffer,
205                  uint16* code,
206                  std::string* reason);
207
208  // The URL to which we connect.
209  const GURL socket_url_;
210
211  // The object receiving events.
212  const scoped_ptr<WebSocketEventInterface> event_interface_;
213
214  // The WebSocketStream to which we are sending/receiving data.
215  scoped_ptr<WebSocketStream> stream_;
216
217  // A data structure containing a vector of frames to be sent and the total
218  // number of bytes contained in the vector.
219  class SendBuffer;
220  // Data that is currently pending write, or NULL if no write is pending.
221  scoped_ptr<SendBuffer> data_being_sent_;
222  // Data that is queued up to write after the current write completes.
223  // Only non-NULL when such data actually exists.
224  scoped_ptr<SendBuffer> data_to_send_next_;
225
226  // Destination for the current call to WebSocketStream::ReadFrames
227  ScopedVector<WebSocketFrameChunk> read_frame_chunks_;
228  // Frame header for the frame currently being received. Only non-NULL while we
229  // are processing the frame. If the frame arrives in multiple chunks, can
230  // remain non-NULL while we wait for additional chunks to arrive. If the
231  // header of the frame was invalid, this is set to NULL, the channel is
232  // failed, and subsequent chunks of the same frame will be ignored.
233  scoped_ptr<WebSocketFrameHeader> current_frame_header_;
234  // Handle to an in-progress WebSocketStream creation request. Only non-NULL
235  // during the connection process.
236  scoped_ptr<WebSocketStreamRequest> stream_request_;
237  // Although it will almost never happen in practice, we can be passed an
238  // incomplete control frame, in which case we need to keep the data around
239  // long enough to reassemble it. This variable will be NULL the rest of the
240  // time.
241  scoped_refptr<IOBufferWithSize> incomplete_control_frame_body_;
242  // The point at which we give the renderer a quota refresh (quota units).
243  // "quota units" are currently bytes. TODO(ricea): Update the definition of
244  // quota units when necessary.
245  int send_quota_low_water_mark_;
246  // The amount which we refresh the quota to when it reaches the
247  // low_water_mark (quota units).
248  int send_quota_high_water_mark_;
249  // The current amount of quota that the renderer has available for sending
250  // on this logical channel (quota units).
251  int current_send_quota_;
252
253  // Storage for the status code and reason from the time we receive the Close
254  // frame until the connection is closed and we can call OnDropChannel().
255  uint16 closing_code_;
256  std::string closing_reason_;
257
258  // The current state of the channel. Mainly used for sanity checking, but also
259  // used to track the close state.
260  State state_;
261
262  DISALLOW_COPY_AND_ASSIGN(WebSocketChannel);
263};
264
265}  // namespace net
266
267#endif  // NET_WEBSOCKETS_WEBSOCKET_CHANNEL_H_
268