internal static string GetSupportedVersion()
        {
            if (!IsSupported)
            {
                HttpWebSocket.ThrowPlatformNotSupportedException_WSPC();
            }

            SafeWebSocketHandle?webSocketHandle = null;

            try
            {
                int errorCode = Interop.WebSocket.WebSocketCreateClientHandle(null !, 0, out webSocketHandle);
                ThrowOnError(errorCode);

                if (webSocketHandle == null ||
                    webSocketHandle.IsInvalid)
                {
                    HttpWebSocket.ThrowPlatformNotSupportedException_WSPC();
                }

                IntPtr additionalHeadersPtr;
                uint   additionalHeaderCount;

                errorCode = Interop.WebSocket.WebSocketBeginClientHandshake(webSocketHandle !,
                                                                            IntPtr.Zero,
                                                                            0,
                                                                            IntPtr.Zero,
                                                                            0,
                                                                            s_initialClientRequestHeaders,
                                                                            (uint)s_initialClientRequestHeaders.Length,
                                                                            out additionalHeadersPtr,
                                                                            out additionalHeaderCount);
                ThrowOnError(errorCode);

                Interop.WebSocket.HttpHeader[] additionalHeaders = MarshalHttpHeaders(additionalHeadersPtr, (int)additionalHeaderCount);

                string?version = null;
                foreach (Interop.WebSocket.HttpHeader header in additionalHeaders)
                {
                    if (string.Equals(header.Name,
                                      HttpKnownHeaderNames.SecWebSocketVersion,
                                      StringComparison.OrdinalIgnoreCase))
                    {
                        version = header.Value;
                        break;
                    }
                }
                Debug.Assert(version != null, "'version' MUST NOT be NULL.");

                return(version);
            }
            finally
            {
                if (webSocketHandle != null)
                {
                    webSocketHandle.Dispose();
                }
            }
        }
        private async Task WriteAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Enter(this, HttpWebSocket.GetTraceMsgForParameters(offset, count, cancellationToken));
            }

            CancellationTokenRegistration cancellationTokenRegistration = default;

            try
            {
                if (cancellationToken.CanBeCanceled)
                {
                    cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false);
                }

                if (!_inOpaqueMode)
                {
                    await _outputStream.WriteAsync(buffer, offset, count, cancellationToken).SuppressContextFlow();
                }
                else
                {
#if DEBUG
                    // When using fast path only one outstanding read is permitted. By switching into opaque mode
                    // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition)
                    // caller takes responsibility for enforcing this constraint.
                    Debug.Assert(Interlocked.Increment(ref _outstandingOperations._writes) == 1,
                                 "Only one outstanding write allowed at any given time.");
#endif
                    _writeTaskCompletionSource = new TaskCompletionSource <object>();
                    _writeEventArgs.BufferList = null;
                    _writeEventArgs.SetBuffer(buffer, offset, count);
                    if (WriteAsyncFast(_writeEventArgs))
                    {
                        await _writeTaskCompletionSource.Task.SuppressContextFlow();
                    }
                }
            }
            catch (Exception error)
            {
                if (s_CanHandleException(error))
                {
                    cancellationToken.ThrowIfCancellationRequested();
                }

                throw;
            }
            finally
            {
                cancellationTokenRegistration.Dispose();

                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Exit(this);
                }
            }
        }
示例#3
0
        internal static void WebSocketCreateServerHandle(Interop.WebSocket.Property[] properties,
                                                         int propertyCount,
                                                         out SafeWebSocketHandle webSocketHandle)
        {
            Debug.Assert(propertyCount >= 0, "'propertyCount' MUST NOT be negative.");
            Debug.Assert((properties == null && propertyCount == 0) ||
                         (properties != null && propertyCount == properties.Length),
                         "'propertyCount' MUST MATCH 'properties.Length'.");

            if (!IsSupported)
            {
                HttpWebSocket.ThrowPlatformNotSupportedException_WSPC();
            }

            int errorCode = Interop.WebSocket.WebSocketCreateServerHandle(properties, (uint)propertyCount, out webSocketHandle);

            ThrowOnError(errorCode);

            if (webSocketHandle == null ||
                webSocketHandle.IsInvalid)
            {
                HttpWebSocket.ThrowPlatformNotSupportedException_WSPC();
            }

            IntPtr responseHeadersPtr;
            uint   responseHeaderCount;

            // Currently the WSPC doesn't allow to initiate a data session
            // without also being involved in the http handshake
            // There is no information whatsoever, which is needed by the
            // WSPC for parsing WebSocket frames from the HTTP handshake
            // In the managed implementation the HTTP header handling
            // will be done using the managed HTTP stack and we will
            // just fake an HTTP handshake for the WSPC calling
            // WebSocketBeginServerHandshake and WebSocketEndServerHandshake
            // with statically defined dummy headers.
            errorCode = Interop.WebSocket.WebSocketBeginServerHandshake(webSocketHandle,
                                                                        IntPtr.Zero,
                                                                        IntPtr.Zero,
                                                                        0,
                                                                        s_ServerFakeRequestHeaders,
                                                                        (uint)s_ServerFakeRequestHeaders.Length,
                                                                        out responseHeadersPtr,
                                                                        out responseHeaderCount);

            ThrowOnError(errorCode);

            Interop.WebSocket.HttpHeader[] responseHeaders = MarshalHttpHeaders(responseHeadersPtr, (int)responseHeaderCount);
            errorCode = Interop.WebSocket.WebSocketEndServerHandshake(webSocketHandle);

            ThrowOnError(errorCode);

            Debug.Assert(webSocketHandle != null, "'webSocketHandle' MUST NOT be NULL at this point.");
        }
示例#4
0
        internal static SafeWebSocketHandle WebSocketCreateServerHandle(Interop.WebSocket.Property[] properties, int propertyCount)
        {
            Debug.Assert(propertyCount >= 0, "'propertyCount' MUST NOT be negative.");
            Debug.Assert((properties == null && propertyCount == 0) ||
                         (properties != null && propertyCount == properties.Length),
                         "'propertyCount' MUST MATCH 'properties.Length'.");

            if (!IsSupported)
            {
                HttpWebSocket.ThrowPlatformNotSupportedException_WSPC();
            }

            SafeWebSocketHandle?webSocketHandle = null;

            try
            {
                int errorCode = Interop.WebSocket.WebSocketCreateServerHandle(properties !, (uint)propertyCount, out webSocketHandle);
                ThrowOnError(errorCode);
                if (webSocketHandle.IsInvalid)
                {
                    HttpWebSocket.ThrowPlatformNotSupportedException_WSPC();
                }

                // Currently the WSPC doesn't allow to initiate a data session
                // without also being involved in the http handshake
                // There is no information whatsoever, which is needed by the
                // WSPC for parsing WebSocket frames from the HTTP handshake
                // In the managed implementation the HTTP header handling
                // will be done using the managed HTTP stack and we will
                // just fake an HTTP handshake for the WSPC calling
                // WebSocketBeginServerHandshake and WebSocketEndServerHandshake
                // with statically defined dummy headers.
                errorCode = Interop.WebSocket.WebSocketBeginServerHandshake(webSocketHandle,
                                                                            IntPtr.Zero,
                                                                            IntPtr.Zero,
                                                                            0,
                                                                            s_ServerFakeRequestHeaders !,
                                                                            (uint)s_ServerFakeRequestHeaders !.Length,
                                                                            out _,
                                                                            out _);
                ThrowOnError(errorCode);

                errorCode = Interop.WebSocket.WebSocketEndServerHandshake(webSocketHandle);
                ThrowOnError(errorCode);
            }
            catch
            {
                webSocketHandle?.Dispose();
                throw;
            }

            return(webSocketHandle);
        }
示例#5
0
        public ServerWebSocket(Stream innerStream,
                               string subProtocol,
                               int receiveBufferSize,
                               TimeSpan keepAliveInterval,
                               ArraySegment <byte> internalBuffer)
            : base(innerStream, subProtocol, keepAliveInterval,
                   WebSocketBuffer.CreateServerBuffer(internalBuffer, receiveBufferSize))
        {
            _properties    = InternalBuffer.CreateProperties(false);
            _sessionHandle = CreateWebSocketHandle();

            if (_sessionHandle == null || _sessionHandle.IsInvalid)
            {
                HttpWebSocket.ThrowPlatformNotSupportedException_WSPC();
            }

            StartKeepAliveTimer();
        }
示例#6
0
        internal static WebSocket Create(Stream innerStream,
                                         string subProtocol,
                                         int receiveBufferSize,
                                         TimeSpan keepAliveInterval,
                                         ArraySegment <byte> internalBuffer)
        {
            if (!WebSocketProtocolComponent.IsSupported)
            {
                HttpWebSocket.ThrowPlatformNotSupportedException_WSPC();
            }

            HttpWebSocket.ValidateInnerStream(innerStream);
            HttpWebSocket.ValidateOptions(subProtocol, receiveBufferSize, HttpWebSocket.MinSendBufferSize, keepAliveInterval);
            WebSocketValidate.ValidateArraySegment(internalBuffer, nameof(internalBuffer));
            WebSocketBuffer.Validate(internalBuffer.Count, receiveBufferSize, HttpWebSocket.MinSendBufferSize, true);

            return(new ServerWebSocket(innerStream,
                                       subProtocol,
                                       receiveBufferSize,
                                       keepAliveInterval,
                                       internalBuffer));
        }
        internal static async Task <HttpListenerWebSocketContext> AcceptWebSocketAsyncCore(HttpListenerContext context,
                                                                                           string subProtocol,
                                                                                           int receiveBufferSize,
                                                                                           TimeSpan keepAliveInterval,
                                                                                           ArraySegment <byte>?internalBuffer = null)
        {
            ValidateOptions(subProtocol, receiveBufferSize, MinSendBufferSize, keepAliveInterval);

            // get property will create a new response if one doesn't exist.
            HttpListenerResponse response = context.Response;
            HttpListenerRequest  request  = context.Request;

            ValidateWebSocketHeaders(context);

            string secWebSocketVersion = request.Headers[HttpKnownHeaderNames.SecWebSocketVersion];

            // Optional for non-browser client
            string origin = request.Headers[HttpKnownHeaderNames.Origin];

            string[] secWebSocketProtocols = null;
            string   outgoingSecWebSocketProtocolString;
            bool     shouldSendSecWebSocketProtocolHeader =
                ProcessWebSocketProtocolHeader(
                    request.Headers[HttpKnownHeaderNames.SecWebSocketProtocol],
                    subProtocol,
                    out outgoingSecWebSocketProtocolString);

            if (shouldSendSecWebSocketProtocolHeader)
            {
                secWebSocketProtocols = new string[] { outgoingSecWebSocketProtocolString };
                response.Headers.Add(HttpKnownHeaderNames.SecWebSocketProtocol, outgoingSecWebSocketProtocolString);
            }

            // negotiate the websocket key return value
            string secWebSocketKey    = request.Headers[HttpKnownHeaderNames.SecWebSocketKey];
            string secWebSocketAccept = HttpWebSocket.GetSecWebSocketAcceptString(secWebSocketKey);

            response.Headers.Add(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade);
            response.Headers.Add(HttpKnownHeaderNames.Upgrade, WebSocketUpgradeToken);
            response.Headers.Add(HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept);

            response.StatusCode        = (int)HttpStatusCode.SwitchingProtocols; // HTTP 101
            response.StatusDescription = HttpStatusDescription.Get(HttpStatusCode.SwitchingProtocols);

            HttpResponseStream responseStream = response.OutputStream as HttpResponseStream;

            // Send websocket handshake headers
            await responseStream.WriteWebSocketHandshakeHeadersAsync().ConfigureAwait(false);

            WebSocket webSocket = WebSocket.CreateFromStream(context.Connection.ConnectedStream, isServer: true, subProtocol, keepAliveInterval);

            HttpListenerWebSocketContext webSocketContext = new HttpListenerWebSocketContext(
                request.Url,
                request.Headers,
                request.Cookies,
                context.User,
                request.IsAuthenticated,
                request.IsLocal,
                request.IsSecureConnection,
                origin,
                secWebSocketProtocols != null ? secWebSocketProtocols : Array.Empty <string>(),
                secWebSocketVersion,
                secWebSocketKey,
                webSocket);

            return(webSocketContext);
        }
示例#8
0
        private static async Task <HttpListenerWebSocketContext> AcceptWebSocketAsyncCore(HttpListenerContext context,
                                                                                          string subProtocol,
                                                                                          int receiveBufferSize,
                                                                                          TimeSpan keepAliveInterval,
                                                                                          ArraySegment <byte> internalBuffer)
        {
            HttpListenerWebSocketContext webSocketContext = null;

            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Enter(null, context);
            }

            try
            {
                // get property will create a new response if one doesn't exist.
                HttpListenerResponse response = context.Response;
                HttpListenerRequest  request  = context.Request;
                ValidateWebSocketHeaders(context);

                string secWebSocketVersion = request.Headers[HttpKnownHeaderNames.SecWebSocketVersion];

                // Optional for non-browser client
                string origin = request.Headers[HttpKnownHeaderNames.Origin];

                List <string> secWebSocketProtocols = new List <string>();
                string        outgoingSecWebSocketProtocolString;
                bool          shouldSendSecWebSocketProtocolHeader =
                    ProcessWebSocketProtocolHeader(
                        request.Headers[HttpKnownHeaderNames.SecWebSocketProtocol],
                        subProtocol,
                        out outgoingSecWebSocketProtocolString);

                if (shouldSendSecWebSocketProtocolHeader)
                {
                    secWebSocketProtocols.Add(outgoingSecWebSocketProtocolString);
                    response.Headers.Add(HttpKnownHeaderNames.SecWebSocketProtocol,
                                         outgoingSecWebSocketProtocolString);
                }

                // negotiate the websocket key return value
                string secWebSocketKey    = request.Headers[HttpKnownHeaderNames.SecWebSocketKey];
                string secWebSocketAccept = HttpWebSocket.GetSecWebSocketAcceptString(secWebSocketKey);

                response.Headers.Add(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade);
                response.Headers.Add(HttpKnownHeaderNames.Upgrade, WebSocketUpgradeToken);
                response.Headers.Add(HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept);

                response.StatusCode = (int)HttpStatusCode.SwitchingProtocols; // HTTP 101
                response.ComputeCoreHeaders();
                ulong hresult = SendWebSocketHeaders(response);
                if (hresult != 0)
                {
                    throw new WebSocketException((int)hresult,
                                                 SR.Format(SR.net_WebSockets_NativeSendResponseHeaders,
                                                           nameof(AcceptWebSocketAsync),
                                                           hresult));
                }

                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Info(null, $"{HttpKnownHeaderNames.Origin} = {origin}");
                    NetEventSource.Info(null, $"{HttpKnownHeaderNames.SecWebSocketVersion} = {secWebSocketVersion}");
                    NetEventSource.Info(null, $"{HttpKnownHeaderNames.SecWebSocketKey} = {secWebSocketKey}");
                    NetEventSource.Info(null, $"{HttpKnownHeaderNames.SecWebSocketAccept} = {secWebSocketAccept}");
                    NetEventSource.Info(null, $"{HttpKnownHeaderNames.SecWebSocketProtocol} = {request.Headers[HttpKnownHeaderNames.SecWebSocketProtocol]}");
                    NetEventSource.Info(null, $"{HttpKnownHeaderNames.SecWebSocketProtocol} = {outgoingSecWebSocketProtocolString}");
                }

                await response.OutputStream.FlushAsync().SuppressContextFlow();

                HttpResponseStream responseStream = response.OutputStream as HttpResponseStream;
                Debug.Assert(responseStream != null, "'responseStream' MUST be castable to System.Net.HttpResponseStream.");
                ((HttpResponseStream)response.OutputStream).SwitchToOpaqueMode();
                HttpRequestStream requestStream = new HttpRequestStream(context);
                requestStream.SwitchToOpaqueMode();
                WebSocketHttpListenerDuplexStream webSocketStream =
                    new WebSocketHttpListenerDuplexStream(requestStream, responseStream, context);
                WebSocket webSocket = ServerWebSocket.Create(webSocketStream,
                                                             subProtocol,
                                                             receiveBufferSize,
                                                             keepAliveInterval,
                                                             internalBuffer);

                webSocketContext = new HttpListenerWebSocketContext(
                    request.Url,
                    request.Headers,
                    request.Cookies,
                    context.User,
                    request.IsAuthenticated,
                    request.IsLocal,
                    request.IsSecureConnection,
                    origin,
                    secWebSocketProtocols.AsReadOnly(),
                    secWebSocketVersion,
                    secWebSocketKey,
                    webSocket);

                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Associate(context, webSocketContext);
                    NetEventSource.Associate(webSocketContext, webSocket);
                }
            }
            catch (Exception ex)
            {
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Error(context, ex);
                }
                throw;
            }
            finally
            {
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Exit(context);
                }
            }

            return(webSocketContext);
        }