【问题标题】:Proxy won't work in chrome and only partly in firefox代理在 chrome 中不起作用,在 Firefox 中只能部分起作用
【发布时间】:2014-05-07 02:27:08
【问题描述】:

我用 C# 编写了一个代理。它的工作原理是从浏览器获取 http 请求,将请求发送到站点并将站点的响应发送回客户端。它可以在 Firefox 中运行,但某些页面会被剪切,就像它没有发送所有响应一样,在 chrome 中它会提供空白页面,而对于 google.co.uk 在 chrome 中,浏览器会给出“未收到数据”。你能在我的代码中看到可能导致这一切的错误吗?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;

namespace LexProxy
{
    class ProxyServer
    {
        private TcpListener tcpListener;

        public ProxyServer()
        {
            this.tcpListener = new TcpListener(IPAddress.Any, 3000);
            this.tcpListener.Start();
            while (true)
            {
                Console.Write("Waiting for a connection... ");
                TcpClient client = tcpListener.AcceptTcpClient();
                Thread thread = new Thread(delegate()
                {
                    Serve(client);
                });
                thread.Start();
            }
        }

        private void Serve(TcpClient client)
        {
            Console.WriteLine("Connected!");
            NetworkStream stream = client.GetStream();
            byte[] request = GetBytesFromStream(stream, client.ReceiveBufferSize);
            if (request != null)
            {
                string requestString = System.Text.Encoding.UTF8.GetString(request);
                string[] requestParts = requestString.Split(' ');
                if (requestParts.Length >= 2)
                {
                    string method = requestParts[0];
                    if (!requestParts[1].Contains("http://") && !requestParts[1].Contains("https://"))
                        requestParts[1] = "http://" + requestParts[1];

                    Uri uri = new Uri(requestParts[1], UriKind.RelativeOrAbsolute);
                    string host = StringUtils.ReplaceFirst(uri.Host, "www.", "");
                    int port = uri.Port;
                    byte[] response = getResponse(host, port, request);
                    if (response != null)
                        stream.Write(response, 0, response.Length);
                    client.Close();
                }
            }
        }

        private byte[] getResponse(string host, int port, byte[] request)
        {
            TcpClient client = new TcpClient(host, port);
            NetworkStream stream = client.GetStream();
            stream.Write(request, 0, request.Length);
            byte[] response = GetBytesFromStream(stream, client.ReceiveBufferSize);
            return response;
        }

        private byte[] GetBytesFromStream(NetworkStream stream, int bufferSize)
        {
            Byte[] bytes = new Byte[bufferSize];
            int i;
            while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
            {
                return bytes;
            }

            return null;
        }
    }
}

【问题讨论】:

    标签: c#


    【解决方案1】:

    一个小错误是您使用UTF8 来读取请求的第一行。 HTTP 请求行和标头是ASCII(而正文可能UTF8,但不一定是,甚至可能根本不是字符串)。它起作用的原因是 b/c 用于英语字符集,UTF8 和 ASCII 恰好使用相同的字节进行编码。但这是次要问题。

    最有可能的主要问题隐藏在您的GetBytesFromStream 中。您只调用一次.Read,但这并不能保证返回整个消息。它可能只返回 1 个字节......所以您需要继续获取更多数据。你怎么知道还有多少?它由您需要正确解析和检查的 HTTP 协议决定。 (至少您会一直阅读到 \r\n\r\n 表示请求标头结束的字节序列。

    但是,这还不够,因为可能存在请求正文,其长度将通过 HTTP 标头 Content-Length: (IIRC) 或可能使用 chunked encoding 指定。除了 URI 检查之外,我没有看到任何代码,因此很可能您自己不处理 HTTP 消息传递协议,因此它不太可能正常工作(除非您设法强制浏览器使用 HTTP/0.9HTTP/1.0,因为那些不要重用连接并为每个连接发送一条消息,此时您可以盲目地读取套接字必须提供给您的所有内容,直到浏览器通过关闭其连接的写入端点来发出流结束的信号)。

    但您的主要问题是 GetBytesFromStream 不会给您“所有”字节。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多