簡體   English   中英

構建簡單的http代理的方式

[英]The way of building a simple http proxy

我正在嘗試構建一個簡單的http代理 ,它執行四個非常基本的事情:

  • 接受來自Web瀏覽器的連接(使用TcpClient / TcpListener)。
  • 從其流中讀取請求。
  • 讀取主機名並啟動與主機的連接。
  • 從網頁加載內容並將其轉發回客戶端。

我遇到的麻煩

  • 有時頁面根本不會加載。
  • 有時瀏覽器給我一個錯誤'內容有錯誤的加密'(在Firefox中)。
  • 我很少能看到內容損壞(純文本而不是HTML)。

我做了什么:

  • HttpListener類,包含偵聽傳入請求和調用事件OnNewRequestReceived的方法:
        public void Listen()
        {
            Listener.Start();

            while (true)
            {
                var client = Listener.AcceptTcpClient();

                Task.Run(() => StartReceivingData(client));      
            }

        }

        public void StartReceivingData(TcpClient client)
        {
            NetworkStream clientStream = client.GetStream();

            var buffer = new byte[16000];

            while (true)
            {
                try
                {
                    if (!clientStream.CanRead)
                        return;

                    //connection is closed
                    if (clientStream.Read(buffer).Equals(0))
                        return;

                    OnNewRequestReceived?.Invoke(this, new RequestReceivedEventArgs() { User = client, Request = buffer });
                } // when clientStream is disposed, exception is thrown.
                catch { return; }
            }
        }

  • HttpClient類基本上包含一個訂閱上述事件的方法:
 private void Listener_OnNewConnectionReceived(object sender, RequestReceivedEventArgs e)
        {
            string hostname = HttpQueryParser.GetHostName(e.Request);
            NetworkStream proxyClientStream = e.User.GetStream();

            try
            {
                if (firewall.CheckIfBlocked(hostname))
                {
                    //send error page
                    e.User.GetStream().Write(Encoding.ASCII.GetBytes("<html><body style=\"padding:0; margin:0;\"><img style=\"padding:0; margin:0; width:100%; height:100%;\" src=\"https://www.hostinger.co.id/tutorial/wp-content/uploads/sites/11/2017/08/what-is-403-forbidden-error-and-how-to-fix-it.jpg\"</body></html>"));
                    return;
                }

                var targetServer = new TcpClient(hostname, 80);

                NetworkStream targetServerStream = targetServer.GetStream();

                targetServerStream.Write(e.Request);

                var responseBuffer = new byte[32];

                for (int offsetCounter = 0; true; ++offsetCounter)
                {
                    var bytesRead = targetServerStream.Read(responseBuffer, 0, responseBuffer.Length);

                  //  Console.WriteLine($"Read {bytesRead} from {hostname}.");

                    if (bytesRead.Equals(0))
                        return;


                    proxyClientStream.Write(responseBuffer, 0, responseBuffer.Length);

                    if (offsetCounter.Equals(0))
                    {
                        var headers = Encoding.UTF8.GetString(responseBuffer).Split("\r\n");

                        logger.Log(new HttpRequestEntry()
                        {
                            ResponseCode = headers[0].Substring(headers[0].IndexOf(" ") + 1),
                            Hostname = hostname
                        });
                    }
                }

            }
            catch { return; }
            finally { proxyClientStream.Dispose(); }


        }

所以,我猜我的緩沖區大小有問題,但將其更改為更高的值實際上並沒有改變任何東西。

好的,所以我不知道我的字節數組是什么問題, 但是我使用Stream.CopyTo使它工作,我很驚訝 - 它適用於兩個NetworkStreams。 如果你好奇,這是工作方法:

 private void Listener_OnNewConnectionReceived(object sender, RequestReceivedEventArgs e)
 {
            string hostname = HttpQueryParser.GetHostName(e.Request);
            NetworkStream proxyClientStream = e.User.GetStream();

            try
            {
                if (firewall.CheckIfBlocked(hostname))
                {
                    //send error page
                    e.User.GetStream().Write(Encoding.ASCII.GetBytes("<html><body style=\"padding:0; margin:0;\"><img style=\"padding:0; margin:0; width:100%; height:100%;\" src=\"https://www.hostinger.co.id/tutorial/wp-content/uploads/sites/11/2017/08/what-is-403-forbidden-error-and-how-to-fix-it.jpg\"</body></html>"));
                    return;
                }

                var targetServer = new TcpClient(hostname, 80);

                NetworkStream targetServerStream = targetServer.GetStream();

                targetServerStream.Write(e.Request);

                var responseBuffer = new byte[32];

                //this is to capture status of http request and log it.

                targetServerStream.Read(responseBuffer, 0, responseBuffer.Length);

                proxyClientStream.Write(responseBuffer, 0, responseBuffer.Length);

                var headers = Encoding.UTF8.GetString(responseBuffer).Split("\r\n");

                logger.Log(new HttpRequestEntry()
                {
                    ResponseCode = headers[0].Substring(headers[0].IndexOf(" ") + 1),
                    Hostname = hostname
                });

                targetServerStream.CopyTo(proxyClientStream);

            }
            catch { return; }
            finally { proxyClientStream.Dispose(); }


}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM