private async Task <HttpRequest> ReadByteFromClientSocketAndBuildRequest(Socket socketAccepted) { byte[] bufferReceive = new byte[_bufferLength]; using (var received = new MemoryStream()) { while (true) { int receiveLength = socketAccepted.Receive(bufferReceive); if (receiveLength <= 0) { break; } received.Write(bufferReceive, 0, receiveLength); if (receiveLength <= _bufferLength) { break; } } string data = Encoding.UTF8.GetString(received.ToArray()); var tempReq = await HttpTransform.BuildHttpRequest(data); return(tempReq); } }
internal static async Task <HttpRequest> DoHandShaking(TcpClient clientWssAccepted, NetworkStream clientStream, byte[] wssReceivedBytes) { string wss1stData = Encoding.UTF8.GetString(wssReceivedBytes); HttpRequest firstRequest = null; if (Regex.IsMatch(wss1stData, "^GET", RegexOptions.IgnoreCase)) { firstRequest = await HttpTransform.BuildHttpRequest(wss1stData); WebsocketServerHub.Register(firstRequest.UrlRelative, clientWssAccepted, clientStream); //do handshaking string swk = Regex.Match(wss1stData, "Sec-WebSocket-Key: (.*)").Groups[1].Value.Trim(); string swka = swk + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; byte[] swkaSha1 = System.Security.Cryptography.SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(swka)); string swkaSha1Base64 = Convert.ToBase64String(swkaSha1); byte[] response = Encoding.UTF8.GetBytes( "HTTP/1.1 101 Switching Protocols\r\n" + "Connection: Upgrade\r\n" + "Upgrade: websocket\r\n" + "Sec-WebSocket-Accept: " + swkaSha1Base64 + "\r\n\r\n"); await clientStream.WriteAsync(response, 0, response.Length); return(firstRequest); } return(firstRequest); }
async Task InternalStartAcceptIncommingAsync(TcpListener tcpListener) { //you may want to do with ssl //https://docs.microsoft.com/en-us/dotnet/api/system.net.security.sslstream?redirectedfrom=MSDN&view=netcore-3.1 while (!_isStop) { try { if (_isWss) { //https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_server TcpClient clientWssAccepted = await tcpListener.AcceptTcpClientAsync(); NetworkStream clientStream = clientWssAccepted.GetStream(); HttpRequest wss1stRequestOfHandShake = null; Task twss = Task.Run(async() => { while (!_isStop) { if (!clientWssAccepted.Client.Connected) { if (wss1stRequestOfHandShake != null) { WebsocketServerHub.Remove(wss1stRequestOfHandShake.UrlRelative); } await Shutdown(clientWssAccepted.Client, wss1stRequestOfHandShake); break; } while (!clientStream.DataAvailable) { ; } while (clientWssAccepted.Available < 3) { ; // match against "get" } byte[] wssReceivedBytes = new byte[clientWssAccepted.Available]; await clientStream.ReadAsync(wssReceivedBytes, 0, clientWssAccepted.Available); var handShakeRequest = await WebsocketServerHub.DoHandShaking(clientWssAccepted, clientStream, wssReceivedBytes); if (handShakeRequest != null) { wss1stRequestOfHandShake = handShakeRequest; } await WebsocketServerHub.ReceiveAndReplyClientMessage(clientWssAccepted, clientStream, wssReceivedBytes, wss1stRequestOfHandShake); } }); continue; } //WebHostWorker will try accept its job Socket clientSocket = await tcpListener.AcceptSocketAsync(); //parse request then dispatched by RoutingHandler var t = Task.Run(async() => { Task <HttpRequest> tRequest = ReadByteFromClientSocketAndBuildRequest(clientSocket); HttpRequest request = new HttpRequest(); request.CreatedAt = DateTime.Now; request.RemoteEndPoint = clientSocket.RemoteEndPoint.ToString(); var tempRequest = await tRequest; request.Body = tempRequest.Body; request.Error = tempRequest.Error; request.Header = tempRequest.Header; request.HeadlerCollection = tempRequest.HeadlerCollection; request.HttpVersion = tempRequest.HttpVersion; request.Method = tempRequest.Method; request.QueryParamCollection = tempRequest.QueryParamCollection; request.Url = tempRequest.Url; request.UrlRelative = tempRequest.UrlRelative; request.UrlQueryString = tempRequest.UrlQueryString; //dispatched routing here var processedResult = await RoutingHandler.Handle(request); HttpResponse response = await HttpTransform.BuildHttpResponse(processedResult, request); await SendResponseToClientSocket(clientSocket, request, response); await Shutdown(clientSocket, request); HttpLogger.Log(request); Console.WriteLine($"{request.RemoteEndPoint}@{request.CreatedAt}=>{request.Method}:{request.Url}"); }); } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(JsonConvert.SerializeObject(ex)); } finally { await Task.Delay(0); } } }