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