public async Task HandleHttp(IClient client, CancellationToken cancellationToken)
        {
            if (null == client)
            {
                return;
            }
            using (SmartBuffer clientRequest = SmartBuffer.Rent(2048))
            {
                clientRequest.SignificantLength = await client.ReadAsync(clientRequest.Memory, cancellationToken);

                if (10 >= clientRequest.SignificantLength)
                {
                    goto GOODBYE503;
                }


                if (HttpProxyHeaderResolver.TryResolve(clientRequest.SignificantMemory,
                                                       out HttpProxyHeaderResolver.Verb httpVerb, out Uri targetHost, out byte[] normalHttpRequestHeader))
                {
                    //_logger?.LogInformation($"HttpRoxyServer Verb={httpVerb.ToString()}.");
                    var server = _serverLoader.Load(null);
                    if (null == server)
                    {
                        _logger?.LogInformation($"HttpRoxyServer Proxy server not found.");
                        goto GOODBYE503;
                    }
                    var serverAddr = await server.GetIPEndPoint();

                    if (null == serverAddr)
                    {
                        _logger?.LogInformation($"HttpRoxyServer Unable to get proxy server address.");
                        goto GOODBYE503;
                    }

                    var relayClient = await TcpClient1.ConnectAsync(serverAddr, _logger); //A. connect ss-remote

                    if (null == relayClient)                                              //unable to connect ss-remote
                    {
                        _logger?.LogInformation($"HttpRoxyServer Unable to connect ss-remote:[{serverAddr.ToString()}]");
                        goto GOODBYE503;
                    }

                    using (var relayRequst = SmartBuffer.Rent(HttpProxyHeaderResolver.Verb.CONNECT == httpVerb ? 300 : normalHttpRequestHeader.Length + 300))
                    {
                        if (ShadowsocksAddress.TryParse(targetHost, out Tuple <byte, ushort, byte[]> ssaddr))//B. construct sssaddr
                        {
                            //_logger?.LogInformation($"HttpRoxyServer ATYP={ssaddr.Item1}, port={ssaddr.Item2}");
                            ShadowsocksAddress.TrySerailizeTo(ssaddr.Item1, ssaddr.Item3, ssaddr.Item2, relayRequst.Memory, out int written);
                            relayRequst.SignificantLength = written;

                            if (HttpProxyHeaderResolver.Verb.CONNECT != httpVerb)
                            {
                                normalHttpRequestHeader.CopyTo(relayRequst.FreeMemory);
                                relayRequst.SignificantLength += normalHttpRequestHeader.Length;
                            }

                            var                    cipher       = server.CreateCipher(_logger);
                            DefaultPipe            pipe         = new DefaultPipe(client, relayClient, Defaults.ReceiveBufferSize, _logger);
                            Cipher.TcpCipherFilter cipherFilter = new Cipher.TcpCipherFilter(relayClient, cipher, _logger);
                            pipe.ApplyClientFilter(cipherFilter);

                            var writeResult = await pipe.Writer[relayClient].Write(relayRequst.SignificantMemory, cancellationToken);//C. send target addr (& http header) to ss-remote.
                            _logger?.LogInformation($"Send target addr {writeResult.Written} bytes. {writeResult.Result}.");

                            if (HttpProxyHeaderResolver.Verb.CONNECT == httpVerb)
                            {
                                await client.WriteAsync(RESPONSE_200_Connection_Established, cancellationToken);
                            }
                            PipeClient(pipe, cancellationToken);//D. start piping.

                            return;
                        }
                        else
                        {
                            _logger?.LogInformation($"HttpRoxyServer parse host URL failed."); goto GOODBYE503;
                        }
                    }
                }
        public async Task HandleTcp(IClient client, CancellationToken cancellationToken)
        {
            if (null == client)
            {
                return;
            }
            if (!await Handshake(client, cancellationToken))
            {
                return;
            }                                                            //Handshake
            using (SmartBuffer request = SmartBuffer.Rent(300), response = SmartBuffer.Rent(300))
            {
                request.SignificantLength = await client.ReadAsync(request.Memory, cancellationToken);

                if (5 >= request.SignificantLength)
                {
                    client.Close(); return;
                }
                #region socks5

                /*
                 +----+-----+-------+------+----------+----------+
                 |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
                 +----+-----+-------+------+----------+----------+
                 | 1  |  1  | X'00' |  1   | Variable |    2     |
                 +----+-----+-------+------+----------+----------+
                 |
                 | Where:
                 |
                 |    o  VER    protocol version: X'05'
                 |    o  CMD
                 |       o  CONNECT X'01'
                 |       o  BIND X'02'
                 |       o  UDP ASSOCIATE X'03'
                 |    o  RSV    RESERVED
                 |    o  ATYP   address type of following address
                 |       o  IP V4 address: X'01'
                 |       o  DOMAINNAME: X'03'
                 |       o  IP V6 address: X'04'
                 |    o  DST.ADDR       desired destination address
                 |    o  DST.PORT desired destination port in network octet
                 |       order
                 |
                 |
                 +----+-----+-------+------+----------+----------+
                 |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
                 +----+-----+-------+------+----------+----------+
                 | 1  |  1  | X'00' |  1   | Variable |    2     |
                 +----+-----+-------+------+----------+----------+
                 |
                 | Where:
                 |
                 |    o  VER    protocol version: X'05'
                 |    o  REP    Reply field:
                 |       o  X'00' succeeded
                 |       o  X'01' general SOCKS server failure
                 |       o  X'02' connection not allowed by ruleset
                 |       o  X'03' Network unreachable
                 |       o  X'04' Host unreachable
                 |       o  X'05' Connection refused
                 |       o  X'06' TTL expired
                 |       o  X'07' Command not supported
                 |       o  X'08' Address type not supported
                 |       o  X'09' to X'FF' unassigned
                 |    o  RSV    RESERVED
                 |    o  ATYP   address type of following address
                 |       o  IP V4 address: X'01'
                 |       o  DOMAINNAME: X'03'
                 |       o  IP V6 address: X'04'
                 |    o  BND.ADDR       server bound address
                 |    o  BND.PORT       server bound port in network octet order
                 */

                #endregion

                switch (request.Memory.Span[1])
                {
                case 0x1:    //connect //TODO validate addr
                {
                    var server = _serverLoader.Load(null);
                    if (null == server)
                    {
                        _logger?.LogInformation($"proxy server not found.");
                        client.Close();
                        break;
                    }
                    var serverAddr = await server.GetIPEndPoint();

                    if (null == serverAddr)
                    {
                        _logger?.LogInformation($"unable to get proxy server address.");
                        client.Close();
                        break;
                    }

                    var relayClient = await TcpClient1.ConnectAsync(serverAddr, _logger); //A. connect ss-remote

                    if (null == relayClient)                                              //unable to connect ss-remote
                    {
                        _logger?.LogInformation($"unable to connect ss-remote:[{serverAddr.ToString()}]");
                        await client.WriteAsync(NegotiationResponse.CommandConnectFailed, cancellationToken);

                        client.Close();
                        break;
                    }

                    var clientRequest = request;
                    if (ShadowsocksAddress.TryResolve(clientRequest.Memory.Slice(3), out ShadowsocksAddress ssaddr))        //B.resove target addr.
                    {
                        var cipher = server.CreateCipher(_logger);

                        DuplexPipe    pipe         = new DuplexPipe(client, relayClient, Defaults.ReceiveBufferSize, _logger);
                        IClientFilter cipherFilter = new Cipher.TcpCipherFilter(cipher, _logger);
                        pipe.AddFilter(relayClient, cipherFilter);

                        var writeResult = await pipe.GetWriter(relayClient).Write(ssaddr.RawMemory, cancellationToken);        //C. send target addr to ss-remote.

                        _logger?.LogInformation($"Send target addr {writeResult.Written} bytes. {writeResult.Result}.");

                        await client.WriteAsync(NegotiationResponse.CommandConnectOK, cancellationToken); //D. notify client to send data.

                        PipeClient(pipe, cancellationToken);                                              //E. start piping.
                    }
                    else
                    {
                        _logger?.LogWarning("resolve target addr failed.");
                        client.Close();
                    }
                }
                break;

                case 0x2:    //bind
                {
                    request.SignificantMemory.CopyTo(response.Memory);
                    response.Memory.Span[1] = 0x7;
                    await client.WriteAsync(response.Memory.Slice(0, request.SignificantLength), cancellationToken);

                    client.Close();
                }
                break;

                case 0x3:    //udp assoc
                {
                    if (ShadowsocksAddress.TrySerailizeTo(
                            (byte)(AddressFamily.InterNetworkV6 == client.LocalEndPoint.AddressFamily ? 0x4 : 0x1),
                            client.LocalEndPoint.Address.GetAddressBytes(),
                            (ushort)client.LocalEndPoint.Port,
                            response.Memory,
                            out int written))
                    {
                        response.SignificantLength = written;
                        await client.WriteAsync(response.SignificantMemory, cancellationToken);
                    }

                    //TODO
                    client.Closing += this.Client_Closing;
                }
                break;

                default:
                    break;
                }
            }
        }