Open UE2020 opened 3 years ago
Maybe.
If you want to connect using HTTP CONNECT
proxy, you need to supply custom underlying channel instead of usual automatic TCP for the implementation.
If you expect to the proxy to hangle HTTP upgrades properly and send something like GET ws://host/path HTTP/1.1
, you'll probably need to either modify the library; or to provide HTTP handling part yourself and only use this library for WebSocket message format encoding/decoding.
Note that this library is not well-maintained, and you should try tungstenite
and its satellites first.
An example of going through HTTP proxy to a secure websocket (with tokio and tungstenite, obviously, as prescribed by the previous commenter):
let tcp = TcpStream::connect("proxy_domain:80").await?;
let (mut request_sender, conn) = conn::handshake(tcp).await?;
let conn = tokio::spawn(conn.without_shutdown());
// create an HTTP method CONNECT request, port mandatory, even if 80 or 443
let req = Request::connect("domain.tld:443")
.header("Proxy-Authorization", format!("Basic {}", proxy_base64))
.body(())?;
let res = request_sender.send_request(req).await?;
assert!(response.status() == StatusCode::OK);
// `into_parts` panics if the connection is HTTP/2! Which might be negotiated if the proxy_domain is https! So maybe specify to use HTTP 1.1 above! (we don't worry this time, we are connecting to HTTP, on port 80. Does `without_shutdown` solve that instead? can we do a HTTP/2 connection to the proxy? find out next time on dragonballz
// unwrapping the joinhandle against panic, then the withoutshutdown
let tcp = connection.await??.io;
let req = Request::get("wss://domain.tld/path?query")
.header("Sec-WebSocket-Key", tungstenite::handshake::client::generate_key())
.header("Connection", "Upgrade")
.header("Upgrade", "websocket")
.header("Sec-WebSocket-Version", "13")
.header("Host", "domain.tld")
// technically not required, but many servers will demand it, so we are basically spoofing that we came from a webpage (can't have path though, just "origin" ...or is it "authority"? Idk I forgor. Don't remember which places `user:password@` goes and goesn't... ¯\_(ツ)_/¯ )
.header("Origin", "https://domain.tld")
.body(())?;
let (mut ws_stream, _) = tokio_tungstenite::client_async_tls(req, tcp).await?;
Note all the different variants of urls, don't mix them up.
Thank you very much! FYI, I don't think you're supposed to include ws://
in the Origin header.
@UE2020 you have to include the schema/protocol in a non-null
Origin:
header, but perhaps https://
would be more appropriate than wss://
here(you wrote ws
, I had wss
).
As in "we came here to upgrade to websocket from your https site".
I will change my example now.
@UE2020 you have to include the schema/protocol in a non-
null
Origin:
header, but perhapshttps://
would be more appropriate thanwss://
here(you wrotews
, I hadwss
). As in "we came here to upgrade to websocket from your https site". I will change my example now.
It's Ok, but do you have any experience with async-socks5 which maybe easier?
async-socks5
, but
async_socks5::connect
fast_socks5::client::Socks5Stream
and
tokio_socks::tcp::Socks5Stream
should all work.But I don't know how to write the code, do you have any example?
async-socks5
It is based on Tokio 1, but async in current version of rust-websocket is based on legacy Tokio 0.1.
This Issue is derailed and we are talking about tokio_tungstenite
here instead :v
This Issue is derailed and we are talking about
tokio_tungstenite
here instead :v
To be fair, the README of this crate suggests tungstenite as an alternative.
Is it possible to proxy a connection using http proxies?