reqwest icon indicating copy to clipboard operation
reqwest copied to clipboard

Is there a way to use a unix socket?

Open bbigras opened this issue 7 years ago • 42 comments

I would like to do the equivalent of:

curl --unix-socket /var/run/docker.sock http://localhost/containers/json

There's the unix_socket crate but I'm not sure if I can use it with reqwest.

bbigras avatar Jan 02 '17 07:01 bbigras

There isn't a way yet, but it definitely makes sense to provide when cfg(unix)!

What makes sense for the best way to provide this? Just adding to the connector to look for the unix:// scheme? There doesn't seem to be a standard way to handle this, as I look up various HTTP libraries.

seanmonstar avatar Jan 02 '17 07:01 seanmonstar

The unix:// scheme seems to be well established, I'd recommend doing what you propose.

stephanbuys avatar Jan 10 '17 12:01 stephanbuys

The url crate seems to support the unix:// scheme (see example).

let url = Url::parse("unix:/run/foo.socket").unwrap();

Would it be possible to include the path with something like this?

let url = Url::parse("unix:/var/run/docker.sock/containers/json").unwrap();

I'm also wondering if localhost is passed to the unix socket. If so, I don't know how it would be possible to specify it (or another vhost) using the unix:// scheme.

According to the Docker Remote API page, older curl version used http://containers/json as the URL so I don't know if the localhost part is used.

bbigras avatar Jan 10 '17 15:01 bbigras

So looking around, I see two possible routes.

  • As curl does it, which is to not use the URL to indicate that a unix socket should be used instead of TCP. This could either be a single constructor on the client, like Client::unix_socket("/var/docker.sock"), or it could be considered a "proxy", and thus as suggested in #30, be something like Proxy::unix("/var/docket.sock").
  • Using the URL, something like requests-unixsocket, with an example of http+unix://%2Ftmp%2Fprofilesvc.sock/path/to/page. This is a whole lot uglier, but allows all the semantics to exist in the Url, such as whether to use TLS, and is possibly easier to allow dynamic selection of which unix socket.

seanmonstar avatar Jan 10 '17 20:01 seanmonstar

@seanmonstar in case you were looking for feedback, I definitely prefer the first option because it allows to leave the scheme and host-fqdn part untouched. This is important if at the other end of the unix-socket there is a virtualhost-aware server, or something doing TLS-ALPN (or similar upper protocol detection/negotiation).

lucab avatar Aug 24 '17 11:08 lucab

I've wanted "use a socket for HTTP requests" for a while because setting up a proxy on a port doesn't lock it down to just the current user. Not that that project is ever going to use Rust at its network level anytime soon, but it's not an unheard of use case.

mathstuf avatar Aug 24 '17 12:08 mathstuf

I think I prefer this being Proxy::unix(path). For implementation details, it'd need to be slightly different since it would actually connect a unix stream instead of just give a new URL.

seanmonstar avatar Aug 25 '17 21:08 seanmonstar

Any progress in this area?

farodin91 avatar Mar 10 '18 23:03 farodin91

Doing some research in how it is done elsewhere:

mathstuf avatar Mar 11 '18 15:03 mathstuf

I saw a implementation of unix socket in boondock using hyper 0.9.0 https://github.com/faradayio/boondock/blob/master/src/unix.rs

farodin91 avatar Mar 11 '18 21:03 farodin91

This also might not be a non-Windows thing in the future as well: https://blogs.msdn.microsoft.com/commandline/2017/12/19/af_unix-comes-to-windows/

mathstuf avatar Mar 11 '18 21:03 mathstuf

I came across the hyperlocal crate today which might be of interest

jjl avatar Apr 13 '18 18:04 jjl

Is there any workaround now? I was looking at something with the xmlrpc crate (which uses reqwest by default) but unix sockets are a must-have for my environment and it looked like all the Transport stuff in reqwest is currently hidden away in the async_impl module; there didn't seem to be any hooks in ClientBuilder where I could shove a custom Transport.

Roguelazer avatar Aug 01 '18 21:08 Roguelazer

Has there been any progress on this? I am also looking for a way to use the Docker authorization via the Docker socket, but without going through the loopback address.

doctorCC avatar Feb 05 '19 19:02 doctorCC

@seanmonstar .. I've designed a solution to support Unix Socket... and we already use it in our codebase. I can make it more generic and reqwesty .. and then submit a PR, in case if you're not already working on it. Please let me know your thoughts.

snawaz avatar Apr 17 '19 03:04 snawaz

@seanmonstar To be precise, I think you mean something like Proxy::all("unix:/var/run/docker.sock") right? as Proxy::http vs Proxy::https vs Proxy::all vs Proxy::custom appears to be about what should be proxied, not how it's proxied. Looks like the argument determines the latter, within ProxyScheme::parse.

scottlamb avatar Jun 20 '19 05:06 scottlamb

It would be nice if this could work on Windows too via named pipes.

lucasyvas avatar Jun 29 '19 04:06 lucasyvas

I found this discussion after trying to use reqwest with our unix domain socket-based authentication proxy, and was reminded of this: One of the things that I find that go's http.Transport got right is the way you establish an HTTP-able connection. The Transport has Dial (and, because it's go, DialContext) field that holds a function, which establishes the unencrypted TCP connection.

I kind of wish that reqwest allowed this kind of customization: I'd like to be able to tell the system in what way to establish a network connection. Then, reqwest could be entirely independent of how the proxy wants to be reached: named pipe, unix domain socket, CONNECT proxy over open SMTP relay, etc.

asf-stripe avatar Jul 05 '19 16:07 asf-stripe

I would also use this if it was available. I'm making a REST API, but I need to be able to access it by mounting a Unix socket into a container. Reqwest seems pretty de-facto for making HTTP requests so it would be really nice to be able to use it for Unix sockets too.

zicklag avatar Nov 12 '19 23:11 zicklag

I'll also note that Docker's socket talks HTTP.

mathstuf avatar Nov 12 '19 23:11 mathstuf

What's the current status of this? As @snawaz mentioned it's already partially ready. Would love some updates as I'd love to talk to docker over a unix socket. Cheers :)

vv9k avatar Dec 12 '19 12:12 vv9k

This is really easy to do with Hyper. Any chance of exposing the necessary methods? Or better yet, creating a Request Client from a Hyper Client?

danieleades avatar Dec 19 '19 09:12 danieleades

I'm not seeing anything obvious in the docs. Do you have a link to the methods involved (or example code)?

mathstuf avatar Dec 19 '19 18:12 mathstuf

I'm not seeing anything obvious in the docs. Do you have a link to the methods involved (or example code)?

if you were talking to me, you could take a look at my pull request on hyperlocal for some code examples

danieleades avatar Dec 26 '19 20:12 danieleades

I would recommend the unix: scheme as well because it means that all reqwest users would get it automatically (or with a feature enabled). It would also mean that all tools that use reqwest would have a consistent syntax for specifying UNIX sockets.

kevincox avatar Mar 27 '20 13:03 kevincox

with the hyper client, it's easy to send http requests over anything that implements AsyncRead and AsyncWrite

let (mut request_sender, connection) = hyper::client::conn::Builder::new()
	.handshake::<MyCustomTcpStream, Body>(stream)
	.await?;

let request = Request::builder()
	.header("Host", "example.com")
	.method("GET")
	.body(Body::from("hello world!"))?;

let response = request_sender.send_request(request).await?;

Absolucy avatar Feb 14 '21 03:02 Absolucy

Would be nice if it was possible to use a unix domain socket as a socks5h proxy (tor provides a socks uds option for example)

jackloomen avatar Aug 30 '21 20:08 jackloomen

Hi everyone. Any update on this issue? Since it has been opened for 4 years I wonder if there is anything to do to help :)

jvjfk avatar Mar 10 '22 14:03 jvjfk

This would be a great addition!

ahl avatar May 20 '22 18:05 ahl

Apache's ProxyPass uses the syntax unix:/path/to/socket|http://example.com/path?query, i.e. socket path + pipe + URI, which I think is very readable, and has the advantage that you can use it with HTTPS, basic authorization, etc.

Kijewski avatar Aug 18 '22 15:08 Kijewski