得得

开源
FastGithub社区

不兼容 urllib3 的 http 代理

SadPencil 2022-02-25 14:02 6回复

Bug描述
urllib3 具有 http 代理功能,但无法接入 fastgithub 提供的 http 代理端口,报错信息在后面给出。

看过 urllib3 和 fastgithub 的代码,HttpProxyMiddleware.cs里面的context.Request.Host是空导致了这个问题,但没有找到明显的原因和修复手段。可疑的地方就是urllib3在发送CONNECT 这一条HTTP请求的时候没有加Host: 的http header,但根据 RFC 7231 - section 4.3.6 的示例:

     CONNECT server.example.com:80 HTTP/1.1
     Host: server.example.com:80

似乎 Host: 不是必须的,因为 CONNECT 那一行已经给出了服务器地址和端口。根据 urllib3 的代码 poolmanager.py在connect时故意不加header也印证了这一点:

    def _prepare_proxy(self, conn: HTTPSConnection) -> None:  # type: ignore[override]
        """
        Establishes a tunnel connection through HTTP CONNECT.
        Tunnel connection is established early because otherwise httplib would
        improperly set Host: header to proxy's IP:port.
        """

重现步骤

  1. 在 Linux 下运行 FastGitHub(Windows 也行,把Program.cs里面那个Windows启动什么服务Linux启动什么服务的if判断改掉)
  2. Python 3.10,pip install urllib3==1.26.8
  3. 在 Python 交互式命令行下运行如下代码
import urllib3

proxy = urllib3.ProxyManager("http://localhost:38457/")
proxy.request("GET", "https://github.com/")
  1. urllib3 和 fastgithub 都会报错
    fastgithub 报错如下
2022-02-25T06:14:40.6117934+00:00 [ERR]
Microsoft.AspNetCore.Server.Kestrel
Connection id "0HMFO4OAIS3AE", Request id "0HMFO4OAIS3AE:00000002": An unhandled exception was thrown by the application.
System.ArgumentException: The parameter 'host' cannot be an empty string.
   at System.Net.DnsEndPoint..ctor(String , Int32 , AddressFamily )
   at FastGithub.HttpServer.HttpProxyMiddleware.GetUpstreamEndPointsAsync(HostString host, CancellationToken cancellationToken)+MoveNext()
   at FastGithub.HttpServer.HttpProxyMiddleware.GetUpstreamEndPointsAsync(HostString host, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource<System.Boolean>.GetResult()
   at FastGithub.HttpServer.HttpProxyMiddleware.CreateConnectionAsync(HostString host, CancellationToken cancellationToken)
   at FastGithub.HttpServer.HttpProxyMiddleware.CreateConnectionAsync(HostString host, CancellationToken cancellationToken)
   at FastGithub.HttpServer.HttpProxyMiddleware.InvokeAsync(HttpContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

软件信息

  • 操作系统: Linux 5.10.0-9-amd64 #1 SMP Debian 5.10.70-1 (2021-09-30) x86_64 GNU/Linux
  • FastGithub:v2.1.3
6 条回复
  • #1
    xljiulang 2022-02-25 15:02

    我想知道客户端发送的报文是什么,目前的情况是,如果请求报文是CONNECT server.example.com:80 HTTP/1.1\r\n\r\n,fastgithub会响应400的错误码,但上面的异常显然不是缺少Host,而是在处理Host的内容遇到问题。

    你可以在 windows开启fildder,在 tools->options->connections里配置监听端口,然后重启fildder做为一个代理服务器,相应的,你的代码修改为```proxy = urllib3.ProxyManager("http://{fildder的ip}:{配置监听接口}/"),然后使用fildder看报文。

    或者你在linux使用tcp dump等工具抓包也行,能分析客户端发出的报文就ok.

  • #2
    SadPencil 2022-02-25 15:02

    我想知道客户端发送的报文是什么,目前的情况是,如果请求报文是CONNECT server.example.com:80 HTTP/1.1\r\n\r\n,fastgithub会响应400的错误码,但上面的异常显然不是缺少Host,而是在处理Host的内容遇到问题。

    你可以在 windows开启fildder,在 tools->options->connections里配置监听端口,然后重启fildder做为一个代理服务器,相应的,你的代码修改为```proxy = urllib3.ProxyManager("http://{fildder的ip}:{配置监听接口}/"),然后使用fildder看报文。

    或者你在linux使用tcp dump等工具抓包也行,能分析客户端发出的报文就ok.

    wireshark抓了一下,已上传
    看起来urllib3发送的就是

    CONNECT github.com:443 HTTP/1.0\r\n\r\n
    
  • #3
    SadPencil 2022-02-25 15:02
  • #4
    xljiulang 2022-02-25 16:02
    CONNECT github.com:443 HTTP/1.0
    
    HTTP/1.1 500 Internal Server Error
    Content-Length: 0
    Connection: close
    Date: Fri, 25 Feb 2022 07:24:56 GMT
    Server: Kestrel
    

    Connect协议必须是http1.1或以上版本。

  • #5
    xljiulang 2022-02-25 16:02
  • #6
    SadPencil 2022-02-25 17:02

    谢谢!看来是urllib3的问题,非常感谢!