Skip to content
New issue

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

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

Already on GitHub? # to your account

Http Proxy Support (+ relevant tokio-tungstenite discussion) #258

Open
UE2020 opened this issue Feb 19, 2021 · 10 comments
Open

Http Proxy Support (+ relevant tokio-tungstenite discussion) #258

UE2020 opened this issue Feb 19, 2021 · 10 comments

Comments

@UE2020
Copy link

UE2020 commented Feb 19, 2021

Is it possible to proxy a connection using http proxies?

@vi
Copy link
Member

vi commented Feb 20, 2021

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.

@qm3ster
Copy link

qm3ster commented Feb 26, 2022

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.

@UE2020
Copy link
Author

UE2020 commented Mar 9, 2022

Thank you very much! FYI, I don't think you're supposed to include ws:// in the Origin header.

@qm3ster
Copy link

qm3ster commented Mar 9, 2022

@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.

@Praying
Copy link

Praying commented Mar 25, 2022

@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.

It's Ok, but do you have any experience with async-socks5 which maybe easier?

@qm3ster
Copy link

qm3ster commented Mar 25, 2022

  1. What is "Ok"? 🤣
  2. No, I don't have experience with async-socks5, but
    async_socks5::connect
    fast_socks5::client::Socks5Stream and
    tokio_socks::tcp::Socks5Stream should all work.

@Praying
Copy link

Praying commented Mar 25, 2022

But I don't know how to write the code, do you have any example?

@vi
Copy link
Member

vi commented Mar 25, 2022

async-socks5

It is based on Tokio 1, but async in current version of rust-websocket is based on legacy Tokio 0.1.

@qm3ster
Copy link

qm3ster commented Mar 26, 2022

This Issue is derailed and we are talking about tokio_tungstenite here instead :v

@vi vi changed the title Http Proxy Support Http Proxy Support (+ relevant tokio-tungstenite discussion) Mar 26, 2022
@UE2020
Copy link
Author

UE2020 commented Mar 26, 2022

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.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants