private void AddRequestHeaders(Uri uri, ClientWebSocketOptions options) { var requestHeadersBuffer = new StringBuilder(); // Manually add cookies. if (options.Cookies != null) { string cookieHeader = GetCookieHeader(uri, options.Cookies); if (!string.IsNullOrEmpty(cookieHeader)) { requestHeadersBuffer.AppendLine(cookieHeader); } } // Serialize general request headers. requestHeadersBuffer.AppendLine(options.RequestHeaders.ToString()); var subProtocols = options.RequestedSubProtocols; if (subProtocols.Count > 0) { requestHeadersBuffer.AppendLine(string.Format("{0}: {1}", HeaderNameWebSocketProtocol, string.Join(", ", subProtocols))); } // Add request headers to WinHTTP request handle. if (!Interop.WinHttp.WinHttpAddRequestHeaders( _operation.RequestHandle, requestHeadersBuffer, (uint)requestHeadersBuffer.Length, Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD)) { WinHttpException.ThrowExceptionUsingLastError(); } }
// Requires lock taken. private Interop.WinHttp.SafeWinHttpHandle InitializeWinHttp(ClientWebSocketOptions options) { Interop.WinHttp.SafeWinHttpHandle sessionHandle; sessionHandle = Interop.WinHttp.WinHttpOpen( IntPtr.Zero, Interop.WinHttp.WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, null, null, (int)Interop.WinHttp.WINHTTP_FLAG_ASYNC); ThrowOnInvalidHandle(sessionHandle); uint optionAssuredNonBlockingTrue = 1; // TRUE if (!Interop.WinHttp.WinHttpSetOption( sessionHandle, Interop.WinHttp.WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS, ref optionAssuredNonBlockingTrue, (uint)Marshal.SizeOf <uint>())) { WinHttpException.ThrowExceptionUsingLastError(); } return(sessionHandle); }
public Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { cancellationToken.ThrowIfCancellationRequested(); var ws = new BrowserWebSocket(); WebSocket = ws; return(ws.ConnectAsync(uri, options.RequestedSubProtocols, cancellationToken)); }
public ClientWebSocket() { if (Logging.On) Logging.Enter(Logging.WebSockets, this, ".ctor", null); if (!WebSocketProtocolComponent.IsSupported) { WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); } state = created; options = new ClientWebSocketOptions(); cts = new CancellationTokenSource(); if (Logging.On) Logging.Exit(Logging.WebSockets, this, ".ctor", null); }
public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { try { await _webSocket.ConnectAsync(uri, cancellationToken, options).ConfigureAwait(false); } catch (Exception ex) { WebErrorStatus status = RTWebSocketError.GetStatus(ex.HResult); var inner = new Exception(status.ToString(), ex); WebSocketException wex = new WebSocketException(SR.net_webstatus_ConnectFailure, inner); if (NetEventSource.IsEnabled) NetEventSource.Error(_webSocket, wex); throw wex; } }
public ClientWebSocket() { if (NetEventSource.IsEnabled) { NetEventSource.Enter(this); } WebSocketHandle.CheckPlatformSupport(); _state = (int)InternalState.Created; _options = new ClientWebSocketOptions(); if (NetEventSource.IsEnabled) { NetEventSource.Exit(this); } }
public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { try { await _webSocket.ConnectAsync(uri, cancellationToken, options).ConfigureAwait(false); } catch (Win32Exception ex) { WebSocketException wex = new WebSocketException(SR.net_webstatus_ConnectFailure, ex); if (Logging.On) { Logging.Exception(Logging.WebSockets, this, "ConnectAsync", wex); } throw wex; } }
public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { try { await _webSocket.ConnectAsync(uri, cancellationToken, options).ConfigureAwait(false); } catch (Win32Exception ex) { WebSocketException wex = new WebSocketException(SR.net_webstatus_ConnectFailure, ex); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Exception(NetEventSource.ComponentType.WebSocket, this, "ConnectAsync", wex); } throw wex; } }
public ClientWebSocket() { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Enter(NetEventSource.ComponentType.WebSocket, this, ".ctor", null); } WebSocketHandle.CheckPlatformSupport(); _state = (int)InternalState.Created; _options = new ClientWebSocketOptions(); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Exit(NetEventSource.ComponentType.WebSocket, this, ".ctor", null); } }
public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { try { cancellationToken.ThrowIfCancellationRequested(); // avoid allocating a WebSocket object if cancellation was requested before connect CancellationTokenSource?linkedCancellation; CancellationTokenSource externalAndAbortCancellation; if (cancellationToken.CanBeCanceled) // avoid allocating linked source if external token is not cancelable { linkedCancellation = externalAndAbortCancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _abortSource.Token); } else { linkedCancellation = null; externalAndAbortCancellation = _abortSource; } using (linkedCancellation) { WebSocket = new BrowserWebSocket(); await((BrowserWebSocket)WebSocket).ConnectAsyncJavaScript(uri, externalAndAbortCancellation.Token, options.RequestedSubProtocols).ConfigureAwait(continueOnCapturedContext: true); externalAndAbortCancellation.Token.ThrowIfCancellationRequested(); } } catch (Exception exc) { if (_state < WebSocketState.Closed) { _state = WebSocketState.Closed; } Abort(); switch (exc) { case WebSocketException: case OperationCanceledException _ when cancellationToken.IsCancellationRequested: throw; default: throw new WebSocketException(SR.net_webstatus_ConnectFailure, exc); } } }
public ClientWebSocket() { if (Logging.On) { Logging.Enter(Logging.WebSockets, this, ".ctor", null); } WebSocketHandle.CheckPlatformSupport(); _state = (int)InternalState.Created; _options = new ClientWebSocketOptions(); _cts = new CancellationTokenSource(); if (Logging.On) { Logging.Exit(Logging.WebSockets, this, ".ctor", null); } }
public ClientWebSocket() { if (Logging.On) { Logging.Enter(Logging.WebSockets, this, ".ctor", null); } CheckPlatformSupport(); _state = (int)InternalState.Created; _options = new ClientWebSocketOptions(); _cts = new CancellationTokenSource(); if (Logging.On) { Logging.Exit(Logging.WebSockets, this, ".ctor", null); } }
public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { InterlockedCheckAndUpdateState(WebSocketState.Connecting, s_validConnectStates); CheckValidState(s_validConnectingStates); _messageWebSocket = new MessageWebSocket(); foreach (var header in options.RequestHeaders) { _messageWebSocket.SetRequestHeader((string)header, options.RequestHeaders[(string)header]); } string cookies = options.Cookies == null ? null : options.Cookies.GetCookieHeader(uri); if (!string.IsNullOrEmpty(cookies)) { _messageWebSocket.SetRequestHeader(HeaderNameCookie, cookies); } var websocketControl = _messageWebSocket.Control; foreach (var subProtocol in options.RequestedSubProtocols) { websocketControl.SupportedProtocols.Add(subProtocol); } try { _receiveAsyncBufferTcs = new TaskCompletionSource <ArraySegment <byte> >(); _closeWebSocketReceiveResultTcs = new TaskCompletionSource <WebSocketReceiveResult>(); _messageWebSocket.MessageReceived += OnMessageReceived; _messageWebSocket.Closed += OnCloseReceived; await _messageWebSocket.ConnectAsync(uri).AsTask(cancellationToken); _subProtocol = _messageWebSocket.Information.Protocol; _messageWriter = new DataWriter(_messageWebSocket.OutputStream); } catch (Exception) { UpdateState(WebSocketState.Closed); throw; } UpdateState(WebSocketState.Open); }
public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { try { await _webSocket.ConnectAsync(uri, cancellationToken, options).ConfigureAwait(false); } catch (Exception ex) { WebErrorStatus status = RTWebSocketError.GetStatus(ex.HResult); var inner = new Exception(status.ToString(), ex); WebSocketException wex = new WebSocketException(SR.net_webstatus_ConnectFailure, inner); if (Logging.On) { Logging.Exception(Logging.WebSockets, this, "ConnectAsync", wex); } throw wex; } }
public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { InterlockedCheckAndUpdateState(WebSocketState.Connecting, s_validConnectStates); CheckValidState(s_validConnectingStates); _messageWebSocket = new MessageWebSocket(); foreach (var header in options.RequestHeaders) { _messageWebSocket.SetRequestHeader((string)header, options.RequestHeaders[(string)header]); } string cookies = options.Cookies == null ? null : options.Cookies.GetCookieHeader(uri); if (!string.IsNullOrEmpty(cookies)) { _messageWebSocket.SetRequestHeader(HeaderNameCookie, cookies); } var websocketControl = _messageWebSocket.Control; foreach (var subProtocol in options.RequestedSubProtocols) { websocketControl.SupportedProtocols.Add(subProtocol); } try { _receiveAsyncBufferTcs = new TaskCompletionSource<ArraySegment<byte>>(); _closeWebSocketReceiveResultTcs = new TaskCompletionSource<WebSocketReceiveResult>(); _messageWebSocket.MessageReceived += OnMessageReceived; _messageWebSocket.Closed += OnCloseReceived; await _messageWebSocket.ConnectAsync(uri).AsTask(cancellationToken); _subProtocol = _messageWebSocket.Information.Protocol; _messageWriter = new DataWriter(_messageWebSocket.OutputStream); } catch (Exception) { UpdateState(WebSocketState.Closed); throw; } UpdateState(WebSocketState.Open); }
// internal API ///////////////////////////////////////////////////////////// internal WebSocket(Uri uri, WebSocketListener listener) { bool ignoreCase = true; this.uri = uri; this.listener = listener; this.protocols = new ArrayList(); if ((String.Compare("ws", uri.Scheme, ignoreCase) != 0) && (String.Compare("wss", uri.Scheme, ignoreCase) != 0)) { throw new Exception("URI scheme must be 'ws' or 'wss'"); } clientWebSocket = new ClientWebSocket(); options = clientWebSocket.Options; // turn off pongs from client to server. options.KeepAliveInterval = new System.TimeSpan(0); }
public ClientWebSocket() { if (Logging.On) { Logging.Enter(Logging.WebSockets, this, ".ctor", null); } if (!WebSocketProtocolComponent.IsSupported) { WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); } state = created; options = new ClientWebSocketOptions(); cts = new CancellationTokenSource(); if (Logging.On) { Logging.Exit(Logging.WebSockets, this, ".ctor", null); } }
private void AddRequestHeaders(Uri uri, ClientWebSocketOptions options) { var requestHeadersBuffer = new StringBuilder(); // Manually add cookies. if (options.Cookies != null) { AppendCookieHeaderLine(uri, options.Cookies, requestHeadersBuffer); } // Serialize general request headers. requestHeadersBuffer.AppendLine(options.RequestHeaders.ToString()); using (List <string> .Enumerator e = options.RequestedSubProtocols.GetEnumerator()) { if (e.MoveNext()) { requestHeadersBuffer.Append(HeaderNameWebSocketProtocol + ": "); requestHeadersBuffer.Append(e.Current); while (e.MoveNext()) { requestHeadersBuffer.Append(", "); requestHeadersBuffer.Append(e.Current); } requestHeadersBuffer.AppendLine(); } } // Add request headers to WinHTTP request handle. if (!Interop.WinHttp.WinHttpAddRequestHeaders( _operation.RequestHandle, requestHeadersBuffer, (uint)requestHeadersBuffer.Length, Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD)) { WinHttpException.ThrowExceptionUsingLastError(); } }
public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { try { await _webSocket.ConnectAsync(uri, cancellationToken, options).ConfigureAwait(false); } catch (Exception ex) { // TODO #4143: ** TFS BUILD IS BROKEN ** // This doesn't compile right now due to missing types 'WebErrorStatus' and 'RTWebSocketError' // Commenting out for now to allow the build to resume. //WebErrorStatus status = RTWebSocketError.GetStatus(ex.HResult); //var inner = new Exception(status.ToString(), ex); var inner = ex; WebSocketException wex = new WebSocketException(SR.net_webstatus_ConnectFailure, inner); if (Logging.On) { Logging.Exception(Logging.WebSockets, this, "ConnectAsync", wex); } throw wex; } }
public FrameworkClientWebSocketOptions(System.Net.WebSockets.ClientWebSocketOptions options) { this.options = options; }
public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { if (options.RemoteCertificateValidationCallback != null) { throw new PlatformNotSupportedException(SR.net_WebSockets_RemoteValidationCallbackNotSupported); } try { await _webSocket.ConnectAsync(uri, cancellationToken, options).ConfigureAwait(false); } catch (Exception ex) { WebErrorStatus status = RTWebSocketError.GetStatus(ex.HResult); var inner = new Exception(status.ToString(), ex); WebSocketException wex = new WebSocketException(WebSocketError.Faulted, SR.net_webstatus_ConnectFailure, inner); if (NetEventSource.IsEnabled) { NetEventSource.Error(_webSocket, wex); } throw wex; } }
public ClientWebSocket() { options = new ClientWebSocketOptions(); state = WebSocketState.None; headerBuffer = new byte[HeaderMaxLength]; }
/// <summary>Adds the necessary headers for the web socket request.</summary> /// <param name="request">The request to which the headers should be added.</param> /// <param name="secKey">The generated security key to send in the Sec-WebSocket-Key header.</param> /// <param name="options">The options controlling the request.</param> private static void AddWebSocketHeaders(HttpRequestMessage request, string secKey, ClientWebSocketOptions options) { request.Headers.TryAddWithoutValidation(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade); request.Headers.TryAddWithoutValidation(HttpKnownHeaderNames.Upgrade, "websocket"); request.Headers.TryAddWithoutValidation(HttpKnownHeaderNames.SecWebSocketVersion, "13"); request.Headers.TryAddWithoutValidation(HttpKnownHeaderNames.SecWebSocketKey, secKey); if (options._requestedSubProtocols?.Count > 0) { request.Headers.TryAddWithoutValidation(HttpKnownHeaderNames.SecWebSocketProtocol, string.Join(", ", options.RequestedSubProtocols)); } }
public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { try { await _webSocket.ConnectAsync(uri, cancellationToken, options).ConfigureAwait(false); } catch (Exception ex) { WebErrorStatus status = RTWebSocketError.GetStatus(ex.HResult); var inner = new Exception(status.ToString(), ex); WebSocketException wex = new WebSocketException(SR.net_webstatus_ConnectFailure, inner); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Exception(NetEventSource.ComponentType.WebSocket, this, "ConnectAsync", wex); } throw wex; } }
public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { _operation.InterlockedCheckAndUpdateState(WebSocketState.Connecting, s_validConnectStates); using (CancellationTokenRegistration ctr = ThrowOrRegisterCancellation(cancellationToken)) { lock (_operation.Lock) { _operation.CheckValidState(s_validConnectingStates); // Must grab lock until RequestHandle is populated, otherwise we risk resource leaks on Abort. // // TODO (Issue 2506): Alternatively, release the lock between WinHTTP operations and check, under lock, that the // state is still valid to continue operation. _operation.SessionHandle = InitializeWinHttp(options); _operation.ConnectionHandle = Interop.WinHttp.WinHttpConnectWithCallback( _operation.SessionHandle, uri.IdnHost, (ushort)uri.Port, 0); ThrowOnInvalidHandle(_operation.ConnectionHandle); bool secureConnection = uri.Scheme == UriScheme.Https || uri.Scheme == UriScheme.Wss; _operation.RequestHandle = Interop.WinHttp.WinHttpOpenRequestWithCallback( _operation.ConnectionHandle, "GET", uri.PathAndQuery, null, Interop.WinHttp.WINHTTP_NO_REFERER, null, secureConnection ? Interop.WinHttp.WINHTTP_FLAG_SECURE : 0); ThrowOnInvalidHandle(_operation.RequestHandle); if (!Interop.WinHttp.WinHttpSetOption( _operation.RequestHandle, Interop.WinHttp.WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, IntPtr.Zero, 0)) { WinHttpException.ThrowExceptionUsingLastError(); } // We need the address of the IntPtr to the GCHandle. IntPtr context = _operation.ToIntPtr(); IntPtr contextAddress; unsafe { contextAddress = (IntPtr)(void*)&context; } if (!Interop.WinHttp.WinHttpSetOption( _operation.RequestHandle, Interop.WinHttp.WINHTTP_OPTION_CONTEXT_VALUE, contextAddress, (uint)IntPtr.Size)) { WinHttpException.ThrowExceptionUsingLastError(); } if (Interop.WinHttp.WinHttpSetStatusCallback( _operation.RequestHandle, WinHttpWebSocketCallback.s_StaticCallbackDelegate, Interop.WinHttp.WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, IntPtr.Zero) == (IntPtr)Interop.WinHttp.WINHTTP_INVALID_STATUS_CALLBACK) { WinHttpException.ThrowExceptionUsingLastError(); } _operation.RequestHandle.AttachCallback(); AddRequestHeaders(uri, options); _operation.TcsUpgrade = new TaskCompletionSource<bool>(); } await InternalSendWsUpgradeRequestAsync().ConfigureAwait(false); await InternalReceiveWsUpgradeResponse().ConfigureAwait(false); lock (_operation.Lock) { VerifyUpgradeResponse(); ThrowOnInvalidConnectState(); _operation.WebSocketHandle = Interop.WinHttp.WinHttpWebSocketCompleteUpgrade(_operation.RequestHandle, IntPtr.Zero); ThrowOnInvalidHandle(_operation.WebSocketHandle); // We need the address of the IntPtr to the GCHandle. IntPtr context = _operation.ToIntPtr(); IntPtr contextAddress; unsafe { contextAddress = (IntPtr)(void*)&context; } if (!Interop.WinHttp.WinHttpSetOption( _operation.WebSocketHandle, Interop.WinHttp.WINHTTP_OPTION_CONTEXT_VALUE, contextAddress, (uint)IntPtr.Size)) { WinHttpException.ThrowExceptionUsingLastError(); } _operation.WebSocketHandle.AttachCallback(); _operation.UpdateState(WebSocketState.Open); if (_operation.RequestHandle != null) { _operation.RequestHandle.Dispose(); // RequestHandle will be set to null in the callback. } _operation.TcsUpgrade = null; ctr.Dispose(); } } }
public ClientWebSocket () { options = new ClientWebSocketOptions (); state = WebSocketState.None; headerBuffer = new byte[HeaderMaxLength]; }
// Requires lock taken. private Interop.WinHttp.SafeWinHttpHandle InitializeWinHttp(ClientWebSocketOptions options) { Interop.WinHttp.SafeWinHttpHandle sessionHandle; sessionHandle = Interop.WinHttp.WinHttpOpen( IntPtr.Zero, Interop.WinHttp.WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, null, null, (int)Interop.WinHttp.WINHTTP_FLAG_ASYNC); ThrowOnInvalidHandle(sessionHandle); uint optionAssuredNonBlockingTrue = 1; // TRUE if (!Interop.WinHttp.WinHttpSetOption( sessionHandle, Interop.WinHttp.WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS, ref optionAssuredNonBlockingTrue, (uint)Marshal.SizeOf<uint>())) { WinHttpException.ThrowExceptionUsingLastError(); } return sessionHandle; }
/// <summary>Creates a byte[] containing the headers to send to the server.</summary> /// <param name="uri">The Uri of the server.</param> /// <param name="options">The options used to configure the websocket.</param> /// <param name="secKey">The generated security key to send in the Sec-WebSocket-Key header.</param> /// <returns>The byte[] containing the encoded headers ready to send to the network.</returns> private static byte[] BuildRequestHeader(Uri uri, ClientWebSocketOptions options, string secKey) { StringBuilder builder = t_cachedStringBuilder ?? (t_cachedStringBuilder = new StringBuilder()); Debug.Assert(builder.Length == 0, $"Expected builder to be empty, got one of length {builder.Length}"); try { builder.Append("GET ").Append(uri.PathAndQuery).Append(" HTTP/1.1\r\n"); // Add all of the required headers builder.Append("Host: ").Append(uri.IdnHost).Append(":").Append(uri.Port).Append("\r\n"); builder.Append("Connection: Upgrade\r\n"); builder.Append("Upgrade: websocket\r\n"); builder.Append("Sec-WebSocket-Version: 13\r\n"); builder.Append("Sec-WebSocket-Key: ").Append(secKey).Append("\r\n"); // Add all of the additionally requested headers foreach (string key in options.RequestHeaders.AllKeys) { builder.Append(key).Append(": ").Append(options.RequestHeaders[key]).Append("\r\n"); } // Add the optional subprotocols header if (options.RequestedSubProtocols.Count > 0) { builder.Append(HttpKnownHeaderNames.SecWebSocketProtocol).Append(": "); builder.Append(options.RequestedSubProtocols[0]); for (int i = 1; i < options.RequestedSubProtocols.Count; i++) { builder.Append(", ").Append(options.RequestedSubProtocols[i]); } builder.Append("\r\n"); } // Add an optional cookies header if (options.Cookies != null) { string header = options.Cookies.GetCookieHeader(uri); if (!string.IsNullOrWhiteSpace(header)) { builder.Append(HttpKnownHeaderNames.Cookie).Append(": ").Append(header).Append("\r\n"); } } // End the headers builder.Append("\r\n"); // Return the bytes for the built up header return s_defaultHttpEncoding.GetBytes(builder.ToString()); } finally { // Make sure we clear the builder builder.Clear(); } }
/// <summary>Read and validate the connect response headers from the server.</summary> /// <param name="stream">The stream from which to read the response headers.</param> /// <param name="options">The options used to configure the websocket.</param> /// <param name="expectedSecWebSocketAccept">The expected value of the Sec-WebSocket-Accept header.</param> /// <param name="cancellationToken">The CancellationToken to use to cancel the websocket.</param> /// <returns>The agreed upon subprotocol with the server, or null if there was none.</returns> private async Task<string> ParseAndValidateConnectResponseAsync( Stream stream, ClientWebSocketOptions options, string expectedSecWebSocketAccept, CancellationToken cancellationToken) { // Read the first line of the response string statusLine = await ReadResponseHeaderLineAsync(stream, cancellationToken).ConfigureAwait(false); // Depending on the underlying sockets implementation and timing, connecting to a server that then // immediately closes the connection may either result in an exception getting thrown from the connect // earlier, or it may result in getting to here but reading 0 bytes. If we read 0 bytes and thus have // an empty status line, treat it as a connect failure. if (string.IsNullOrEmpty(statusLine)) { throw new WebSocketException(SR.Format(SR.net_webstatus_ConnectFailure)); } const string ExpectedStatusStart = "HTTP/1.1 "; const string ExpectedStatusStatWithCode = "HTTP/1.1 101"; // 101 == SwitchingProtocols // If the status line doesn't begin with "HTTP/1.1" or isn't long enough to contain a status code, fail. if (!statusLine.StartsWith(ExpectedStatusStart, StringComparison.Ordinal) || statusLine.Length < ExpectedStatusStatWithCode.Length) { throw new WebSocketException(WebSocketError.HeaderError); } // If the status line doesn't contain a status code 101, or if it's long enough to have a status description // but doesn't contain whitespace after the 101, fail. if (!statusLine.StartsWith(ExpectedStatusStatWithCode, StringComparison.Ordinal) || (statusLine.Length > ExpectedStatusStatWithCode.Length && !char.IsWhiteSpace(statusLine[ExpectedStatusStatWithCode.Length]))) { throw new WebSocketException(SR.net_webstatus_ConnectFailure); } // Read each response header. Be liberal in parsing the response header, treating // everything to the left of the colon as the key and everything to the right as the value, trimming both. // For each header, validate that we got the expected value. bool foundUpgrade = false, foundConnection = false, foundSecWebSocketAccept = false; string subprotocol = null; string line; while (!string.IsNullOrEmpty(line = await ReadResponseHeaderLineAsync(stream, cancellationToken).ConfigureAwait(false))) { int colonIndex = line.IndexOf(':'); if (colonIndex == -1) { throw new WebSocketException(WebSocketError.HeaderError); } string headerName = line.SubstringTrim(0, colonIndex); string headerValue = line.SubstringTrim(colonIndex + 1); // The Connection, Upgrade, and SecWebSocketAccept headers are required and with specific values. ValidateAndTrackHeader(HttpKnownHeaderNames.Connection, "Upgrade", headerName, headerValue, ref foundConnection); ValidateAndTrackHeader(HttpKnownHeaderNames.Upgrade, "websocket", headerName, headerValue, ref foundUpgrade); ValidateAndTrackHeader(HttpKnownHeaderNames.SecWebSocketAccept, expectedSecWebSocketAccept, headerName, headerValue, ref foundSecWebSocketAccept); // The SecWebSocketProtocol header is optional. We should only get it with a non-empty value if we requested subprotocols, // and then it must only be one of the ones we requested. If we got a subprotocol other than one we requested (or if we // already got one in a previous header), fail. Otherwise, track which one we got. if (string.Equals(HttpKnownHeaderNames.SecWebSocketProtocol, headerName, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(headerValue)) { string newSubprotocol = options.RequestedSubProtocols.Find(requested => string.Equals(requested, headerValue, StringComparison.OrdinalIgnoreCase)); if (newSubprotocol == null || subprotocol != null) { throw new WebSocketException( WebSocketError.UnsupportedProtocol, SR.Format(SR.net_WebSockets_AcceptUnsupportedProtocol, string.Join(", ", options.RequestedSubProtocols), subprotocol)); } subprotocol = newSubprotocol; } } if (!foundUpgrade || !foundConnection || !foundSecWebSocketAccept) { throw new WebSocketException(SR.net_webstatus_ConnectFailure); } return subprotocol; }
public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { // Not currently used: // - ClientWebSocketOptions.Credentials // - ClientWebSocketOptions.Proxy lock (StateUpdateLock) { ClientWebSocket.ThrowIfInvalidState(_state, _disposed, s_validConnectStates); _state = WebSocketState.Connecting; } // Establish connection to the server CancellationTokenRegistration registration = cancellationToken.Register(s => ((ManagedClientWebSocket)s).Abort(), this); try { // Connect to the remote server Socket connectedSocket = await ConnectSocketAsync(uri.Host, uri.Port, cancellationToken).ConfigureAwait(false); SetStream(new AsyncEventArgsNetworkStream(connectedSocket)); // Upgrade to SSL if needed if (uri.Scheme == UriScheme.Wss) { var sslStream = new SslStream(_stream); await sslStream.AuthenticateAsClientAsync( uri.Host, options.ClientCertificates, SecurityProtocol.AllowedSecurityProtocols, checkCertificateRevocation: false).ConfigureAwait(false); SetStream(sslStream); } // Create the security key and expected response, then build all of the request headers KeyValuePair<string, string> secKeyAndSecWebSocketAccept = CreateSecKeyAndSecWebSocketAccept(); byte[] requestHeader = BuildRequestHeader(uri, options, secKeyAndSecWebSocketAccept.Key); // Write out the header to the connection await _stream.WriteAsync(requestHeader, 0, requestHeader.Length, cancellationToken).ConfigureAwait(false); // Parse the response and store our state for the remainder of the connection _subprotocol = await ParseAndValidateConnectResponseAsync(options, secKeyAndSecWebSocketAccept.Value, cancellationToken).ConfigureAwait(false); lock (StateUpdateLock) { if (_state == WebSocketState.Connecting) { _state = WebSocketState.Open; } } // Now that we're opened, initiate the keep alive timer to send periodic pings if (options.KeepAliveInterval > TimeSpan.Zero) { _keepAliveTimer = new Timer( s => ((ManagedClientWebSocket)s).SendKeepAliveFrameAsync(), this, options.KeepAliveInterval, options.KeepAliveInterval); } } catch (Exception exc) { lock (StateUpdateLock) { if (_state < WebSocketState.Closed) { _state = WebSocketState.Closed; } } Abort(); if (exc is WebSocketException) { throw; } throw new WebSocketException(SR.net_webstatus_ConnectFailure, exc); } finally { registration.Dispose(); } }
public Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { throw new PlatformNotSupportedException(SR.net_WebSockets_UnsupportedPlatform); }
public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { HttpResponseMessage?response = null; SocketsHttpHandler? handler = null; bool disposeHandler = true; try { var request = new HttpRequestMessage(HttpMethod.Get, uri); if (options._requestHeaders?.Count > 0) // use field to avoid lazily initializing the collection { foreach (string key in options.RequestHeaders) { request.Headers.TryAddWithoutValidation(key, options.RequestHeaders[key]); } } // Create the security key and expected response, then build all of the request headers KeyValuePair <string, string> secKeyAndSecWebSocketAccept = CreateSecKeyAndSecWebSocketAccept(); AddWebSocketHeaders(request, secKeyAndSecWebSocketAccept.Key, options); // Create the handler for this request and populate it with all of the options. // Try to use a shared handler rather than creating a new one just for this request, if // the options are compatible. if (options.Credentials == null && !options.UseDefaultCredentials && options.Proxy == null && options.Cookies == null && options.RemoteCertificateValidationCallback == null && options._clientCertificates?.Count == 0) { disposeHandler = false; handler = s_defaultHandler; if (handler == null) { handler = new SocketsHttpHandler() { PooledConnectionLifetime = TimeSpan.Zero, UseProxy = false, UseCookies = false, }; if (Interlocked.CompareExchange(ref s_defaultHandler, handler, null) != null) { handler.Dispose(); handler = s_defaultHandler; } } } else { handler = new SocketsHttpHandler(); handler.PooledConnectionLifetime = TimeSpan.Zero; handler.CookieContainer = options.Cookies; handler.UseCookies = options.Cookies != null; handler.SslOptions.RemoteCertificateValidationCallback = options.RemoteCertificateValidationCallback; if (options.UseDefaultCredentials) { handler.Credentials = CredentialCache.DefaultCredentials; } else { handler.Credentials = options.Credentials; } if (options.Proxy == null) { handler.UseProxy = false; } else if (options.Proxy != DefaultWebProxy.Instance) { handler.Proxy = options.Proxy; } if (options._clientCertificates?.Count > 0) // use field to avoid lazily initializing the collection { Debug.Assert(handler.SslOptions.ClientCertificates == null); handler.SslOptions.ClientCertificates = new X509Certificate2Collection(); handler.SslOptions.ClientCertificates.AddRange(options.ClientCertificates); } } // Issue the request. The response must be status code 101. CancellationTokenSource?linkedCancellation; CancellationTokenSource externalAndAbortCancellation; if (cancellationToken.CanBeCanceled) // avoid allocating linked source if external token is not cancelable { linkedCancellation = externalAndAbortCancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _abortSource.Token); } else { linkedCancellation = null; externalAndAbortCancellation = _abortSource; } using (linkedCancellation) { response = await new HttpMessageInvoker(handler).SendAsync(request, externalAndAbortCancellation.Token).ConfigureAwait(false); externalAndAbortCancellation.Token.ThrowIfCancellationRequested(); // poll in case sends/receives in request/response didn't observe cancellation } if (response.StatusCode != HttpStatusCode.SwitchingProtocols) { throw new WebSocketException(WebSocketError.NotAWebSocket, SR.Format(SR.net_WebSockets_Connect101Expected, (int)response.StatusCode)); } // The Connection, Upgrade, and SecWebSocketAccept headers are required and with specific values. ValidateHeader(response.Headers, HttpKnownHeaderNames.Connection, "Upgrade"); ValidateHeader(response.Headers, HttpKnownHeaderNames.Upgrade, "websocket"); ValidateHeader(response.Headers, HttpKnownHeaderNames.SecWebSocketAccept, secKeyAndSecWebSocketAccept.Value); // The SecWebSocketProtocol header is optional. We should only get it with a non-empty value if we requested subprotocols, // and then it must only be one of the ones we requested. If we got a subprotocol other than one we requested (or if we // already got one in a previous header), fail. Otherwise, track which one we got. string?subprotocol = null; if (response.Headers.TryGetValues(HttpKnownHeaderNames.SecWebSocketProtocol, out IEnumerable <string>?subprotocolEnumerableValues)) { Debug.Assert(subprotocolEnumerableValues is string[]); string[] subprotocolArray = (string[])subprotocolEnumerableValues; if (subprotocolArray.Length > 0 && !string.IsNullOrEmpty(subprotocolArray[0])) { subprotocol = options.RequestedSubProtocols.Find(requested => string.Equals(requested, subprotocolArray[0], StringComparison.OrdinalIgnoreCase)); if (subprotocol == null) { throw new WebSocketException( WebSocketError.UnsupportedProtocol, SR.Format(SR.net_WebSockets_AcceptUnsupportedProtocol, string.Join(", ", options.RequestedSubProtocols), string.Join(", ", subprotocolArray))); } } } if (response.Content is null) { throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely); } // Get the response stream and wrap it in a web socket. Stream connectedStream = response.Content.ReadAsStream(); Debug.Assert(connectedStream.CanWrite); Debug.Assert(connectedStream.CanRead); WebSocket = WebSocket.CreateFromStream( connectedStream, isServer: false, subprotocol, options.KeepAliveInterval); } catch (Exception exc) { if (_state < WebSocketState.Closed) { _state = WebSocketState.Closed; } Abort(); response?.Dispose(); if (exc is WebSocketException || (exc is OperationCanceledException && cancellationToken.IsCancellationRequested)) { throw; } throw new WebSocketException(WebSocketError.Faulted, SR.net_webstatus_ConnectFailure, exc); } finally { // Disposing the handler will not affect any active stream wrapped in the WebSocket. if (disposeHandler) { handler?.Dispose(); } } }
public Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) => _webSocket.ConnectAsync(uri, cancellationToken, options);
public Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { // TODO: Implement this to connect and set WebSocket to a working instance. return(Task.FromException(new PlatformNotSupportedException())); }
private static SocketsHttpHandler SetupHandler(ClientWebSocketOptions options, out bool disposeHandler) { SocketsHttpHandler?handler; // Create the handler for this request and populate it with all of the options. // Try to use a shared handler rather than creating a new one just for this request, if // the options are compatible. if (options.Credentials == null && !options.UseDefaultCredentials && options.Proxy == null && options.Cookies == null && options.RemoteCertificateValidationCallback == null && (options._clientCertificates?.Count ?? 0) == 0) { disposeHandler = false; handler = s_defaultHandler; if (handler == null) { handler = new SocketsHttpHandler() { PooledConnectionLifetime = TimeSpan.Zero, UseProxy = false, UseCookies = false, }; if (Interlocked.CompareExchange(ref s_defaultHandler, handler, null) != null) { handler.Dispose(); handler = s_defaultHandler; } } } else { disposeHandler = true; handler = new SocketsHttpHandler(); handler.PooledConnectionLifetime = TimeSpan.Zero; handler.CookieContainer = options.Cookies; handler.UseCookies = options.Cookies != null; handler.SslOptions.RemoteCertificateValidationCallback = options.RemoteCertificateValidationCallback; handler.Credentials = options.UseDefaultCredentials ? CredentialCache.DefaultCredentials : options.Credentials; if (options.Proxy == null) { handler.UseProxy = false; } else if (options.Proxy != DefaultWebProxy.Instance) { handler.Proxy = options.Proxy; } if (options._clientCertificates?.Count > 0) // use field to avoid lazily initializing the collection { Debug.Assert(handler.SslOptions.ClientCertificates == null); handler.SslOptions.ClientCertificates = new X509Certificate2Collection(); handler.SslOptions.ClientCertificates.AddRange(options.ClientCertificates); } } return(handler); }
public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { _operation.InterlockedCheckAndUpdateState(WebSocketState.Connecting, s_validConnectStates); using (CancellationTokenRegistration ctr = ThrowOrRegisterCancellation(cancellationToken)) { lock (_operation.Lock) { _operation.CheckValidState(s_validConnectingStates); // Must grab lock until RequestHandle is populated, otherwise we risk resource leaks on Abort. // // TODO (Issue 2506): Alternatively, release the lock between WinHTTP operations and check, under lock, that the // state is still valid to continue operation. _operation.SessionHandle = InitializeWinHttp(options); _operation.ConnectionHandle = Interop.WinHttp.WinHttpConnectWithCallback( _operation.SessionHandle, uri.IdnHost, (ushort)uri.Port, 0); ThrowOnInvalidHandle(_operation.ConnectionHandle); bool secureConnection = uri.Scheme == UriScheme.Https || uri.Scheme == UriScheme.Wss; _operation.RequestHandle = Interop.WinHttp.WinHttpOpenRequestWithCallback( _operation.ConnectionHandle, "GET", uri.PathAndQuery, null, Interop.WinHttp.WINHTTP_NO_REFERER, null, secureConnection ? Interop.WinHttp.WINHTTP_FLAG_SECURE : 0); ThrowOnInvalidHandle(_operation.RequestHandle); _operation.IncrementHandlesOpenWithCallback(); if (!Interop.WinHttp.WinHttpSetOption( _operation.RequestHandle, Interop.WinHttp.WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, IntPtr.Zero, 0)) { WinHttpException.ThrowExceptionUsingLastError(); } // We need the address of the IntPtr to the GCHandle. IntPtr context = _operation.ToIntPtr(); IntPtr contextAddress; unsafe { contextAddress = (IntPtr)(void *)&context; } if (!Interop.WinHttp.WinHttpSetOption( _operation.RequestHandle, Interop.WinHttp.WINHTTP_OPTION_CONTEXT_VALUE, contextAddress, (uint)IntPtr.Size)) { WinHttpException.ThrowExceptionUsingLastError(); } const uint notificationFlags = Interop.WinHttp.WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS | Interop.WinHttp.WINHTTP_CALLBACK_FLAG_HANDLES | Interop.WinHttp.WINHTTP_CALLBACK_FLAG_SECURE_FAILURE; if (Interop.WinHttp.WinHttpSetStatusCallback( _operation.RequestHandle, WinHttpWebSocketCallback.s_StaticCallbackDelegate, notificationFlags, IntPtr.Zero) == (IntPtr)Interop.WinHttp.WINHTTP_INVALID_STATUS_CALLBACK) { WinHttpException.ThrowExceptionUsingLastError(); } _operation.RequestHandle.AttachCallback(); // We need to pin the operation object at this point in time since the WinHTTP callback // has been fully wired to the request handle and the operation object has been set as // the context value of the callback. Any notifications from activity on the handle will // result in the callback being called with the context value. _operation.Pin(); AddRequestHeaders(uri, options); _operation.TcsUpgrade = new TaskCompletionSource <bool>(); } await InternalSendWsUpgradeRequestAsync().ConfigureAwait(false); await InternalReceiveWsUpgradeResponse().ConfigureAwait(false); lock (_operation.Lock) { VerifyUpgradeResponse(); ThrowOnInvalidConnectState(); _operation.WebSocketHandle = Interop.WinHttp.WinHttpWebSocketCompleteUpgrade(_operation.RequestHandle, IntPtr.Zero); ThrowOnInvalidHandle(_operation.WebSocketHandle); _operation.IncrementHandlesOpenWithCallback(); // We need the address of the IntPtr to the GCHandle. IntPtr context = _operation.ToIntPtr(); IntPtr contextAddress; unsafe { contextAddress = (IntPtr)(void *)&context; } if (!Interop.WinHttp.WinHttpSetOption( _operation.WebSocketHandle, Interop.WinHttp.WINHTTP_OPTION_CONTEXT_VALUE, contextAddress, (uint)IntPtr.Size)) { WinHttpException.ThrowExceptionUsingLastError(); } _operation.WebSocketHandle.AttachCallback(); _operation.UpdateState(WebSocketState.Open); if (_operation.RequestHandle != null) { _operation.RequestHandle.Dispose(); // RequestHandle will be set to null in the callback. } _operation.TcsUpgrade = null; ctr.Dispose(); } } }
public async Task ConnectAsync(Uri uri, HttpMessageInvoker?invoker, CancellationToken cancellationToken, ClientWebSocketOptions options) { bool disposeHandler = false; invoker ??= new HttpMessageInvoker(SetupHandler(options, out disposeHandler)); HttpResponseMessage?response = null; bool disposeResponse = false; bool tryDowngrade = false; try { while (true) { try { HttpRequestMessage request; if (!tryDowngrade && options.HttpVersion >= HttpVersion.Version20 || (options.HttpVersion == HttpVersion.Version11 && options.HttpVersionPolicy == HttpVersionPolicy.RequestVersionOrHigher)) { if (options.HttpVersion > HttpVersion.Version20 && options.HttpVersionPolicy != HttpVersionPolicy.RequestVersionOrLower) { throw new WebSocketException(WebSocketError.UnsupportedProtocol); } request = new HttpRequestMessage(HttpMethod.Connect, uri) { Version = HttpVersion.Version20 }; tryDowngrade = true; } else if (tryDowngrade || options.HttpVersion == HttpVersion.Version11) { request = new HttpRequestMessage(HttpMethod.Get, uri) { Version = HttpVersion.Version11 }; tryDowngrade = false; } else { throw new WebSocketException(WebSocketError.UnsupportedProtocol); } if (options._requestHeaders?.Count > 0) // use field to avoid lazily initializing the collection { foreach (string key in options.RequestHeaders) { request.Headers.TryAddWithoutValidation(key, options.RequestHeaders[key]); } } string?secValue = AddWebSocketHeaders(request, options); // Issue the request. CancellationTokenSource?linkedCancellation; CancellationTokenSource externalAndAbortCancellation; if (cancellationToken.CanBeCanceled) // avoid allocating linked source if external token is not cancelable { linkedCancellation = externalAndAbortCancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _abortSource.Token); } else { linkedCancellation = null; externalAndAbortCancellation = _abortSource; } using (linkedCancellation) { response = await invoker.SendAsync(request, externalAndAbortCancellation.Token).ConfigureAwait(false); externalAndAbortCancellation.Token.ThrowIfCancellationRequested(); // poll in case sends/receives in request/response didn't observe cancellation } ValidateResponse(response, secValue, options); break; } catch (HttpRequestException ex) when ((ex.Data.Contains("SETTINGS_ENABLE_CONNECT_PROTOCOL") || ex.Data.Contains("HTTP2_ENABLED")) && tryDowngrade && (options.HttpVersion == HttpVersion.Version11 || options.HttpVersionPolicy == HttpVersionPolicy.RequestVersionOrLower)) { } } // The SecWebSocketProtocol header is optional. We should only get it with a non-empty value if we requested subprotocols, // and then it must only be one of the ones we requested. If we got a subprotocol other than one we requested (or if we // already got one in a previous header), fail. Otherwise, track which one we got. string?subprotocol = null; if (response.Headers.TryGetValues(HttpKnownHeaderNames.SecWebSocketProtocol, out IEnumerable <string>?subprotocolEnumerableValues)) { Debug.Assert(subprotocolEnumerableValues is string[]); string[] subprotocolArray = (string[])subprotocolEnumerableValues; if (subprotocolArray.Length > 0 && !string.IsNullOrEmpty(subprotocolArray[0])) { if (options._requestedSubProtocols is not null) { foreach (string requestedProtocol in options._requestedSubProtocols) { if (requestedProtocol.Equals(subprotocolArray[0], StringComparison.OrdinalIgnoreCase)) { subprotocol = requestedProtocol; break; } } } if (subprotocol == null) { throw new WebSocketException( WebSocketError.UnsupportedProtocol, SR.Format(SR.net_WebSockets_AcceptUnsupportedProtocol, string.Join(", ", options.RequestedSubProtocols), string.Join(", ", subprotocolArray))); } } } // Because deflate options are negotiated we need a new object WebSocketDeflateOptions?negotiatedDeflateOptions = null; if (options.DangerousDeflateOptions is not null && response.Headers.TryGetValues(HttpKnownHeaderNames.SecWebSocketExtensions, out IEnumerable <string>?extensions)) { foreach (ReadOnlySpan <char> extension in extensions) { if (extension.TrimStart().StartsWith(ClientWebSocketDeflateConstants.Extension)) { negotiatedDeflateOptions = ParseDeflateOptions(extension, options.DangerousDeflateOptions); break; } } } // Get the response stream and wrap it in a web socket. Stream connectedStream = response.Content.ReadAsStream(); Debug.Assert(connectedStream.CanWrite); Debug.Assert(connectedStream.CanRead); WebSocket = WebSocket.CreateFromStream(connectedStream, new WebSocketCreationOptions { IsServer = false, SubProtocol = subprotocol, KeepAliveInterval = options.KeepAliveInterval, DangerousDeflateOptions = negotiatedDeflateOptions }); _negotiatedDeflateOptions = negotiatedDeflateOptions; } catch (Exception exc) { if (_state < WebSocketState.Closed) { _state = WebSocketState.Closed; } Abort(); disposeResponse = true; if (exc is WebSocketException || (exc is OperationCanceledException && cancellationToken.IsCancellationRequested)) { throw; } throw new WebSocketException(WebSocketError.Faulted, SR.net_webstatus_ConnectFailure, exc); } finally { if (response is not null) { if (options.CollectHttpResponseDetails) { HttpStatusCode = response.StatusCode; HttpResponseHeaders = new HttpResponseHeadersReadOnlyCollection(response.Headers); } if (disposeResponse) { response.Dispose(); } } // Disposing the handler will not affect any active stream wrapped in the WebSocket. if (disposeHandler) { invoker?.Dispose(); } } }
public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { // TODO: Not currently implemented: // - ClientWebSocketOptions.Credentials // - ClientWebSocketOptions.Proxy // Establish connection to the server CancellationTokenRegistration registration = cancellationToken.Register(s => ((WebSocketHandle)s).Abort(), this); try { // Connect to the remote server Socket connectedSocket = await ConnectSocketAsync(uri.Host, uri.Port, cancellationToken).ConfigureAwait(false); Stream stream = new AsyncEventArgsNetworkStream(connectedSocket); // Upgrade to SSL if needed if (uri.Scheme == UriScheme.Wss) { var sslStream = new SslStream(stream); await sslStream.AuthenticateAsClientAsync( uri.Host, options.ClientCertificates, SecurityProtocol.AllowedSecurityProtocols, checkCertificateRevocation: false).ConfigureAwait(false); stream = sslStream; } // Create the security key and expected response, then build all of the request headers KeyValuePair<string, string> secKeyAndSecWebSocketAccept = CreateSecKeyAndSecWebSocketAccept(); byte[] requestHeader = BuildRequestHeader(uri, options, secKeyAndSecWebSocketAccept.Key); // Write out the header to the connection await stream.WriteAsync(requestHeader, 0, requestHeader.Length, cancellationToken).ConfigureAwait(false); // Parse the response and store our state for the remainder of the connection string subprotocol = await ParseAndValidateConnectResponseAsync(stream, options, secKeyAndSecWebSocketAccept.Value, cancellationToken).ConfigureAwait(false); _webSocket = ManagedWebSocket.CreateFromConnectedStream(stream, false, subprotocol); // If a concurrent Abort or Dispose came in before we set _webSocket, make sure to update it appropriately if (_state == WebSocketState.Aborted) { _webSocket.Abort(); } else if (_state == WebSocketState.Closed) { _webSocket.Dispose(); } } catch (Exception exc) { if (_state < WebSocketState.Closed) { _state = WebSocketState.Closed; } Abort(); if (exc is WebSocketException) { throw; } throw new WebSocketException(SR.net_webstatus_ConnectFailure, exc); } finally { registration.Dispose(); } }
public ClientWebSocket () { options = new ClientWebSocketOptions (); state = WebSocketState.None; }
public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { InterlockedCheckAndUpdateState(WebSocketState.Connecting, s_validConnectStates); CheckValidState(s_validConnectingStates); _messageWebSocket = new MessageWebSocket(); foreach (var header in options.RequestHeaders) { _messageWebSocket.SetRequestHeader((string)header, options.RequestHeaders[(string)header]); } string cookies = options.Cookies == null ? null : options.Cookies.GetCookieHeader(uri); if (!string.IsNullOrEmpty(cookies)) { _messageWebSocket.SetRequestHeader(HeaderNameCookie, cookies); } var websocketControl = _messageWebSocket.Control; foreach (var subProtocol in options.RequestedSubProtocols) { websocketControl.SupportedProtocols.Add(subProtocol); } if (options.ClientCertificates.Count > 0) { if (!MessageWebSocketClientCertificateSupported) { throw new PlatformNotSupportedException(string.Format(CultureInfo.InvariantCulture, SR.net_WebSockets_UWPClientCertSupportRequiresWindows10GreaterThan1703)); } X509Certificate2 dotNetClientCert = CertificateHelper.GetEligibleClientCertificate(options.ClientCertificates); if (dotNetClientCert != null) { RTCertificate winRtClientCert = await CertificateHelper.ConvertDotNetClientCertToWinRtClientCertAsync(dotNetClientCert).ConfigureAwait(false); if (winRtClientCert == null) { throw new PlatformNotSupportedException(string.Format( CultureInfo.InvariantCulture, SR.net_WebSockets_UWPClientCertSupportRequiresCertInPersonalCertificateStore)); } websocketControl.ClientCertificate = winRtClientCert; } } // Try to opt into PartialMessage receive mode so that we can hand partial data back to the app as it arrives. // If the MessageWebSocketControl.ReceiveMode API surface is not available, the MessageWebSocket.MessageReceived // event will only get triggered when an entire WebSocket message has been received. This results in large memory // footprint and prevents "streaming" scenarios (e.g., WCF) from working properly. if (MessageWebSocketReceiveModeSupported) { // Always enable partial message receive mode if the WinRT API supports it. _messageWebSocket.Control.ReceiveMode = MessageWebSocketReceiveMode.PartialMessage; } try { _receiveAsyncBufferTcs = new TaskCompletionSource <ArraySegment <byte> >(); _closeWebSocketReceiveResultTcs = new TaskCompletionSource <WebSocketReceiveResult>(); _messageWebSocket.MessageReceived += OnMessageReceived; _messageWebSocket.Closed += OnCloseReceived; await _messageWebSocket.ConnectAsync(uri).AsTask(cancellationToken).ConfigureAwait(false); _subProtocol = _messageWebSocket.Information.Protocol; _messageWriter = new DataWriter(_messageWebSocket.OutputStream); } catch (Exception) { UpdateState(WebSocketState.Closed); throw; } UpdateState(WebSocketState.Open); }
public ClientWebSocket() { if (NetEventSource.IsEnabled) NetEventSource.Enter(this); WebSocketHandle.CheckPlatformSupport(); _state = (int)InternalState.Created; _options = new ClientWebSocketOptions(); if (NetEventSource.IsEnabled) NetEventSource.Exit(this); }
public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { try { await _webSocket.ConnectAsync(uri, cancellationToken, options).ConfigureAwait(false); } catch (Win32Exception ex) { var wex = new WebSocketException(SR.net_webstatus_ConnectFailure, ex); if (NetEventSource.IsEnabled) NetEventSource.Error(_webSocket, wex); throw wex; } }