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