1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_WEBSOCKETS_WEBSOCKET_STREAM_H_
#define NET_WEBSOCKETS_WEBSOCKET_STREAM_H_
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/time/time.h"
#include "net/base/completion_once_callback.h"
#include "net/base/isolation_info.h"
#include "net/base/net_export.h"
#include "net/cookies/site_for_cookies.h"
#include "net/log/net_log_with_source.h"
#include "net/storage_access_api/status.h"
#include "net/websockets/websocket_event_interface.h"
#include "net/websockets/websocket_handshake_request_info.h"
#include "net/websockets/websocket_handshake_response_info.h"
class GURL;
namespace base {
class OneShotTimer;
class Time;
}
namespace url {
class Origin;
} // namespace url
namespace net {
class AuthChallengeInfo;
class AuthCredentials;
class HttpRequestHeaders;
class HttpResponseHeaders;
class IPEndPoint;
class IsolationInfo;
class NetLogWithSource;
class SSLInfo;
class SiteForCookies;
class URLRequest;
class URLRequestContext;
class WebSocketBasicHandshakeStream;
class WebSocketHttp2HandshakeStream;
class WebSocketHttp3HandshakeStream;
struct NetworkTrafficAnnotationTag;
struct TransportInfo;
struct WebSocketFrame;
struct WebSocketHandshakeRequestInfo;
struct WebSocketHandshakeResponseInfo;
// WebSocketStreamRequest is the caller's handle to the process of creation of a
// WebSocketStream. Deleting the object before the ConnectDelegate OnSuccess or
// OnFailure callbacks are called will cancel the request (and neither callback
// will be called). After OnSuccess or OnFailure have been called, this object
// may be safely deleted without side-effects.
class NET_EXPORT_PRIVATE WebSocketStreamRequest {
public:
virtual ~WebSocketStreamRequest();
};
// A subclass of WebSocketStreamRequest that exposes methods that are used as
// part of the handshake.
class NET_EXPORT_PRIVATE WebSocketStreamRequestAPI
: public WebSocketStreamRequest {
public:
virtual void OnBasicHandshakeStreamCreated(
WebSocketBasicHandshakeStream* handshake_stream) = 0;
virtual void OnHttp2HandshakeStreamCreated(
WebSocketHttp2HandshakeStream* handshake_stream) = 0;
virtual void OnHttp3HandshakeStreamCreated(
WebSocketHttp3HandshakeStream* handshake_stream) = 0;
virtual void OnFailure(const std::string& message,
int net_error,
std::optional<int> response_code) = 0;
};
// WebSocketStream is a transport-agnostic interface for reading and writing
// WebSocket frames. This class provides an abstraction for WebSocket streams
// based on various transport layers, such as normal WebSocket connections
// (WebSocket protocol upgraded from HTTP handshake), SPDY transports, or
// WebSocket connections with multiplexing extension. Subtypes of
// WebSocketStream are responsible for managing the underlying transport
// appropriately.
//
// All functions except Close() can be asynchronous. If an operation cannot
// be finished synchronously, the function returns ERR_IO_PENDING, and
// |callback| will be called when the operation is finished. Non-null |callback|
// must be provided to these functions.
class NET_EXPORT_PRIVATE WebSocketStream {
public:
// A concrete object derived from ConnectDelegate is supplied by the caller to
// CreateAndConnectStream() to receive the result of the connection.
class NET_EXPORT_PRIVATE ConnectDelegate {
public:
virtual ~ConnectDelegate();
// Called when the URLRequest is created.
virtual void OnCreateRequest(URLRequest* url_request) = 0;
// Called when the URLRequest::OnConnected() is called.
virtual void OnURLRequestConnected(URLRequest* request,
const TransportInfo& info) = 0;
// Called on successful connection. The parameter is an object derived from
// WebSocketStream.
virtual void OnSuccess(
std::unique_ptr<WebSocketStream> stream,
std::unique_ptr<WebSocketHandshakeResponseInfo> response) = 0;
// Called on failure to connect.
// |message| contains defails of the failure.
virtual void OnFailure(const std::string& message,
int net_error,
std::optional<int> response_code) = 0;
// Called when the WebSocket Opening Handshake starts.
virtual void OnStartOpeningHandshake(
std::unique_ptr<WebSocketHandshakeRequestInfo> request) = 0;
// Called when there is an SSL certificate error. Should call
// ssl_error_callbacks->ContinueSSLRequest() or
// ssl_error_callbacks->CancelSSLRequest().
virtual void OnSSLCertificateError(
std::unique_ptr<WebSocketEventInterface::SSLErrorCallbacks>
ssl_error_callbacks,
int net_error,
const SSLInfo& ssl_info,
bool fatal) = 0;
// Called when authentication is required. Returns a net error. The opening
// handshake is blocked when this function returns ERR_IO_PENDING.
// In that case calling |callback| resumes the handshake. |callback| can be
// called during the opening handshake. An implementation can rewrite
// |*credentials| (in the sync case) or provide new credentials (in the
// async case).
// Providing null credentials (nullopt in the sync case and nullptr in the
// async case) cancels authentication. Otherwise the new credentials are set
// and the opening handshake will be retried with the credentials.
virtual int OnAuthRequired(
const AuthChallengeInfo& auth_info,
scoped_refptr<HttpResponseHeaders> response_headers,
const IPEndPoint& remote_endpoint,
base::OnceCallback<void(const AuthCredentials*)> callback,
std::optional<AuthCredentials>* credentials) = 0;
};
// Create and connect a WebSocketStream of an appropriate type. The actual
// concrete type returned depends on whether multiplexing or SPDY are being
// used to communicate with the remote server. If the handshake completed
// successfully, then connect_delegate->OnSuccess() is called with a
// WebSocketStream instance. If it failed, then connect_delegate->OnFailure()
// is called with a WebSocket result code corresponding to the error. Deleting
// the returned WebSocketStreamRequest object will cancel the connection, in
// which case the |connect_delegate| object that the caller passed will be
// deleted without any of its methods being called. Unless cancellation is
// required, the caller should keep the WebSocketStreamRequest object alive
// until connect_delegate->OnSuccess() or OnFailure() have been called, then
// it is safe to delete.
static std::unique_ptr<WebSocketStreamRequest> CreateAndConnectStream(
const GURL& socket_url,
const std::vector<std::string>& requested_subprotocols,
const url::Origin& origin,
const SiteForCookies& site_for_cookies,
StorageAccessApiStatus storage_access_api_status,
const IsolationInfo& isolation_info,
const HttpRequestHeaders& additional_headers,
URLRequestContext* url_request_context,
const NetLogWithSource& net_log,
NetworkTrafficAnnotationTag traffic_annotation,
std::unique_ptr<ConnectDelegate> connect_delegate);
// Alternate version of CreateAndConnectStream() for testing use only. It
// takes |timer| as the handshake timeout timer, and for methods on
// WebSocketStreamRequestAPI calls the |api_delegate| object before the
// in-built behaviour if non-null.
static std::unique_ptr<WebSocketStreamRequest>
CreateAndConnectStreamForTesting(
const GURL& socket_url,
const std::vector<std::string>& requested_subprotocols,
const url::Origin& origin,
const SiteForCookies& site_for_cookies,
StorageAccessApiStatus storage_access_api_status,
const IsolationInfo& isolation_info,
const HttpRequestHeaders& additional_headers,
URLRequestContext* url_request_context,
const NetLogWithSource& net_log,
NetworkTrafficAnnotationTag traffic_annotation,
std::unique_ptr<ConnectDelegate> connect_delegate,
std::unique_ptr<base::OneShotTimer> timer,
std::unique_ptr<WebSocketStreamRequestAPI> api_delegate);
WebSocketStream(const WebSocketStream&) = delete;
WebSocketStream& operator=(const WebSocketStream&) = delete;
// Derived classes must make sure Close() is called when the stream is not
// closed on destruction.
virtual ~WebSocketStream();
// Reads WebSocket frame data. This operation finishes when new frame data
// becomes available.
//
// |frames| remains owned by the caller and must be valid until the
// operation completes or Close() is called. |frames| must be empty on
// calling.
//
// This function should not be called while the previous call of ReadFrames()
// is still pending.
//
// Returns net::OK or one of the net::ERR_* codes.
//
// frames->size() >= 1 if the result is OK.
//
// Only frames with complete header information are inserted into |frames|. If
// the currently available bytes of a new frame do not form a complete frame
// header, then the implementation will buffer them until all the fields in
// the WebSocketFrameHeader object can be filled. If ReadFrames() is freshly
// called in this situation, it will return ERR_IO_PENDING exactly as if no
// data was available.
//
// Original frame boundaries are not preserved. In particular, if only part of
// a frame is available, then the frame will be split, and the available data
// will be returned immediately.
//
// When the socket is closed on the remote side, this method will return
// ERR_CONNECTION_CLOSED. It will not return OK with an empty vector.
//
// If the connection is closed in the middle of receiving an incomplete frame,
// ReadFrames may discard the incomplete frame. Since the renderer will
// discard any incomplete messages when the connection is closed, this makes
// no difference to the overall semantics.
//
// Implementations of ReadFrames() must be able to handle being deleted during
// the execution of callback.Run(). In practice this means that the method
// calling callback.Run() (and any calling methods in the same object) must
// return immediately without any further method calls or access to member
// variables. Implementors should write test(s) for this case.
//
// Extensions which use reserved header bits should clear them when they are
// set correctly. If the reserved header bits are set incorrectly, it is okay
// to leave it to the caller to report the error.
//
// Each WebSocketFrame.data is owned by WebSocketStream and must be valid
// until next ReadFrames() call.
virtual int ReadFrames(std::vector<std::unique_ptr<WebSocketFrame>>* frames,
CompletionOnceCallback callback) = 0;
// Writes WebSocket frame data.
//
// |frames| must be valid until the operation completes or Close() is called.
//
// This function must not be called while a previous call of WriteFrames() is
// still pending.
//
// This method will only return OK if all frames were written completely.
// Otherwise it will return an appropriate net error code.
//
// The callback implementation is permitted to delete this
// object. Implementations of WriteFrames() should be robust against
// this. This generally means returning to the event loop immediately after
// calling the callback.
virtual int WriteFrames(std::vector<std::unique_ptr<WebSocketFrame>>* frames,
CompletionOnceCallback callback) = 0;
// Closes the stream. All pending I/O operations (if any) are cancelled
// at this point, so |frames| can be freed.
virtual void Close() = 0;
// The subprotocol that was negotiated for the stream. If no protocol was
// negotiated, then the empty string is returned.
virtual std::string GetSubProtocol() const = 0;
// The extensions that were negotiated for the stream. Since WebSocketStreams
// can be layered, this may be different from what this particular
// WebSocketStream implements. The primary purpose of this accessor is to make
// the data available to Javascript. The format of the string is identical to
// the contents of the Sec-WebSocket-Extensions header supplied by the server,
// with some canonicalisations applied (leading and trailing whitespace
// removed, multiple headers concatenated into one comma-separated list). See
// RFC6455 section 9.1 for the exact format specification. If no
// extensions were negotiated, the empty string is returned.
virtual std::string GetExtensions() const = 0;
virtual const NetLogWithSource& GetNetLogWithSource() const = 0;
protected:
WebSocketStream();
};
// A helper function used in the implementation of CreateAndConnectStream() and
// WebSocketBasicHandshakeStream. It creates a WebSocketHandshakeResponseInfo
// object and dispatches it to the OnFinishOpeningHandshake() method of the
// supplied |connect_delegate|.
void WebSocketDispatchOnFinishOpeningHandshake(
WebSocketStream::ConnectDelegate* connect_delegate,
const GURL& gurl,
const scoped_refptr<HttpResponseHeaders>& headers,
const IPEndPoint& remote_endpoint,
base::Time response_time);
} // namespace net
#endif // NET_WEBSOCKETS_WEBSOCKET_STREAM_H_
|