How to keep connection open when doing HTTP tunneling
Asked Answered
H

2

6

I connect to a proxy and with the connect command I send some custom headers. This is a requirement. I get a 200 response. Then I try to use the same connection to do a get request (search attached code for "GET {0}") but I always get a error that ends up "connection closed" (cant recall the exact error offhand). esssentially I need to tunnel to a websit like https:\www.somesecuresite.com Heres the code. Certain parts were excluded for breviaty.

using (TcpClient client = new TcpClient(proxy, proxyPort))
            {
                using (NetworkStream stream = client.GetStream())
                {
                    string EncodedData = encodeUIDPWD(UserName, Password);
                    #region Establish Tcp tunnel

                    string reqString = "CONNECT {0}:{1} HTTP/1.1\r\nProxy-Authorization:Basic " + EncodedData + "\r\nHost: {2}:{3}\r\n";
                    reqString += "Proxy-Connection: keep-alive\r\n";
                    reqString += "Connection: keep-alive\r\n";
                    reqString += "Header1: " + header1 + "\r\n";
                    reqString += "Header2: " + header2 + "\r\n"; 
                    reqString += "None: " + None + "\r\n\r\n";

                    string rString = String.Format(reqString, myUri.Host, myUri.Port, myUri.Host, myUri.Port);
                    #endregion
                    ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
                    string reqConnectResult = await DoRequest(myUri, stream, rString);

                    lines.AddRange(reqConnectResult.Split(new string[] { Environment.NewLine }, StringSplitOptions.None).ToList());

                    if (!lines[0].Contains("200"))
                    {
                         //Error code gets caterd for here e.g 503 etc
                    }
                    else
                    {
                        foreach (string line in lines)
                        {
                            if (line.Contains("X-ProxyMesh-IP: "))
                            {
                                ip = line.Replace("X-ProxyMesh-IP: ", string.Empty);
                            }
                        }

                        string reqString1 = "GET {0} HTTP/1.1\r\nHost: {1}:{2}\r\n";
                        reqString1 += "Proxy-Connection: keep-alive\r\n";
                        reqString1 += "Connection: keep-alive\r\n\r\n";

                        string rString1 = string.Format(reqString1, myUri.PathAndQuery, myUri.Host, myUri.Port);
                        string reqPageResult = await DoRequest(myUri, stream, rString1);


                        lines.AddRange(reqPageResult.Split(new string[] { Environment.NewLine }, StringSplitOptions.None).ToList());
                        response.Content = new StringContent(lines.ToString());

                        if (lines[0].Contains("200"))
                        { 
                            return new Tuple<bool, HttpResponseMessage>(true, response);
                        }
                        else
                        {
                            return new Tuple<bool, HttpResponseMessage>(false, response);
                        }
                    }
                }
            }

 private async Task<string> DoRequest(Uri myUri, NetworkStream stream, string reqString)
{

    byte[] tunnelRequest = Encoding.UTF8.GetBytes(reqString);

    await stream.WriteAsync(tunnelRequest, 0, tunnelRequest.Length);
    await stream.FlushAsync();


    using (var memory = new MemoryStream())
    {
        await stream.CopyToAsync(memory);

        memory.Position = 0;
        var data = memory.ToArray();

        //Basically just gets the header part.
        int bm = BinaryMatch(data, Encoding.ASCII.GetBytes("\r\n\r\n"));
        var index = bm + 4;
        if (bm == -1)
        {
            index = 0;
        }

        var headers = Encoding.ASCII.GetString(data, 0, index);
        memory.Position = index;

        Console.WriteLine(headers);
        if (headers.IndexOf("Content-Encoding: gzip") > 0)
        {
            using (GZipStream decompressionStream = new GZipStream(memory, CompressionMode.Decompress))
            using (var decompressedMemory = new MemoryStream())
            {
                decompressionStream.CopyTo(decompressedMemory);
                decompressedMemory.Position = 0;
                string s = (Encoding.UTF8.GetString(decompressedMemory.ToArray()));
                Console.WriteLine(s);

                return headers + s;
            }
        }
        else
        {
            string s = (Encoding.UTF8.GetString(data, index, data.Length - index));
            Console.WriteLine(s);

            return headers + s;
        }
    }
}           
Heterochromatic answered 5/8, 2017 at 20:50 Comment(3)
Is the server responding with a header of Connection: keep-alive? If not then it probably does not support it..Turnstone
Also is there any reason you are doing this manually and not using System.Net.WebRequest?Turnstone
This might be helpful.Barone
O
10

Http Connection get close due to its nature of auto closing connection after specific time ,there is not much you can do about apart from increasing autclosing duration for connection which is again depends on server to server. which ends up in connection time out at the end.

FTP Connection if you want to upload or download data which require hell lot of time better use FTP connection which exists for the very same reason only.

Orelle answered 8/8, 2017 at 10:35 Comment(0)
N
6

Depending on the nature of your headers you may consider using WebSockets as you can send custom authorization headers.

Because WebSocket is intended to be used when the same connection should allow full duplex communication (both data download and upload), it is more appropriate than an HTTP connection.

Nanete answered 9/8, 2017 at 13:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.