// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/websockets?view=aspnetcore-2.1
        private static async System.Threading.Tasks.Task GetTableAsync(
            Microsoft.AspNetCore.Http.HttpContext context
            , System.Net.WebSockets.WebSocket webSocket)
        {
            WebSocketTextWriter wtw = new WebSocketTextWriter(webSocket);

            byte[] buffer = new byte[1024 * 4];
            System.Net.WebSockets.WebSocketReceiveResult result = await webSocket.ReceiveAsync(
                new System.ArraySegment <byte>(buffer)
                , System.Threading.CancellationToken.None
                );


            SqlService service = (SqlService)context.RequestServices.GetService(typeof(SqlService));

            while (!result.CloseStatus.HasValue)
            {
                //string answer = @"The server received the following message: ";
                //byte[] answerBuffer = System.Text.Encoding.UTF8.GetBytes(answer);

                //await webSocket.SendAsync(
                //      new ArraySegment<byte>(answerBuffer, 0, answerBuffer.Length)
                //    , System.Net.WebSockets.WebSocketMessageType.Text
                //    , false, System.Threading.CancellationToken.None
                //);

                //wtw.WriteLine("Test 123");
                //wtw.Transmit();
                //await System.Threading.Tasks.Task.Delay(30);



                await SqlServiceJsonHelper.AnyDataReaderToJson("SELECT * FROM T_Benutzer", null, service, wtw, RenderType_t.DataTable);

                await wtw.TransmitAsync();


                //await System.Threading.Tasks.Task.Delay(3000);
                //wtw.WriteLine("Test 456");
                //wtw.Transmit();
                //await System.Threading.Tasks.Task.Delay(30);


                //using (Newtonsoft.Json.JsonTextWriter jsonWriter =
                //    new Newtonsoft.Json.JsonTextWriter(wtw))
                //{

                //}

                result = await webSocket.ReceiveAsync(
                    new System.ArraySegment <byte>(buffer)
                    , System.Threading.CancellationToken.None
                    );
            } // Whend

            await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, System.Threading.CancellationToken.None);
        } // End Task GetTableAsync
示例#2
0
        // https://docs.microsoft.com/en-us/aspnet/core/fundamentals/websockets?view=aspnetcore-2.1
        private static async System.Threading.Tasks.Task Echo(
            Microsoft.AspNetCore.Http.HttpContext context
            , System.Net.WebSockets.WebSocket webSocket)
        {
            WebSocketTextWriter wtw = new WebSocketTextWriter(webSocket);

            byte[] buffer = new byte[1024 * 4];
            System.Net.WebSockets.WebSocketReceiveResult result = await webSocket.ReceiveAsync(
                new System.ArraySegment <byte>(buffer)
                , System.Threading.CancellationToken.None
                );


            while (!result.CloseStatus.HasValue)
            {
                //string answer = @"The server received the following message: ";
                //byte[] answerBuffer = System.Text.Encoding.UTF8.GetBytes(answer);

                //await webSocket.SendAsync(
                //      new ArraySegment<byte>(answerBuffer, 0, answerBuffer.Length)
                //    , System.Net.WebSockets.WebSocketMessageType.Text
                //    , false, System.Threading.CancellationToken.None
                //);

                wtw.WriteLine("Test 123");
                await wtw.TransmitAsync();

                wtw.WriteLine("Test 456");
                await wtw.TransmitAsync();

                wtw.WriteLine("Echo: ");
                await wtw.FlushAsync();

                wtw.Write(@"The server received the following message: ");
                await wtw.FlushAsync();

                // wtw.Send(false, new byte[0]);

                await webSocket.SendAsync(
                    new System.ArraySegment <byte>(buffer, 0, result.Count)
                    , result.MessageType
                    , result.EndOfMessage
                    , System.Threading.CancellationToken.None
                    );

                result = await webSocket.ReceiveAsync(
                    new System.ArraySegment <byte>(buffer)
                    , System.Threading.CancellationToken.None
                    );
            } // Whend

            await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, System.Threading.CancellationToken.None);
        } // End Task Echo
示例#3
0
        private async Task ProcessSystemWebsocket(
            IWebSocketContext context,
            System.Net.WebSockets.WebSocket webSocket,
            CancellationToken ct)
        {
            // define a receive buffer
            var receiveBuffer = new byte[ReceiveBufferSize];

            // define a dynamic buffer that holds multi-part receptions
            var receivedMessage = new List <byte>(receiveBuffer.Length * 2);

            // poll the WebSockets connections for reception
            while (webSocket.State == System.Net.WebSockets.WebSocketState.Open)
            {
                // retrieve the result (blocking)
                var receiveResult = new WebSocketReceiveResult(await webSocket
                                                               .ReceiveAsync(new ArraySegment <byte>(receiveBuffer), ct).ConfigureAwait(false));

                if (receiveResult.MessageType == (int)System.Net.WebSockets.WebSocketMessageType.Close)
                {
                    // close the connection if requested by the client
                    await webSocket
                    .CloseAsync(System.Net.WebSockets.WebSocketCloseStatus.NormalClosure, string.Empty, ct)
                    .ConfigureAwait(false);

                    return;
                }

                var frameBytes = new byte[receiveResult.Count];
                Array.Copy(receiveBuffer, frameBytes, frameBytes.Length);
                OnFrameReceived(context, frameBytes, receiveResult);

                // add the response to the multi-part response
                receivedMessage.AddRange(frameBytes);

                if (receivedMessage.Count > _maximumMessageSize && _maximumMessageSize > 0)
                {
                    // close the connection if message exceeds max length
                    await webSocket.CloseAsync(System.Net.WebSockets.WebSocketCloseStatus.MessageTooBig,
                                               $"Message too big. Maximum is {_maximumMessageSize} bytes.",
                                               ct).ConfigureAwait(false);

                    // exit the loop; we're done
                    return;
                }

                // if we're at the end of the message, process the message
                if (!receiveResult.EndOfMessage)
                {
                    continue;
                }

                OnMessageReceived(context, receivedMessage.ToArray(), receiveResult);
                receivedMessage.Clear();
            }
        }
 public override int Read(byte[] buffer, int offset, int count)
 {
     try
     {
         var result = webSocket.ReceiveAsync(new ArraySegment <byte>(buffer, offset, count), cts.Token).Result;
         return(result.Count);
     }
     catch
     {
         cts.Cancel();
         return(0);
     }
 }
示例#5
0
        private static async System.Threading.Tasks.Task <T> DeserializeJSON <T>(
            System.Net.WebSockets.WebSocket webSocket
            , Newtonsoft.Json.JsonSerializer serializer)
        {
            T searchArguments = default(T);

            using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
            {
                byte[] buffer = new byte[1024 * 4];
                System.Net.WebSockets.WebSocketReceiveResult result = null;

                do
                {
                    result = await webSocket.ReceiveAsync(
                        new System.ArraySegment <byte>(buffer)
                        , System.Threading.CancellationToken.None
                        );

                    ms.Write(buffer, 0, result.Count);
                } while (!result.EndOfMessage);

                // string json = System.Text.Encoding.UTF8.GetString(ms.ToArray());
                // searchArguments = Newtonsoft.Json.JsonConvert.DeserializeObject<SearchArguments>(json);

                ms.Position = 0;


                using (System.IO.TextReader tr = new System.IO.StreamReader(ms, System.Text.Encoding.UTF8))
                {
                    using (Newtonsoft.Json.JsonReader jsonReader = new Newtonsoft.Json.JsonTextReader(tr))
                    {
                        try
                        {
                            searchArguments = serializer.Deserialize <T>(jsonReader);
                        }
                        catch (System.Exception ex)
                        {
                            System.Console.WriteLine(ex.Message);
                        }
                    } // End Using jsonReader
                }     // End Using tr
            }         // End Using ms

            return(searchArguments);
        } // End Task DeserializeJSON
示例#6
0
        /// <summary>
        /// Invoked when this handler is determined to be the best suited to handle the supplied connection.
        /// </summary>
        /// <param name="context">
        /// The HTTP context.
        /// </param>
        /// <returns>
        /// The handling task.
        /// </returns>
        public override async Task Handle(HttpContext context)
        {
            ClientWebSocket wsServer = null;

            System.Net.WebSockets.WebSocket wsClient = null;

            try
            {
                // First we need the URL for this connection, since it's been requested to be
                // upgraded to a websocket.

                var connFeature = context.Features.Get <IHttpRequestFeature>();

                string fullUrl = string.Empty;

                if (connFeature != null && connFeature.RawTarget != null && !string.IsNullOrEmpty(connFeature.RawTarget) && !(string.IsNullOrWhiteSpace(connFeature.RawTarget)))
                {
                    fullUrl = $"{context.Request.Scheme}://{context.Request.Host}{connFeature.RawTarget}";
                }
                else
                {
                    fullUrl = $"{context.Request.Scheme}://{context.Request.Host}{context.Request.Path}{context.Request.QueryString}";
                }

                // Need to replate the scheme with appropriate websocket scheme.
                if (fullUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase))
                {
                    fullUrl = "ws://" + fullUrl.Substring(7);
                }
                else if (fullUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
                {
                    fullUrl = "wss://" + fullUrl.Substring(8);
                }

                // Next we need to try and parse the URL as a URI, because the websocket client
                // requires this for connecting upstream.

                if (!Uri.TryCreate(fullUrl, UriKind.RelativeOrAbsolute, out Uri wsUri))
                {
                    LoggerProxy.Default.Error("Failed to parse websocket URI.");
                    return;
                }

                // Create the websocket that's going to connect to the remote server.
                wsServer = new ClientWebSocket();
                wsServer.Options.Cookies = new System.Net.CookieContainer();
                //wsServer.Options.SetBuffer((int)ushort.MaxValue * 16, (int)ushort.MaxValue * 16);

                foreach (var proto in context.WebSockets.WebSocketRequestedProtocols)
                {
                    wsServer.Options.AddSubProtocol(proto);
                }

                foreach (var hdr in context.Request.Headers)
                {
                    if (!ForbiddenWsHeaders.IsForbidden(hdr.Key))
                    {
                        try
                        {
                            wsServer.Options.SetRequestHeader(hdr.Key, hdr.Value.ToString());
                        }
                        catch (Exception hdrException)
                        {
                            LoggerProxy.Default.Error(hdrException);
                        }
                    }
                }

                foreach (var cookie in context.Request.Cookies)
                {
                    try
                    {
                        wsServer.Options.Cookies.Add(new Uri(fullUrl, UriKind.Absolute), new System.Net.Cookie(cookie.Key, System.Net.WebUtility.UrlEncode(cookie.Value)));
                    }
                    catch (Exception e)
                    {
                        LoggerProxy.Default.Error("Error while attempting to add websocket cookie.");
                        LoggerProxy.Default.Error(e);
                    }
                }

                if (context.Connection.ClientCertificate != null)
                {
                    wsServer.Options.ClientCertificates = new System.Security.Cryptography.X509Certificates.X509CertificateCollection(new[] { context.Connection.ClientCertificate.ToV2Certificate() });
                }

                // Connect the server websocket to the upstream, remote webserver.
                await wsServer.ConnectAsync(wsUri, context.RequestAborted);

                foreach (string key in wsServer.ResponseHeaders)
                {
                    if (!ForbiddenWsHeaders.IsForbidden(key))
                    {
                        try
                        {
                            var value = wsServer.ResponseHeaders[key];
                            context.Response.Headers[key] = wsServer.ResponseHeaders[key];
                        }
                        catch (Exception hdrException)
                        {
                            LoggerProxy.Default.Error(hdrException);
                        }
                    }
                }

                // Create, via acceptor, the client websocket. This is the local machine's websocket.
                wsClient = await context.WebSockets.AcceptWebSocketAsync(wsServer.SubProtocol ?? null);

                // Match the HTTP version of the client on the upstream request. We don't want to
                // transparently pass around headers that are wrong for the client's HTTP version.
                Version upstreamReqVersionMatch = null;

                Match match = s_httpVerRegex.Match(context.Request.Protocol);
                if (match != null && match.Success)
                {
                    upstreamReqVersionMatch = Version.Parse(match.Value);
                }

                var msgNfo = new HttpMessageInfo
                {
                    Url             = wsUri,
                    Method          = new HttpMethod(context.Request.Method),
                    IsEncrypted     = context.Request.IsHttps,
                    Headers         = context.Request.Headers.ToNameValueCollection(),
                    HttpVersion     = upstreamReqVersionMatch ?? new Version(1, 0),
                    MessageProtocol = MessageProtocol.WebSocket,
                    MessageType     = MessageType.Request,
                    RemoteAddress   = context.Connection.RemoteIpAddress,
                    RemotePort      = (ushort)context.Connection.RemotePort,
                    LocalAddress    = context.Connection.LocalIpAddress,
                    LocalPort       = (ushort)context.Connection.LocalPort
                };

                _configuration.NewHttpMessageHandler?.Invoke(msgNfo);

                switch (msgNfo.ProxyNextAction)
                {
                case ProxyNextAction.DropConnection:
                {
                    await wsClient.CloseAsync(System.Net.WebSockets.WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);

                    return;
                }
                }

                var serverMessageInfo = new HttpMessageInfo
                {
                    Url             = wsUri,
                    MessageId       = msgNfo.MessageId,
                    Method          = new HttpMethod(context.Request.Method),
                    IsEncrypted     = context.Request.IsHttps,
                    Headers         = context.Request.Headers.ToNameValueCollection(),
                    HttpVersion     = upstreamReqVersionMatch ?? new Version(1, 0),
                    MessageProtocol = MessageProtocol.WebSocket,
                    MessageType     = MessageType.Response,
                    RemoteAddress   = context.Connection.RemoteIpAddress,
                    RemotePort      = (ushort)context.Connection.RemotePort,
                    LocalAddress    = context.Connection.LocalIpAddress,
                    LocalPort       = (ushort)context.Connection.LocalPort
                };

                var clientMessageInfo = new HttpMessageInfo
                {
                    Url             = wsUri,
                    MessageId       = msgNfo.MessageId,
                    IsEncrypted     = context.Request.IsHttps,
                    Headers         = context.Request.Headers.ToNameValueCollection(),
                    HttpVersion     = upstreamReqVersionMatch ?? new Version(1, 0),
                    MessageProtocol = MessageProtocol.WebSocket,
                    MessageType     = MessageType.Request,
                    RemoteAddress   = context.Connection.RemoteIpAddress,
                    RemotePort      = (ushort)context.Connection.RemotePort,
                    LocalAddress    = context.Connection.LocalIpAddress,
                    LocalPort       = (ushort)context.Connection.LocalPort
                };

                bool inspect = true;

                switch (msgNfo.ProxyNextAction)
                {
                case ProxyNextAction.AllowAndIgnoreContent:
                case ProxyNextAction.AllowAndIgnoreContentAndResponse:
                {
                    inspect = false;
                }
                break;
                }

                // Spawn an async task that will poll the remote server for data in a loop, and then
                // write any data it gets to the client websocket.
                var serverTask = Task.Run(async() =>
                {
                    System.Net.WebSockets.WebSocketReceiveResult serverResult = null;
                    var serverBuffer = new byte[1024 * 4];
                    try
                    {
                        bool looping = true;

                        serverResult = await wsServer.ReceiveAsync(new ArraySegment <byte>(serverBuffer), context.RequestAborted);

                        while (looping && !serverResult.CloseStatus.HasValue && !context.RequestAborted.IsCancellationRequested)
                        {
                            if (inspect)
                            {
                                serverMessageInfo.Body = new Memory <byte>(serverBuffer, 0, serverResult.Count);

                                switch (serverResult.MessageType)
                                {
                                case System.Net.WebSockets.WebSocketMessageType.Binary:
                                    {
                                        serverMessageInfo.BodyContentType = s_octetStreamContentType;
                                    }
                                    break;

                                case System.Net.WebSockets.WebSocketMessageType.Text:
                                    {
                                        serverMessageInfo.BodyContentType = s_plainTextContentType;
                                    }
                                    break;
                                }

                                _configuration.HttpMessageWholeBodyInspectionHandler?.Invoke(serverMessageInfo);
                            }

                            switch (serverMessageInfo.ProxyNextAction)
                            {
                            case ProxyNextAction.DropConnection:
                                {
                                    looping = false;
                                }
                                break;

                            default:
                                {
                                    await wsClient.SendAsync(new ArraySegment <byte>(serverBuffer, 0, serverResult.Count), serverResult.MessageType, serverResult.EndOfMessage, context.RequestAborted);

                                    if (!wsClient.CloseStatus.HasValue)
                                    {
                                        serverResult = await wsServer.ReceiveAsync(new ArraySegment <byte>(serverBuffer), context.RequestAborted);
                                        continue;
                                    }
                                }
                                break;
                            }

                            looping = false;
                        }

                        await wsClient.CloseAsync(serverResult.CloseStatus.Value, serverResult.CloseStatusDescription, context.RequestAborted);
                    }
                    catch (Exception err)
                    {
                        LoggerProxy.Default.Error(err);
                        try
                        {
                            var closeStatus  = serverResult?.CloseStatus ?? System.Net.WebSockets.WebSocketCloseStatus.NormalClosure;
                            var closeMessage = serverResult?.CloseStatusDescription ?? string.Empty;

                            await wsClient.CloseAsync(closeStatus, closeMessage, context.RequestAborted);
                        }
                        catch { }
                    }
                });

                // Spawn an async task that will poll the local client websocket, in a loop, and then
                // write any data it gets to the remote server websocket.
                var clientTask = Task.Run(async() =>
                {
                    System.Net.WebSockets.WebSocketReceiveResult clientResult = null;
                    var clientBuffer = new byte[1024 * 4];
                    try
                    {
                        bool looping = true;

                        clientResult = await wsClient.ReceiveAsync(new ArraySegment <byte>(clientBuffer), context.RequestAborted);

                        while (looping && !clientResult.CloseStatus.HasValue && !context.RequestAborted.IsCancellationRequested)
                        {
                            if (inspect)
                            {
                                clientMessageInfo.Body = new Memory <byte>(clientBuffer, 0, clientResult.Count);

                                switch (clientResult.MessageType)
                                {
                                case System.Net.WebSockets.WebSocketMessageType.Binary:
                                    {
                                        clientMessageInfo.BodyContentType = s_octetStreamContentType;
                                    }
                                    break;

                                case System.Net.WebSockets.WebSocketMessageType.Text:
                                    {
                                        clientMessageInfo.BodyContentType = s_plainTextContentType;
                                    }
                                    break;
                                }

                                _configuration.HttpMessageWholeBodyInspectionHandler?.Invoke(clientMessageInfo);
                            }

                            switch (clientMessageInfo.ProxyNextAction)
                            {
                            case ProxyNextAction.DropConnection:
                                {
                                    looping = false;
                                }
                                break;

                            default:
                                {
                                    await wsServer.SendAsync(new ArraySegment <byte>(clientBuffer, 0, clientResult.Count), clientResult.MessageType, clientResult.EndOfMessage, context.RequestAborted);

                                    if (!wsServer.CloseStatus.HasValue)
                                    {
                                        clientResult = await wsClient.ReceiveAsync(new ArraySegment <byte>(clientBuffer), context.RequestAborted);
                                        continue;
                                    }
                                }
                                break;
                            }

                            looping = false;
                        }

                        await wsServer.CloseAsync(clientResult.CloseStatus.Value, clientResult.CloseStatusDescription, context.RequestAborted);
                    }
                    catch (Exception err)
                    {
                        LoggerProxy.Default.Error(err);
                        try
                        {
                            var closeStatus  = clientResult?.CloseStatus ?? System.Net.WebSockets.WebSocketCloseStatus.NormalClosure;
                            var closeMessage = clientResult?.CloseStatusDescription ?? string.Empty;

                            await wsServer.CloseAsync(closeStatus, closeMessage, context.RequestAborted);
                        }
                        catch { }
                    }
                });

                // Above, we have created a bridge between the local and remote websocket. Wait for
                // both associated tasks to complete.
                await Task.WhenAll(serverTask, clientTask);
            }
            catch (Exception wshe)
            {
                LoggerProxy.Default.Error(wshe);
            }
            finally
            {
                if (wsClient != null)
                {
                    wsClient.Dispose();
                    wsClient = null;
                }

                if (wsServer != null)
                {
                    wsServer.Dispose();
                    wsServer = null;
                }
            }
        }
        public override async Task Handle(HttpContext context)
        {
            ClientWebSocket wsServer = null;

            System.Net.WebSockets.WebSocket wsClient = null;

            try
            {
                // First we need the URL for this connection, since it's been requested to be upgraded to
                // a websocket.
                var fullUrl = Microsoft.AspNetCore.Http.Extensions.UriHelper.GetDisplayUrl(context.Request);

                // Need to replate the scheme with appropriate websocket scheme.
                if (fullUrl.StartsWith("http://"))
                {
                    fullUrl = "ws://" + fullUrl.Substring(7);
                }
                else if (fullUrl.StartsWith("https://"))
                {
                    fullUrl = "wss://" + fullUrl.Substring(8);
                }

                // Next we need to try and parse the URL as a URI, because the websocket client requires
                // this for connecting upstream.

                if (!Uri.TryCreate(fullUrl, UriKind.RelativeOrAbsolute, out Uri wsUri))
                {
                    LoggerProxy.Default.Error("Failed to parse websocket URI.");
                    return;
                }

                // Create the websocket that's going to connect to the remote server.
                wsServer = new ClientWebSocket();
                wsServer.Options.Cookies = new System.Net.CookieContainer();
                wsServer.Options.SetBuffer((int)ushort.MaxValue * 16, (int)ushort.MaxValue * 16);

                foreach (var cookie in context.Request.Cookies)
                {
                    try
                    {
                        wsServer.Options.Cookies.Add(new Uri(fullUrl, UriKind.Absolute), new System.Net.Cookie(cookie.Key, System.Net.WebUtility.UrlEncode(cookie.Value)));
                    }
                    catch (Exception e)
                    {
                        LoggerProxy.Default.Error("Error while attempting to add websocket cookie.");
                        LoggerProxy.Default.Error(e);
                    }
                }

                if (context.Connection.ClientCertificate != null)
                {
                    wsServer.Options.ClientCertificates = new System.Security.Cryptography.X509Certificates.X509CertificateCollection(new[] { context.Connection.ClientCertificate.ToV2Certificate() });
                }

                var reqHeaderBuilder = new StringBuilder();
                foreach (var hdr in context.Request.Headers)
                {
                    if (!ForbiddenWsHeaders.IsForbidden(hdr.Key))
                    {
                        reqHeaderBuilder.AppendFormat("{0}: {1}\r\n", hdr.Key, hdr.Value.ToString());

                        try
                        {
                            wsServer.Options.SetRequestHeader(hdr.Key, hdr.Value.ToString());
                            Console.WriteLine("Set Header: {0} ::: {1}", hdr.Key, hdr.Value.ToString());
                        }
                        catch (Exception hdrException)
                        {
                            Console.WriteLine("Failed Header: {0} ::: {1}", hdr.Key, hdr.Value.ToString());
                            LoggerProxy.Default.Error(hdrException);
                        }
                    }
                }

                reqHeaderBuilder.Append("\r\n");

                LoggerProxy.Default.Info(string.Format("Connecting websocket to {0}", wsUri.AbsoluteUri));

                // Connect the server websocket to the upstream, remote webserver.
                await wsServer.ConnectAsync(wsUri, context.RequestAborted);

                LoggerProxy.Default.Info(String.Format("Connected websocket to {0}", wsUri.AbsoluteUri));

                // Create, via acceptor, the client websocket. This is the local machine's websocket.
                wsClient = await context.WebSockets.AcceptWebSocketAsync(wsServer.SubProtocol ?? null);

                ProxyNextAction nxtAction = ProxyNextAction.AllowAndIgnoreContentAndResponse;
                string          customResponseContentType = string.Empty;
                byte[]          customResponse            = null;
                m_msgBeginCb?.Invoke(wsUri, reqHeaderBuilder.ToString(), null, context.Request.IsHttps ? MessageType.SecureWebSocket : MessageType.WebSocket, MessageDirection.Request, out nxtAction, out customResponseContentType, out customResponse);

                switch (nxtAction)
                {
                case ProxyNextAction.DropConnection:
                {
                    if (customResponse != null)
                    {
                    }

                    await wsClient.CloseAsync(System.Net.WebSockets.WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);

                    return;
                }
                }

                // Spawn an async task that will poll the remote server for data in a loop, and then
                // write any data it gets to the client websocket.
                var serverTask = Task.Run(async() =>
                {
                    System.Net.WebSockets.WebSocketReceiveResult serverStatus = null;
                    var serverBuffer = new byte[1024 * 4];
                    try
                    {
                        bool looping = true;

                        serverStatus = await wsServer.ReceiveAsync(new ArraySegment <byte>(serverBuffer), context.RequestAborted);

                        while (looping && !serverStatus.CloseStatus.HasValue && !context.RequestAborted.IsCancellationRequested)
                        {
                            await wsClient.SendAsync(new ArraySegment <byte>(serverBuffer, 0, serverStatus.Count), serverStatus.MessageType, serverStatus.EndOfMessage, context.RequestAborted);

                            if (!wsClient.CloseStatus.HasValue)
                            {
                                serverStatus = await wsServer.ReceiveAsync(new ArraySegment <byte>(serverBuffer), context.RequestAborted);
                                continue;
                            }

                            looping = false;
                        }

                        await wsClient.CloseAsync(serverStatus.CloseStatus.Value, serverStatus.CloseStatusDescription, context.RequestAborted);
                    }
                    catch
                    {
                        try
                        {
                            var closeStatus  = serverStatus?.CloseStatus ?? System.Net.WebSockets.WebSocketCloseStatus.NormalClosure;
                            var closeMessage = serverStatus?.CloseStatusDescription ?? string.Empty;

                            await wsClient.CloseAsync(closeStatus, closeMessage, context.RequestAborted);
                        }
                        catch { }
                    }
                });

                // Spawn an async task that will poll the local client websocket, in a loop, and then
                // write any data it gets to the remote server websocket.
                var clientTask = Task.Run(async() =>
                {
                    System.Net.WebSockets.WebSocketReceiveResult clientResult = null;
                    var clientBuffer = new byte[1024 * 4];
                    try
                    {
                        bool looping = true;

                        clientResult = await wsClient.ReceiveAsync(new ArraySegment <byte>(clientBuffer), context.RequestAborted);

                        while (looping && !clientResult.CloseStatus.HasValue && !context.RequestAborted.IsCancellationRequested)
                        {
                            await wsServer.SendAsync(new ArraySegment <byte>(clientBuffer, 0, clientResult.Count), clientResult.MessageType, clientResult.EndOfMessage, context.RequestAborted);

                            if (!wsServer.CloseStatus.HasValue)
                            {
                                clientResult = await wsClient.ReceiveAsync(new ArraySegment <byte>(clientBuffer), context.RequestAborted);
                                continue;
                            }

                            looping = false;
                        }

                        await wsServer.CloseAsync(clientResult.CloseStatus.Value, clientResult.CloseStatusDescription, context.RequestAborted);
                    }
                    catch
                    {
                        try
                        {
                            var closeStatus  = clientResult?.CloseStatus ?? System.Net.WebSockets.WebSocketCloseStatus.NormalClosure;
                            var closeMessage = clientResult?.CloseStatusDescription ?? string.Empty;

                            await wsServer.CloseAsync(closeStatus, closeMessage, context.RequestAborted);
                        }
                        catch { }
                    }
                });

                // Above, we have created a bridge between the local and remote websocket. Wait for both
                // associated tasks to complete.
                await Task.WhenAll(serverTask, clientTask);
            }
            catch (Exception wshe)
            {
                if (wshe is System.Net.WebSockets.WebSocketException)
                {
                    var cast = wshe as System.Net.WebSockets.WebSocketException;

                    Console.WriteLine(cast.WebSocketErrorCode);
                    if (cast.Data != null)
                    {
                        foreach (KeyValuePair <object, object> kvp in cast.Data)
                        {
                            Console.WriteLine("{0} ::: {1}", kvp.Key, kvp.Value);
                        }
                    }
                }
                LoggerProxy.Default.Error(wshe);
            }
            finally
            {
                if (wsClient != null)
                {
                    wsClient.Dispose();
                    wsClient = null;
                }

                if (wsServer != null)
                {
                    wsServer.Dispose();
                    wsServer = null;
                }
            }
        }
示例#8
0
        public async Task Invoke(HttpContext httpContext, IHostingEnvironment hostingEnvironment)
        {
            if (httpContext.WebSockets.IsWebSocketRequest)
            {
                //升级协议,建立链接。返回代表此链接的websocket对象。
                socket = await httpContext.WebSockets.AcceptWebSocketAsync();

                var         buffer = new byte[options.ReceiveBufferSize];
                List <byte> msgArr = new List <byte>();
                //开始侦听socket,获取消息。此时可以向客户端发送消息。
                //接收到消息后,消息将传入到buffer中。
                //WebSocketResult 消息接收结果。
                //result.CloseStatus 关闭状态
                //result.CloseStatusDescription 关闭状态描述
                //result.Count 接收的消息长度
                //result.EndOfMessage 是否已经接受完毕
                //result.MessageType 消息类型 Text(文字,默认UTF-8编码),Binary(二进制),Close(关闭消息);
                var result = await socket.ReceiveAsync(new ArraySegment <byte>(buffer), CancellationToken.None);

                //当关闭状态没有值时:
                while (!result.CloseStatus.HasValue)
                {
                    msgArr.Clear();
                    //循环接收消息。
                    while (!result.EndOfMessage)
                    {
                        msgArr.AddRange(new ArraySegment <byte>(buffer, 0, result.Count));
                        result = await socket.ReceiveAsync(new ArraySegment <byte>(buffer), CancellationToken.None);
                    }
                    msgArr.AddRange(new ArraySegment <byte>(buffer, 0, result.Count));
                    switch (result.MessageType)
                    {
                    case System.Net.WebSockets.WebSocketMessageType.Binary:
                        try
                        {
                            var fileName = Path.Combine(hostingEnvironment.WebRootPath, Guid.NewGuid().ToString() + ".png");
                            using (FileStream fileStream = new FileStream(fileName, FileMode.OpenOrCreate))
                            {
                                await fileStream.WriteAsync(msgArr.ToArray(), 0, msgArr.Count());
                            }
                        }
                        catch (FileNotFoundException fileNotFound)
                        {
                            await socket.SendAsync(new ArraySegment <byte>(socketEncoding.Encode(fileNotFound.Message)), System.Net.WebSockets.WebSocketMessageType.Text, true, CancellationToken.None);
                        }
                        catch (InvalidOperationException inEx)
                        {
                            await socket.SendAsync(new ArraySegment <byte>(socketEncoding.Encode(inEx.Message)), System.Net.WebSockets.WebSocketMessageType.Text, true, CancellationToken.None);
                        }
                        catch (Exception e)
                        {
                            await socket.SendAsync(new ArraySegment <byte>(socketEncoding.Encode(e.Message)), System.Net.WebSockets.WebSocketMessageType.Text, true, CancellationToken.None);
                        }
                        break;

                    case System.Net.WebSockets.WebSocketMessageType.Close:
                        //关闭链接。
                        await socket.CloseAsync(System.Net.WebSockets.WebSocketCloseStatus.NormalClosure, "客户端关闭", CancellationToken.None);

                        break;

                    case System.Net.WebSockets.WebSocketMessageType.Text:
                        //获取客户端发送的消息。消息编码,采用UTF8
                        var message = socketEncoding.Decode(msgArr.ToArray());
                        //回显数据
                        await SendMessage("OK \t" + message);

                        break;

                    default:
                        break;
                    }
                    result = await socket.ReceiveAsync(new ArraySegment <byte>(buffer), CancellationToken.None);
                }
            }
            else
            {
                await _next(httpContext);
            }
        }
        /// <summary>
        /// Invoked when this handler is determined to be the best suited to handle the supplied connection.
        /// </summary>
        /// <param name="context">
        /// The HTTP context.
        /// </param>
        /// <returns>
        /// The handling task.
        /// </returns>
        public override async Task Handle(HttpContext context)
        {
            ClientWebSocket wsServer = null;

            System.Net.WebSockets.WebSocket wsClient = null;

            DiagnosticsWebSession diagSession = new DiagnosticsWebSession();

            try
            {
                // First we need the URL for this connection, since it's been requested to be upgraded to
                // a websocket.
                var fullUrl = Microsoft.AspNetCore.Http.Extensions.UriHelper.GetDisplayUrl(context.Request);

                // Need to replate the scheme with appropriate websocket scheme.
                if (fullUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase))
                {
                    fullUrl = "ws://" + fullUrl.Substring(7);
                }
                else if (fullUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
                {
                    fullUrl = "wss://" + fullUrl.Substring(8);
                }

                diagSession.ClientRequestUri = fullUrl;

                // Next we need to try and parse the URL as a URI, because the websocket client requires
                // this for connecting upstream.

                if (!Uri.TryCreate(fullUrl, UriKind.RelativeOrAbsolute, out Uri wsUri))
                {
                    LoggerProxy.Default.Error("Failed to parse websocket URI.");
                    return;
                }

                // Create the websocket that's going to connect to the remote server.
                wsServer = new ClientWebSocket();
                wsServer.Options.Cookies = new System.Net.CookieContainer();
                wsServer.Options.SetBuffer((int)ushort.MaxValue * 16, (int)ushort.MaxValue * 16);

                foreach (var cookie in context.Request.Cookies)
                {
                    try
                    {
                        wsServer.Options.Cookies.Add(new Uri(fullUrl, UriKind.Absolute), new System.Net.Cookie(cookie.Key, System.Net.WebUtility.UrlEncode(cookie.Value)));
                    }
                    catch (Exception e)
                    {
                        LoggerProxy.Default.Error("Error while attempting to add websocket cookie.");
                        LoggerProxy.Default.Error(e);
                    }
                }

                if (context.Connection.ClientCertificate != null)
                {
                    wsServer.Options.ClientCertificates = new System.Security.Cryptography.X509Certificates.X509CertificateCollection(new[] { context.Connection.ClientCertificate.ToV2Certificate() });
                }

                if (Collector.IsDiagnosticsEnabled)
                {
                    var diagHeaderBuilder = new StringBuilder();
                    foreach (var hdr in context.Request.Headers)
                    {
                        diagHeaderBuilder.AppendFormat($"{hdr.Key}: {hdr.Value.ToString()}\r\n");
                    }

                    diagSession.ClientRequestHeaders = diagHeaderBuilder.ToString();
                }

                var reqHeaderBuilder = new StringBuilder();
                foreach (var hdr in context.Request.Headers)
                {
                    if (!ForbiddenWsHeaders.IsForbidden(hdr.Key))
                    {
                        reqHeaderBuilder.AppendFormat("{0}: {1}\r\n", hdr.Key, hdr.Value.ToString());

                        try
                        {
                            wsServer.Options.SetRequestHeader(hdr.Key, hdr.Value.ToString());
                        }
                        catch (Exception hdrException)
                        {
                            LoggerProxy.Default.Error(hdrException);
                        }
                    }
                }

                reqHeaderBuilder.Append("\r\n");

                diagSession.ServerRequestHeaders = reqHeaderBuilder.ToString();

                // Connect the server websocket to the upstream, remote webserver.
                await wsServer.ConnectAsync(wsUri, context.RequestAborted);

                // Create, via acceptor, the client websocket. This is the local machine's websocket.
                wsClient = await context.WebSockets.AcceptWebSocketAsync(wsServer.SubProtocol ?? null);

                var msgNfo = new HttpMessageInfo
                {
                    Url             = wsUri,
                    IsEncrypted     = context.Request.IsHttps,
                    Headers         = context.Request.Headers.ToNameValueCollection(),
                    MessageProtocol = MessageProtocol.WebSocket,
                    MessageType     = MessageType.Request,
                    RemoteAddress   = context.Connection.RemoteIpAddress,
                    RemotePort      = (ushort)context.Connection.RemotePort,
                    LocalAddress    = context.Connection.LocalIpAddress,
                    LocalPort       = (ushort)context.Connection.LocalPort
                };

                _newMessageCb?.Invoke(msgNfo);

                switch (msgNfo.ProxyNextAction)
                {
                case ProxyNextAction.DropConnection:
                {
                    await wsClient.CloseAsync(System.Net.WebSockets.WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);

                    return;
                }
                }

                // Spawn an async task that will poll the remote server for data in a loop, and then
                // write any data it gets to the client websocket.
                var serverTask = Task.Run(async() =>
                {
                    System.Net.WebSockets.WebSocketReceiveResult serverStatus = null;
                    var serverBuffer = new byte[1024 * 4];
                    try
                    {
                        bool looping = true;

                        serverStatus = await wsServer.ReceiveAsync(new ArraySegment <byte>(serverBuffer), context.RequestAborted);

                        while (looping && !serverStatus.CloseStatus.HasValue && !context.RequestAborted.IsCancellationRequested)
                        {
                            await wsClient.SendAsync(new ArraySegment <byte>(serverBuffer, 0, serverStatus.Count), serverStatus.MessageType, serverStatus.EndOfMessage, context.RequestAborted);

                            if (!wsClient.CloseStatus.HasValue)
                            {
                                serverStatus = await wsServer.ReceiveAsync(new ArraySegment <byte>(serverBuffer), context.RequestAborted);
                                continue;
                            }

                            looping = false;
                        }

                        await wsClient.CloseAsync(serverStatus.CloseStatus.Value, serverStatus.CloseStatusDescription, context.RequestAborted);
                    }
                    catch
                    {
                        try
                        {
                            var closeStatus  = serverStatus?.CloseStatus ?? System.Net.WebSockets.WebSocketCloseStatus.NormalClosure;
                            var closeMessage = serverStatus?.CloseStatusDescription ?? string.Empty;

                            await wsClient.CloseAsync(closeStatus, closeMessage, context.RequestAborted);
                        }
                        catch { }
                    }
                });

                // Spawn an async task that will poll the local client websocket, in a loop, and then
                // write any data it gets to the remote server websocket.
                var clientTask = Task.Run(async() =>
                {
                    System.Net.WebSockets.WebSocketReceiveResult clientResult = null;
                    var clientBuffer = new byte[1024 * 4];
                    try
                    {
                        bool looping = true;

                        clientResult = await wsClient.ReceiveAsync(new ArraySegment <byte>(clientBuffer), context.RequestAborted);

                        while (looping && !clientResult.CloseStatus.HasValue && !context.RequestAborted.IsCancellationRequested)
                        {
                            await wsServer.SendAsync(new ArraySegment <byte>(clientBuffer, 0, clientResult.Count), clientResult.MessageType, clientResult.EndOfMessage, context.RequestAborted);

                            if (!wsServer.CloseStatus.HasValue)
                            {
                                clientResult = await wsClient.ReceiveAsync(new ArraySegment <byte>(clientBuffer), context.RequestAborted);
                                continue;
                            }

                            looping = false;
                        }

                        await wsServer.CloseAsync(clientResult.CloseStatus.Value, clientResult.CloseStatusDescription, context.RequestAborted);
                    }
                    catch
                    {
                        try
                        {
                            var closeStatus  = clientResult?.CloseStatus ?? System.Net.WebSockets.WebSocketCloseStatus.NormalClosure;
                            var closeMessage = clientResult?.CloseStatusDescription ?? string.Empty;

                            await wsServer.CloseAsync(closeStatus, closeMessage, context.RequestAborted);
                        }
                        catch { }
                    }
                });

                // Above, we have created a bridge between the local and remote websocket. Wait for both
                // associated tasks to complete.
                await Task.WhenAll(serverTask, clientTask);
            }
            catch (Exception wshe)
            {
                LoggerProxy.Default.Error(wshe);
            }
            finally
            {
                Collector.ReportSession(diagSession);

                if (wsClient != null)
                {
                    wsClient.Dispose();
                    wsClient = null;
                }

                if (wsServer != null)
                {
                    wsServer.Dispose();
                    wsServer = null;
                }
            }
        }