internal Task HandleClient()
        {
            _remoteEndPoint = _client.Client.RemoteEndPoint;
            _logger.LogDebug($"Start client socket on port {_remoteEndPoint}");

            var session = Guid.NewGuid().ToString();

            _connectionSession = _middleware.GetSession(session);

            _connectionSession.Client = _client;

            _client.ReceiveTimeout = 0;
            try
            {
                using (var networkStream = _client.GetStream())
                {
                    byte[] receiveBuffer = new byte[_client.ReceiveBufferSize];

                    while (_client.Connected)
                    {
                        _logger.LogDebug("Waiting for more data from the client....");

                        // This is blocking and will wait for data to come from the client.
                        //
                        var bytesRead = networkStream.Read(receiveBuffer, 0, _client.ReceiveBufferSize);;

                        lock (_connectionSession)
                        {
                            if (bytesRead == 0)
                            {
                                _logger.LogDebug(
                                    "**************************** REQUEST RECEIVED but no data available *************************");
                                break;
                            }

                            var content = receiveBuffer.AsSpan(0, bytesRead).ToArray();

                            if (_connectionSession.IsVerified)
                            {
                                _logger.LogDebug("Already in a verified state..");

                                var encryptionResult = DecryptData(content, _connectionSession);
                                content = encryptionResult;
                            }


                            //_logger.LogTrace($"Read {Encoding.UTF8.GetString(content)}");

                            var ms = new MemoryStream(content);
                            var sr = new StreamReader(ms);

                            var request = sr.ReadLine();
                            var tokens  = request.Split(' ');
                            if (tokens.Length != 3)
                            {
                                _middleware.TerminateSession(session);
                                throw new Exception("Invalid HTTP request line");
                            }

                            var method = tokens[0].ToUpper();
                            var url    = tokens[1].Trim('/');

                            _logger.LogDebug($"Request {method} on path {url}");

                            string line;

                            Dictionary <string, string> httpHeaders = new Dictionary <string, string>();

                            while ((line = sr.ReadLine()) != null)
                            {
                                if (String.IsNullOrEmpty(line))
                                {
                                    break;
                                }

                                var lineSplit = line.Split(":", StringSplitOptions.RemoveEmptyEntries);

                                if (lineSplit.Length != 2)
                                {
                                    _logger.LogWarning($"Invalid header format in {line}");
                                    continue;
                                }

                                httpHeaders.Add(lineSplit[0].ToLower(), lineSplit[1]);
                            }


                            var contentLengthHeader =
                                httpHeaders.ContainsKey("content-length");

                            var contentLenght = 0;

                            if (contentLengthHeader)
                            {
                                contentLenght =
                                    Convert.ToInt32(
                                        httpHeaders.Single(a => a.Key == "content-length").Value);
                            }

                            var datLen = content.Length;
                            var data   = content.AsSpan(datLen - contentLenght, contentLenght).ToArray();


                            var result   = _middleware.Invoke(session, url, method, data, _session);
                            var response = GetHttpResponse("HTTP/1.1", result.Item1, result.Item2, DateTime.Now);

                            _logger.LogTrace($"Writing {Encoding.UTF8.GetString(response)}");

                            if (_connectionSession.IsVerified && !_connectionSession.SkipFirstEncryption)
                            {
                                response = EncryptData(response, _connectionSession);

                                networkStream.Write(response, 0, response.Length);
                                networkStream.Flush();
                            }
                            else
                            {
                                networkStream.Write(response, 0, response.Length);
                                networkStream.Flush();

                                if (_connectionSession.SkipFirstEncryption)
                                {
                                    _connectionSession.SkipFirstEncryption = false;
                                }
                            }


                            _logger.LogDebug(
                                "**************************** REQUEST DONE *************************");
                        }
                    }

                    _middleware.TerminateSession(session);
                    _client.Close();
                    _client.Dispose();
                    _httpServer.ConnectionClosed(this);
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Error occured in http server");
                _middleware.TerminateSession(session);
            }

            return(Task.CompletedTask);
        }
Example #2
0
        private Task HandleClient(TcpClient tcpClient, CancellationTokenSource token)
        {
            return(Task.Run(async() => {
                var session = Guid.NewGuid().ToString();
                var connectionSession = _middleware.GetSession(session);

                connectionSession.Socket = tcpClient.Client;

                tcpClient.ReceiveTimeout = TimeSpan.FromSeconds(1).Milliseconds;
                try
                {
                    using (var networkStream = tcpClient.GetStream())
                    {
                        byte[] receiveBuffer = new byte[tcpClient.ReceiveBufferSize];

                        while (true)
                        {
                            _logger.LogDebug("Waiting for more data from the client....");

                            // This is blocking and will wait for data to come from the client.
                            //
                            var bytesRead =
                                await networkStream.ReadAsync(receiveBuffer, 0, tcpClient.ReceiveBufferSize);

                            lock (connectionSession)
                            {
                                if (bytesRead == 0)
                                {
                                    _logger.LogDebug(
                                        "**************************** REQUEST RECEIVED but not data available *************************");

                                    tcpClient.Close();
                                    break;
                                }

                                var content = receiveBuffer.AsSpan(0, bytesRead).ToArray();

                                if (connectionSession.IsVerified)
                                {
                                    _logger.LogDebug("Already in a verified state..");

                                    var encryptionResult = DecryptData(content, connectionSession);
                                    content = encryptionResult;
                                }


                                _logger.LogTrace($"Read {Encoding.UTF8.GetString(content)}");

                                var ms = new MemoryStream(content);
                                var sr = new StreamReader(ms);

                                var request = sr.ReadLine();
                                var tokens = request.Split(' ');
                                if (tokens.Length != 3)
                                {
                                    _middleware.TerminateSession(session);
                                    throw new Exception("Invalid HTTP request line");
                                }

                                var method = tokens[0].ToUpper();
                                var url = tokens[1].Trim('/');
                                var version = tokens[2];

                                string line;

                                Dictionary <string, string> httpHeaders = new Dictionary <string, string>();

                                while ((line = sr.ReadLine()) != null)
                                {
                                    if (String.IsNullOrEmpty(line))
                                    {
                                        break;
                                    }

                                    var lineSplit = line.Split(":", StringSplitOptions.RemoveEmptyEntries);

                                    if (lineSplit.Length != 2)
                                    {
                                        _logger.LogWarning($"Invalid header format in {line}");
                                        continue;
                                    }

                                    httpHeaders.Add(lineSplit[0].ToLower(), lineSplit[1]);
                                }


                                var contentLengthHeader =
                                    httpHeaders.ContainsKey("content-length");

                                var contentLenght = 0;

                                if (contentLengthHeader)
                                {
                                    contentLenght =
                                        Convert.ToInt32(
                                            httpHeaders.Single(a => a.Key == "content-length").Value);
                                }

                                var datLen = content.Length;
                                var data = content.AsSpan(datLen - contentLenght, contentLenght).ToArray();


                                var result = _middleware.Invoke(session, url, method, data);
                                var response = GetHttpResponse("HTTP/1.1", result.Item1, result.Item2);

                                _logger.LogTrace($"Writing {Encoding.UTF8.GetString(response)}");

                                if (connectionSession.IsVerified && !connectionSession.SkipFirstEncryption)
                                {
                                    response = EncryptData(response, connectionSession);

                                    networkStream.Write(response, 0, response.Length);
                                    networkStream.Flush();
                                }
                                else
                                {
                                    networkStream.Write(response, 0, response.Length);
                                    networkStream.Flush();

                                    if (connectionSession.SkipFirstEncryption)
                                    {
                                        connectionSession.SkipFirstEncryption = false;
                                    }
                                }


                                _logger.LogDebug(
                                    "**************************** REQUEST DONE *************************");
                            }
                        }

                        _middleware.TerminateSession(session);
                    }
                }
                catch (Exception e)
                {
                    _middleware.TerminateSession(session);
                }
            }, token.Token));
        }