Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

请问Exe版本是只支持HTTP/1.1吗? #202

Open
MDZZ-123 opened this issue Oct 11, 2024 · 17 comments
Open

请问Exe版本是只支持HTTP/1.1吗? #202

MDZZ-123 opened this issue Oct 11, 2024 · 17 comments
Labels
bug Something isn't working

Comments

@MDZZ-123
Copy link

开启代理后,原来HTTP/2的链接都降级成HTTP/1.1了,用只支持HTTP/2的fetch会报错

@URenko
Copy link
Owner

URenko commented Oct 12, 2024

根据标准,HTTP 代理的第一步是一个 CONNECT 请求,这一步只能是 HTTP/1.1
后面就是单纯的 TCP 转发,可以是 HTTP/2 (甚至都包裹在TLS中了,不会触及)

你可能在用 node.js?
https://stackoverflow.com/questions/62840291/how-do-you-send-http-2-requests-via-a-proxy-using-node-js 可能对你有帮助

@MDZZ-123
Copy link
Author

根据标准,HTTP 代理的第一步是一个 CONNECT 请求,这一步只能是 HTTP/1.1 后面就是单纯的 TCP 转发,可以是 HTTP/2 (甚至都包裹在TLS中了,不会触及)

你可能在用 node.js? https://stackoverflow.com/questions/62840291/how-do-you-send-http-2-requests-via-a-proxy-using-node-js 可能对你有帮助

我确实在用node/deno,不过我说的降级是在浏览器上发现的,比如这个github.com和api.github.com,我直连的时候火狐的控制台里显示的是HTTP/2,但是开了代理后,就只剩下HTTP/1.1了

@URenko URenko added the bug Something isn't working label Oct 12, 2024
URenko added a commit that referenced this issue Oct 12, 2024
@URenko
Copy link
Owner

URenko commented Oct 12, 2024

给客户端(浏览器)和远程服务器两边都发 ALPN: ['h2', 'http/1.1'] 就行了。
但是有可能有一边不支持 h2,所以需要在 client hello 和 server hello 之间插入一段代码,但是这暂时由于 Python 标准库的一个 bug 而不可行: python/cpython#87748

但你强行 h2 是可行的,只是可能需要手动给客户端(浏览器)和远程服务器两边都发 ALPN: ['h2'],c69c2f3 是对其中一边操作的例子

@MDZZ-123
Copy link
Author

根据标准,HTTP 代理的第一步是一个 CONNECT 请求,这一步只能是 HTTP/1.1 后面就是单纯的 TCP 转发,可以是 HTTP/2 (甚至都包裹在TLS中了,不会触及)

你可能在用 node.js? https://stackoverflow.com/questions/62840291/how-do-you-send-http-2-requests-via-a-proxy-using-node-js 可能对你有帮助

话说用node是不是可以直接构造一个没有SNI或者自定义SNI的TLS请求?这样也就不用再开代理来修改请求了

@URenko
Copy link
Owner

URenko commented Oct 12, 2024

根据标准,HTTP 代理的第一步是一个 CONNECT 请求,这一步只能是 HTTP/1.1 后面就是单纯的 TCP 转发,可以是 HTTP/2 (甚至都包裹在TLS中了,不会触及)
你可能在用 node.js? https://stackoverflow.com/questions/62840291/how-do-you-send-http-2-requests-via-a-proxy-using-node-js 可能对你有帮助

话说用node是不是可以直接构造一个没有SNI或者自定义SNI的TLS请求?这样也就不用再开代理来修改请求了

应该是可以的

@MDZZ-123
Copy link
Author

给客户端(浏览器)和远程服务器两边都发 ALPN: ['h2', 'http/1.1'] 就行了。 但是有可能有一边不支持 h2,所以需要在 client hello 和 server hello 之间插入一段代码,但是这暂时由于 Python 标准库的一个 bug 而不可行: python/cpython#87748

但你强行 h2 是可行的,只是可能需要手动给客户端(浏览器)和远程服务器两边都发 ALPN: ['h2'],c69c2f3 是对其中一边操作的例子

你这个好像不行,我按你那个例子手动添加了那一行以后握手好像会失败

@URenko
Copy link
Owner

URenko commented Oct 13, 2024

给客户端(浏览器)和远程服务器两边都发 ALPN: ['h2', 'http/1.1'] 就行了。 但是有可能有一边不支持 h2,所以需要在 client hello 和 server hello 之间插入一段代码,但是这暂时由于 Python 标准库的一个 bug 而不可行: python/cpython#87748
但你强行 h2 是可行的,只是可能需要手动给客户端(浏览器)和远程服务器两边都发 ALPN: ['h2'],c69c2f3 是对其中一边操作的例子

你这个好像不行,我按你那个例子手动添加了那一行以后握手好像会失败

这个只是一边(给客户端的)的,服务端也加个remote_context.set_alpn_protocols(['h2', 'http/1.1'])

remote_context = ssl.create_default_context()
remote_context.check_hostname = False
remote_reader, remote_writer = await asyncio.open_connection(remote_ip, port, ssl=remote_context, server_hostname=server_hostname)

但是要确认服务器是支持 h2 的,因为此时客户端(如果支持的话)已经协商好接下来用 h2 了,服务端要是协商成 http/1.1 就无法交流了。

@MDZZ-123
Copy link
Author

给客户端(浏览器)和远程服务器两边都发 ALPN: ['h2', 'http/1.1'] 就行了。 但是有可能有一边不支持 h2,所以需要在 client hello 和 server hello 之间插入一段代码,但是这暂时由于 Python 标准库的一个 bug 而不可行: python/cpython#87748
但你强行 h2 是可行的,只是可能需要手动给客户端(浏览器)和远程服务器两边都发 ALPN: ['h2'],c69c2f3 是对其中一边操作的例子

你这个好像不行,我按你那个例子手动添加了那一行以后握手好像会失败

这个只是一边(给客户端的)的,服务端也加个remote_context.set_alpn_protocols(['h2', 'http/1.1'])

remote_context = ssl.create_default_context()
remote_context.check_hostname = False
remote_reader, remote_writer = await asyncio.open_connection(remote_ip, port, ssl=remote_context, server_hostname=server_hostname)

但是要确认服务器是支持 h2 的,因为此时客户端(如果支持的话)已经协商好接下来用 h2 了,服务端要是协商成 http/1.1 就无法交流了。

手动设置那肯定会遇到不支持的,话说不能直接复制客户端和服务器返回的ALPN给对方么?

@URenko
Copy link
Owner

URenko commented Oct 13, 2024

给客户端(浏览器)和远程服务器两边都发 ALPN: ['h2', 'http/1.1'] 就行了。 但是有可能有一边不支持 h2,所以需要在 client hello 和 server hello 之间插入一段代码,但是这暂时由于 Python 标准库的一个 bug 而不可行: python/cpython#87748
但你强行 h2 是可行的,只是可能需要手动给客户端(浏览器)和远程服务器两边都发 ALPN: ['h2'],c69c2f3 是对其中一边操作的例子

你这个好像不行,我按你那个例子手动添加了那一行以后握手好像会失败

这个只是一边(给客户端的)的,服务端也加个remote_context.set_alpn_protocols(['h2', 'http/1.1'])

remote_context = ssl.create_default_context()
remote_context.check_hostname = False
remote_reader, remote_writer = await asyncio.open_connection(remote_ip, port, ssl=remote_context, server_hostname=server_hostname)

但是要确认服务器是支持 h2 的,因为此时客户端(如果支持的话)已经协商好接下来用 h2 了,服务端要是协商成 http/1.1 就无法交流了。

手动设置那肯定会遇到不支持的,话说不能直接复制客户端和服务器返回的ALPN给对方么?

理想的情况是客户端 client hello 后,server hello 前获取客户端的 ALPN 给远程服务器,然后跟远程协商好了 server hello 回给客户端。
但问题是 client hello 和 server hello 之间理应能获取 ALPN 的那个 API 的 cpython 实现有 bug

@MDZZ-123
Copy link
Author

给客户端(浏览器)和远程服务器两边都发 ALPN: ['h2', 'http/1.1'] 就行了。 但是有可能有一边不支持 h2,所以需要在 client hello 和 server hello 之间插入一段代码,但是这暂时由于 Python 标准库的一个 bug 而不可行: python/cpython#87748
但你强行 h2 是可行的,只是可能需要手动给客户端(浏览器)和远程服务器两边都发 ALPN: ['h2'],c69c2f3 是对其中一边操作的例子

你这个好像不行,我按你那个例子手动添加了那一行以后握手好像会失败

这个只是一边(给客户端的)的,服务端也加个remote_context.set_alpn_protocols(['h2', 'http/1.1'])

remote_context = ssl.create_default_context()
remote_context.check_hostname = False
remote_reader, remote_writer = await asyncio.open_connection(remote_ip, port, ssl=remote_context, server_hostname=server_hostname)

但是要确认服务器是支持 h2 的,因为此时客户端(如果支持的话)已经协商好接下来用 h2 了,服务端要是协商成 http/1.1 就无法交流了。

手动设置那肯定会遇到不支持的,话说不能直接复制客户端和服务器返回的ALPN给对方么?

理想的情况是客户端 client hello 后,server hello 前获取客户端的 ALPN 给远程服务器,然后跟远程协商好了 server hello 回给客户端。 但问题是 client hello 和 server hello 之间理应能获取 ALPN 的那个 API 的 cpython 实现有 bug

我试了一下,确实是有问题,在sni_callback的时候用selected_alpn_protocol获取到的是空值,只有servername能获取
这样的话要达成两边协商需要先连接一次远程服务器,获取到服务器返回的ALPN以后再返回给客户端,然后才能获取到客户端的ALPN吧,再重新和服务器握手,中间要浪费不少时间

@MDZZ-123
Copy link
Author

按照上面说的思路试了一下,可以实现转发客户端和服务器的ALPN,就是每次要多一次握手比较麻烦,写了个全局变量缓存了一下结果,这样就只有第一次访问的时候需要多握一次手了
不过HTTP/3好像还是不能完全支持?

@URenko
Copy link
Owner

URenko commented Oct 15, 2024

按照上面说的思路试了一下,可以实现转发客户端和服务器的ALPN,就是每次要多一次握手比较麻烦,写了个全局变量缓存了一下结果,这样就只有第一次访问的时候需要多握一次手了 不过HTTP/3好像还是不能完全支持?

HTTP/3 UDP 都没有 RST,也就不需要 Accesser 了

@MDZZ-123
Copy link
Author

按照上面说的思路试了一下,可以实现转发客户端和服务器的ALPN,就是每次要多一次握手比较麻烦,写了个全局变量缓存了一下结果,这样就只有第一次访问的时候需要多握一次手了 不过HTTP/3好像还是不能完全支持?

HTTP/3 UDP 都没有 RST,也就不需要 Accesser 了

但是目前第一次访问还是要用TCP的吧,然后根据响应头才升级成HTTP/3

@URenko
Copy link
Owner

URenko commented Oct 17, 2024

理论上 DNS SVCB/HTTPS 是这一协商问题的正统解决方案

@MDZZ-123
Copy link
Author

理论上 DNS SVCB/HTTPS 是这一协商问题的正统解决方案

通过DNS啊,不会又像ESNI那样直接被咔了吧

@jonm58
Copy link

jonm58 commented Oct 17, 2024

理论上 DNS SVCB/HTTPS 是这一协商问题的正统解决方案

通过DNS啊,不会又像ESNI那样直接被咔了吧

通过DNS,是DNS over HTTPS.

@MDZZ-123
Copy link
Author

理论上 DNS SVCB/HTTPS 是这一协商问题的正统解决方案

如果考虑到SVCB的话,是不是在DNS解析那一步就可以确定需要传递给客户端的alpn了,哦不对,这种一般都是h3网站,不需要代理了。
但是h3是不是有时候也会回退到h2,这时候咋办

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants