private SocksHttpWebResponse InternalGetResponse()
        {
            Uri requestUri = RequestUri;

            int       redirects            = 0;
            const int maxAutoredirectCount = 10;

            while (redirects++ < maxAutoredirectCount)
            {
                // Loop while redirecting

                var proxyUri  = Proxy.GetProxy(requestUri);
                var ipAddress = GetProxyIpAddress(proxyUri);
                var response  = new List <byte>();

                using (var client = new TcpClient(ipAddress.ToString(), proxyUri.Port))
                {
                    int timeout = Timeout;
                    if (timeout == 0)
                    {
                        timeout = 30 * 1000;
                    }
                    client.ReceiveTimeout = timeout;
                    client.SendTimeout    = timeout;
                    var networkStream = client.GetStream();
                    // auth
                    var buf = new byte[300];
                    buf[0] = 0x05; // Version
                    buf[1] = 0x01; // NMETHODS
                    buf[2] = 0x00; // No auth-method
                    networkStream.Write(buf, 0, 3);

                    networkStream.Read(buf, 0, 2);
                    if (buf[0] != 0x05)
                    {
                        throw new IOException("Invalid Socks Version");
                    }
                    if (buf[1] == 0xff)
                    {
                        throw new IOException("Socks Server does not support no-auth");
                    }
                    if (buf[1] != 0x00)
                    {
                        throw new Exception("Socks Server did choose bogus auth");
                    }

                    // connect
                    var destIP = Dns.GetHostEntry(requestUri.DnsSafeHost).AddressList[0];
                    var index  = 0;
                    buf[index++] = 0x05; // version 5 .
                    buf[index++] = 0x01; // command = connect.
                    buf[index++] = 0x00; // Reserve = must be 0x00

                    buf[index++] = 0x01; // Address is full-qualified domain name.
                    var rawBytes = destIP.GetAddressBytes();
                    rawBytes.CopyTo(buf, index);
                    index += (ushort)rawBytes.Length;

                    var portBytes = BitConverter.GetBytes(Uri.UriSchemeHttps == requestUri.Scheme ? 443 : 80);
                    for (var i = portBytes.Length - 3; i >= 0; i--)
                    {
                        buf[index++] = portBytes[i];
                    }


                    networkStream.Write(buf, 0, index);

                    networkStream.Read(buf, 0, 4);
                    if (buf[0] != 0x05)
                    {
                        throw new IOException("Invalid Socks Version");
                    }
                    if (buf[1] != 0x00)
                    {
                        throw new IOException($"Socks Error {buf[1]:X}");
                    }

                    var rdest = string.Empty;
                    switch (buf[3])
                    {
                    case 0x01:     // IPv4
                        networkStream.Read(buf, 0, 4);
                        var v4 = BitConverter.ToUInt32(buf, 0);
                        rdest = new IPAddress(v4).ToString();
                        break;

                    case 0x03:     // Domain name
                        networkStream.Read(buf, 0, 1);
                        if (buf[0] == 0xff)
                        {
                            throw new IOException("Invalid Domain Name");
                        }
                        networkStream.Read(buf, 1, buf[0]);
                        rdest = Encoding.ASCII.GetString(buf, 1, buf[0]);
                        break;

                    case 0x04:     // IPv6
                        var octets = new byte[16];
                        networkStream.Read(octets, 0, 16);
                        rdest = new IPAddress(octets).ToString();
                        break;

                    default:
                        throw new IOException("Invalid Address type");
                    }
                    networkStream.Read(buf, 0, 2);
                    var rport = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(buf, 0));

                    Stream readStream = null;
                    if (Uri.UriSchemeHttps == requestUri.Scheme)
                    {
                        var ssl = new SslStream(networkStream);
                        ssl.AuthenticateAsClient(requestUri.DnsSafeHost);
                        readStream = ssl;
                    }
                    else
                    {
                        readStream = networkStream;
                    }

                    string requestString = BuildHttpRequestMessage(requestUri);

                    var request = Encoding.ASCII.GetBytes(requestString);
                    readStream.Write(request, 0, request.Length);
                    readStream.Flush();

                    var buffer = new byte[client.ReceiveBufferSize];

                    var readlen = 0;
                    do
                    {
                        readlen = readStream.Read(buffer, 0, buffer.Length);
                        response.AddRange(buffer.Take(readlen));
                    } while (readlen != 0);

                    readStream.Close();
                }

                var webResponse = new SocksHttpWebResponse(requestUri, response.ToArray());

                if (webResponse.StatusCode == HttpStatusCode.Moved || webResponse.StatusCode == HttpStatusCode.MovedPermanently)
                {
                    string redirectUrl = webResponse.Headers["Location"];
                    if (string.IsNullOrEmpty(redirectUrl))
                    {
                        throw new WebException("Missing location for redirect");
                    }

                    requestUri = new Uri(requestUri, redirectUrl);
                    if (AllowAutoRedirect)
                    {
                        continue;
                    }
                    return(webResponse);
                }

                if ((int)webResponse.StatusCode < 200 || (int)webResponse.StatusCode > 299)
                {
                    throw new WebException(webResponse.StatusDescription, null, WebExceptionStatus.UnknownError, webResponse);
                }

                return(webResponse);
            }

            throw new WebException("Too many redirects", null, WebExceptionStatus.ProtocolError, SocksHttpWebResponse.CreateErrorResponse(HttpStatusCode.BadRequest));
        }