OLD | NEW |
| (Empty) |
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 // The default timout for the underlying connection close is a sensible value | |
114 // (see kUnderlyingConnectionCloseTimeoutSeconds in websocket_channel.cc). | |
115 // However, we can set it to a very small value for testing purposes. | |
116 void SetUnderlyingConnectionCloseTimeoutForTesting(base::TimeDelta delay); | |
117 | |
118 // Called when the stream starts the WebSocket Opening Handshake. | |
119 // This method is public for testing. | |
120 void OnStartOpeningHandshake( | |
121 scoped_ptr<WebSocketHandshakeRequestInfo> request); | |
122 | |
123 // Called when the stream ends the WebSocket Opening Handshake. | |
124 // This method is public for testing. | |
125 void OnFinishOpeningHandshake( | |
126 scoped_ptr<WebSocketHandshakeResponseInfo> response); | |
127 | |
128 private: | |
129 class HandshakeNotificationSender; | |
130 | |
131 // The Windows implementation of std::queue requires that this declaration be | |
132 // visible in the header. | |
133 class PendingReceivedFrame { | |
134 public: | |
135 PendingReceivedFrame(bool final, | |
136 WebSocketFrameHeader::OpCode opcode, | |
137 const scoped_refptr<IOBuffer>& data, | |
138 uint64 offset, | |
139 uint64 size); | |
140 ~PendingReceivedFrame(); | |
141 | |
142 bool final() const { return final_; } | |
143 WebSocketFrameHeader::OpCode opcode() const { return opcode_; } | |
144 // ResetOpcode() to Continuation. | |
145 void ResetOpcode(); | |
146 const scoped_refptr<IOBuffer>& data() const { return data_; } | |
147 uint64 offset() const { return offset_; } | |
148 uint64 size() const { return size_; } | |
149 // Increase |offset_| by |bytes|. | |
150 void DidConsume(uint64 bytes); | |
151 | |
152 // This object needs to be copyable and assignable, since it will be placed | |
153 // in a std::queue. The compiler-generated copy constructor and assignment | |
154 // operator will do the right thing. | |
155 | |
156 private: | |
157 bool final_; | |
158 WebSocketFrameHeader::OpCode opcode_; | |
159 scoped_refptr<IOBuffer> data_; | |
160 // Where to start reading from data_. Everything prior to offset_ has | |
161 // already been sent to the browser. | |
162 uint64 offset_; | |
163 // The size of data_. | |
164 uint64 size_; | |
165 }; | |
166 | |
167 // Methods which return a value of type ChannelState may delete |this|. If the | |
168 // return value is CHANNEL_DELETED, then the caller must return without making | |
169 // any further access to member variables or methods. | |
170 typedef WebSocketEventInterface::ChannelState ChannelState; | |
171 | |
172 // The object passes through a linear progression of states from | |
173 // FRESHLY_CONSTRUCTED to CLOSED, except that the SEND_CLOSED and RECV_CLOSED | |
174 // states may be skipped in case of error. | |
175 enum State { | |
176 FRESHLY_CONSTRUCTED, | |
177 CONNECTING, | |
178 CONNECTED, | |
179 SEND_CLOSED, // A Close frame has been sent but not received. | |
180 RECV_CLOSED, // Used briefly between receiving a Close frame and sending | |
181 // the response. Once the response is sent, the state changes | |
182 // to CLOSED. | |
183 CLOSE_WAIT, // The Closing Handshake has completed, but the remote server | |
184 // has not yet closed the connection. | |
185 CLOSED, // The Closing Handshake has completed and the connection | |
186 // has been closed; or the connection is failed. | |
187 }; | |
188 | |
189 // Implementation of WebSocketStream::ConnectDelegate for | |
190 // WebSocketChannel. WebSocketChannel does not inherit from | |
191 // WebSocketStream::ConnectDelegate directly to avoid cluttering the public | |
192 // interface with the implementation of those methods, and because the | |
193 // lifetime of a WebSocketChannel is longer than the lifetime of the | |
194 // connection process. | |
195 class ConnectDelegate; | |
196 | |
197 // Starts the connection process, using the supplied creator callback. | |
198 void SendAddChannelRequestWithSuppliedCreator( | |
199 const GURL& socket_url, | |
200 const std::vector<std::string>& requested_protocols, | |
201 const url::Origin& origin, | |
202 const WebSocketStreamCreator& creator); | |
203 | |
204 // Success callback from WebSocketStream::CreateAndConnectStream(). Reports | |
205 // success to the event interface. May delete |this|. | |
206 void OnConnectSuccess(scoped_ptr<WebSocketStream> stream); | |
207 | |
208 // Failure callback from WebSocketStream::CreateAndConnectStream(). Reports | |
209 // failure to the event interface. May delete |this|. | |
210 void OnConnectFailure(const std::string& message); | |
211 | |
212 // SSL certificate error callback from | |
213 // WebSocketStream::CreateAndConnectStream(). Forwards the request to the | |
214 // event interface. | |
215 void OnSSLCertificateError( | |
216 scoped_ptr<WebSocketEventInterface::SSLErrorCallbacks> | |
217 ssl_error_callbacks, | |
218 const SSLInfo& ssl_info, | |
219 bool fatal); | |
220 | |
221 // Posts a task that sends pending notifications relating WebSocket Opening | |
222 // Handshake to the renderer. | |
223 void ScheduleOpeningHandshakeNotification(); | |
224 | |
225 // Sets |state_| to |new_state| and updates UMA if necessary. | |
226 void SetState(State new_state); | |
227 | |
228 // Returns true if state_ is SEND_CLOSED, CLOSE_WAIT or CLOSED. | |
229 bool InClosingState() const; | |
230 | |
231 // Calls WebSocketStream::WriteFrames() with the appropriate arguments | |
232 ChannelState WriteFrames() WARN_UNUSED_RESULT; | |
233 | |
234 // Callback from WebSocketStream::WriteFrames. Sends pending data or adjusts | |
235 // the send quota of the renderer channel as appropriate. |result| is a net | |
236 // error code, usually OK. If |synchronous| is true, then OnWriteDone() is | |
237 // being called from within the WriteFrames() loop and does not need to call | |
238 // WriteFrames() itself. | |
239 ChannelState OnWriteDone(bool synchronous, int result) WARN_UNUSED_RESULT; | |
240 | |
241 // Calls WebSocketStream::ReadFrames() with the appropriate arguments. Stops | |
242 // calling ReadFrames if current_receive_quota_ is 0. | |
243 ChannelState ReadFrames() WARN_UNUSED_RESULT; | |
244 | |
245 // Callback from WebSocketStream::ReadFrames. Handles any errors and processes | |
246 // the returned chunks appropriately to their type. |result| is a net error | |
247 // code. If |synchronous| is true, then OnReadDone() is being called from | |
248 // within the ReadFrames() loop and does not need to call ReadFrames() itself. | |
249 ChannelState OnReadDone(bool synchronous, int result) WARN_UNUSED_RESULT; | |
250 | |
251 // Handles a single frame that the object has received enough of to process. | |
252 // May call |event_interface_| methods, send responses to the server, and | |
253 // change the value of |state_|. | |
254 // | |
255 // This method performs sanity checks on the frame that are needed regardless | |
256 // of the current state. Then, calls the HandleFrameByState() method below | |
257 // which performs the appropriate action(s) depending on the current state. | |
258 ChannelState HandleFrame( | |
259 scoped_ptr<WebSocketFrame> frame) WARN_UNUSED_RESULT; | |
260 | |
261 // Handles a single frame depending on the current state. It's used by the | |
262 // HandleFrame() method. | |
263 ChannelState HandleFrameByState( | |
264 const WebSocketFrameHeader::OpCode opcode, | |
265 bool final, | |
266 const scoped_refptr<IOBuffer>& data_buffer, | |
267 uint64 size) WARN_UNUSED_RESULT; | |
268 | |
269 // Forward a received data frame to the renderer, if connected. If | |
270 // |expecting_continuation| is not equal to |expecting_to_read_continuation_|, | |
271 // will fail the channel. Also checks the UTF-8 validity of text frames. | |
272 ChannelState HandleDataFrame(WebSocketFrameHeader::OpCode opcode, | |
273 bool final, | |
274 const scoped_refptr<IOBuffer>& data_buffer, | |
275 uint64 size) WARN_UNUSED_RESULT; | |
276 | |
277 // Low-level method to send a single frame. Used for both data and control | |
278 // frames. Either sends the frame immediately or buffers it to be scheduled | |
279 // when the current write finishes. |fin| and |op_code| are defined as for | |
280 // SendFrame() above, except that |op_code| may also be a control frame | |
281 // opcode. | |
282 ChannelState SendFrameFromIOBuffer(bool fin, | |
283 WebSocketFrameHeader::OpCode op_code, | |
284 const scoped_refptr<IOBuffer>& buffer, | |
285 uint64 size) WARN_UNUSED_RESULT; | |
286 | |
287 // Performs the "Fail the WebSocket Connection" operation as defined in | |
288 // RFC6455. A NotifyFailure message is sent to the renderer with |message|. | |
289 // The renderer will log the message to the console but not expose it to | |
290 // Javascript. Javascript will see a Close code of AbnormalClosure (1006) with | |
291 // an empty reason string. If state_ is CONNECTED then a Close message is sent | |
292 // to the remote host containing the supplied |code| and |reason|. If the | |
293 // stream is open, closes it and sets state_ to CLOSED. FailChannel() always | |
294 // returns CHANNEL_DELETED. It is not valid to access any member variables or | |
295 // methods after calling FailChannel(). | |
296 ChannelState FailChannel(const std::string& message, | |
297 uint16 code, | |
298 const std::string& reason) WARN_UNUSED_RESULT; | |
299 | |
300 // Sends a Close frame to Start the WebSocket Closing Handshake, or to respond | |
301 // to a Close frame from the server. As a special case, setting |code| to | |
302 // kWebSocketErrorNoStatusReceived will create a Close frame with no payload; | |
303 // this is symmetric with the behaviour of ParseClose. | |
304 ChannelState SendClose(uint16 code, | |
305 const std::string& reason) WARN_UNUSED_RESULT; | |
306 | |
307 // Parses a Close frame payload. If no status code is supplied, then |code| is | |
308 // set to 1005 (No status code) with empty |reason|. If the reason text is not | |
309 // valid UTF-8, then |reason| is set to an empty string. If the payload size | |
310 // is 1, or the supplied code is not permitted to be sent over the network, | |
311 // then false is returned and |message| is set to an appropriate console | |
312 // message. | |
313 bool ParseClose(const scoped_refptr<IOBuffer>& buffer, | |
314 uint64 size, | |
315 uint16* code, | |
316 std::string* reason, | |
317 std::string* message); | |
318 | |
319 // Drop this channel. | |
320 // If there are pending opening handshake notifications, notify them | |
321 // before dropping. | |
322 // | |
323 // Always returns CHANNEL_DELETED. | |
324 ChannelState DoDropChannel(bool was_clean, | |
325 uint16 code, | |
326 const std::string& reason); | |
327 | |
328 // Called if the closing handshake times out. Closes the connection and | |
329 // informs the |event_interface_| if appropriate. | |
330 void CloseTimeout(); | |
331 | |
332 // The URL of the remote server. | |
333 GURL socket_url_; | |
334 | |
335 // The object receiving events. | |
336 const scoped_ptr<WebSocketEventInterface> event_interface_; | |
337 | |
338 // The URLRequestContext to pass to the WebSocketStream creator. | |
339 URLRequestContext* const url_request_context_; | |
340 | |
341 // The WebSocketStream on which to send and receive data. | |
342 scoped_ptr<WebSocketStream> stream_; | |
343 | |
344 // A data structure containing a vector of frames to be sent and the total | |
345 // number of bytes contained in the vector. | |
346 class SendBuffer; | |
347 // Data that is currently pending write, or NULL if no write is pending. | |
348 scoped_ptr<SendBuffer> data_being_sent_; | |
349 // Data that is queued up to write after the current write completes. | |
350 // Only non-NULL when such data actually exists. | |
351 scoped_ptr<SendBuffer> data_to_send_next_; | |
352 | |
353 // Destination for the current call to WebSocketStream::ReadFrames | |
354 ScopedVector<WebSocketFrame> read_frames_; | |
355 | |
356 // Frames that have been read but not yet forwarded to the renderer due to | |
357 // lack of quota. | |
358 std::queue<PendingReceivedFrame> pending_received_frames_; | |
359 | |
360 // Handle to an in-progress WebSocketStream creation request. Only non-NULL | |
361 // during the connection process. | |
362 scoped_ptr<WebSocketStreamRequest> stream_request_; | |
363 | |
364 // If the renderer's send quota reaches this level, it is sent a quota | |
365 // refresh. "quota units" are currently bytes. TODO(ricea): Update the | |
366 // definition of quota units when necessary. | |
367 int send_quota_low_water_mark_; | |
368 // The level the quota is refreshed to when it reaches the low_water_mark | |
369 // (quota units). | |
370 int send_quota_high_water_mark_; | |
371 // The current amount of quota that the renderer has available for sending | |
372 // on this logical channel (quota units). | |
373 int current_send_quota_; | |
374 // The remaining amount of quota that the renderer will allow us to send on | |
375 // this logical channel (quota units). | |
376 uint64 current_receive_quota_; | |
377 | |
378 // Timer for the closing handshake. | |
379 base::OneShotTimer<WebSocketChannel> close_timer_; | |
380 | |
381 // Timeout for the closing handshake. | |
382 base::TimeDelta closing_handshake_timeout_; | |
383 | |
384 // Timeout for the underlying connection close after completion of closing | |
385 // handshake. | |
386 base::TimeDelta underlying_connection_close_timeout_; | |
387 | |
388 // Storage for the status code and reason from the time the Close frame | |
389 // arrives until the connection is closed and they are passed to | |
390 // OnDropChannel(). | |
391 bool has_received_close_frame_; | |
392 uint16 received_close_code_; | |
393 std::string received_close_reason_; | |
394 | |
395 // The current state of the channel. Mainly used for sanity checking, but also | |
396 // used to track the close state. | |
397 State state_; | |
398 | |
399 // |notification_sender_| is owned by this object. | |
400 scoped_ptr<HandshakeNotificationSender> notification_sender_; | |
401 | |
402 // UTF-8 validator for outgoing Text messages. | |
403 base::StreamingUtf8Validator outgoing_utf8_validator_; | |
404 bool sending_text_message_; | |
405 | |
406 // UTF-8 validator for incoming Text messages. | |
407 base::StreamingUtf8Validator incoming_utf8_validator_; | |
408 bool receiving_text_message_; | |
409 | |
410 // True if we are in the middle of receiving a message. | |
411 bool expecting_to_handle_continuation_; | |
412 | |
413 // True if we have already sent the type (Text or Binary) of the current | |
414 // message to the renderer. This can be false if the message is empty so far. | |
415 bool initial_frame_forwarded_; | |
416 | |
417 // For UMA. The time when OnConnectSuccess() method was called and |stream_| | |
418 // was set. | |
419 base::TimeTicks established_on_; | |
420 | |
421 DISALLOW_COPY_AND_ASSIGN(WebSocketChannel); | |
422 }; | |
423 | |
424 } // namespace net | |
425 | |
426 #endif // NET_WEBSOCKETS_WEBSOCKET_CHANNEL_H_ | |
OLD | NEW |