rust - Rust:如何使用 async-std + TLS + HTTP 代理(http 隧道)?
问题描述
我购买了一个http代理(支持http隧道),但没有rust示例代码,我尝试使用crate surf,但没有找到代理方式,我必须自己实现。以下是我的代码:
use async_std::task::block_on;
use std::error::Error;
use std::result::Result;
use futures::{AsyncWriteExt, AsyncReadExt};
use async_tls::TlsConnector;
use async_std::net::TcpStream;
const PROXY: &str = "200.200.200.200:8000"; // this is proxy / http tunnel / example IP
async fn http_get_with_proxy(url: &str, proxy: &str) -> Result<String, Box<dyn Error>> {
// 1. make proxy to build connection to target host
let mut stream = TcpStream::connect(proxy).await?;
let r = stream.write_all(format!("CONNECT www.domain.com:443 HTTP/1.1\r\n\r\n").as_bytes()).await?;
// 2. start SSL handshake process, resuse TCP stream.
let connector = TlsConnector::default();
let mut tls_stream = connector.connect("www.example.com", stream).await?;
// 3. send data with SSL protocal to proxy, proxy will forward data to target.
let r = tls_stream.write_all(format!("GET https://www.example.com/ HTTP/1.1\r\n\r\n").as_bytes()).await?;
let mut buf = String::new();
// 4. recv data from proxy.
let r = tls_stream.read_to_string(&mut buf).await;
Ok(buf)
}
fn main() {
let r = block_on( http_get_with_proxy("https://www.example.com/", PROXY));
dbg!(r);
}
得到错误:
[src/main.rs:35] r = Err(
Custom {
kind: InvalidData,
error: CorruptMessage,
},
)
我不知道出了什么问题。
解决方案
我不是 rust 专家,但我看到协议级别存在错误:
... CONNECT www.domain.com:443 HTTP/1.1\n\n ...
\r\n\r\n
首先,不应该\n\n
。更重要的是,必须等待代理的 HTTP 响应,只有在获得完整响应后才建立 TLS 连接。否则,代理的纯 HTTP 响应将被解释为 TLS 握手中的回复,因此握手将失败。有关此握手的简短示例,另请参见Wikipedia。
... GET https://www.example.com/ HTTP/1.1\r\n\r\n ...
这不是一个有效的 HTTP/1.1 请求。它至少缺少Host
标题,并且请求行应该只包含路径/
而不是完整的 URL。
如果您真的想自己实现 HTTP 而不是使用库,请研究实际标准,而不是事后猜测协议的工作方式。
推荐阅读
- php - 使用 laravel 导出 Excel 中的问题
- azure - 在 adf 逻辑应用程序中使用有效负载运行时逻辑应用程序引发扩展 ajax 错误
- c# - 是否可以覆盖 DateTime.Now 或警告开发人员不要使用它?
- vb.net - 多选行失败时捕获 Datagridview 错误
- sql-server - 如何判断当前会话是否持有锁?
- mysql - 将列作为日期类型从 CSV 导入 MySQL
- handlebars.js - 如何将自定义链接数据添加到 Branch.io 中的自定义 Deepview?
- node.js - 在浏览器中显示基线 h264 帧流
- c# - 如何抛出异常
- firebase - Firebase Android应用程序无法在物理手机上使用电子邮件和密码登录,只能在模拟器上登录