Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions bitreq/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,29 @@ This crate is a fork for the very nice
rename it because I wanted to totally gut it and provide a crate with
different goals. Many thanks to the original author.

Simple, minimal-dependency HTTP client. Optional features for http
proxies (`proxy`), async support (`async`, `async-https`), and https
with various TLS implementations (`https-rustls`, `https-rustls-probe`,
and `https` which is an alias for `https-rustls`).
Simple, minimal-dependency HTTP client. Optional features for HTTP
proxies and SOCKS5 proxies (`proxy`), async support (`async`,
`async-https`), and https with various TLS implementations
(`https-rustls`, `https-rustls-probe`, and `https` which is an alias
for `https-rustls`).

### Proxy Support

The `proxy` feature enables both HTTP CONNECT and SOCKS5 proxies:

```rust
// HTTP CONNECT proxy
let proxy = bitreq::Proxy::new_http("http://proxy.example.com:8080").unwrap();
let response = bitreq::get("http://example.com").with_proxy(proxy).send();

// SOCKS5 proxy (e.g., Tor)
let proxy = bitreq::Proxy::new_socks5("127.0.0.1:9050").unwrap();
let response = bitreq::get("http://example.com").with_proxy(proxy).send();
```

SOCKS5 proxies use domain-based addressing (RFC 1928 ATYP 0x03), so
DNS resolution happens at the proxy. This is required for `.onion`
routing through Tor.

Without any optional features, my casual testing indicates about 100
KB additional executable size for stripped release builds using this
Expand Down
16 changes: 14 additions & 2 deletions bitreq/src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,14 @@ impl AsyncConnection {
async fn connect(params: ConnectionParams<'_>) -> Result<AsyncTcpStream, Error> {
#[cfg(feature = "proxy")]
match &params.proxy {
Some(proxy) if proxy.is_socks5() => {
// SOCKS5 proxy
let mut tcp = Self::tcp_connect(&proxy.server, proxy.port).await?;
proxy.socks5_handshake_async(&mut tcp, params.host, params.port).await?;
Ok(tcp)
}
Some(proxy) => {
// do proxy things
// HTTP CONNECT proxy
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be good to just drop the HTTP proxy behavior? Not sure anybody is going to use that, and it might make things simpler?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTTP CONNECT is what payjoin originally requested in #472, so I'd keep it. They serve different use cases: SOCKS5 for Tor/general proxying, HTTP CONNECT for corporate forward proxies and HTTPS tunneling. Happy to refactor if the maintainers agree it should go, but wanted to flag the other stakeholders first.

let mut tcp = Self::tcp_connect(&proxy.server, proxy.port).await?;

let proxy_request = proxy.connect(params.host, params.port);
Expand Down Expand Up @@ -709,8 +715,14 @@ impl Connection {
) -> Result<TcpStream, Error> {
#[cfg(feature = "proxy")]
match &params.proxy {
Some(proxy) if proxy.is_socks5() => {
// SOCKS5 proxy
let mut tcp = Self::tcp_connect(&proxy.server, proxy.port, timeout_at)?;
proxy.socks5_handshake_sync(&mut tcp, params.host, params.port)?;
Ok(tcp)
}
Some(proxy) => {
// do proxy things
// HTTP CONNECT proxy
let mut tcp = Self::tcp_connect(&proxy.server, proxy.port, timeout_at)?;

write!(tcp, "{}", proxy.connect(params.host, params.port))?;
Expand Down
Loading
Loading