Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add support to unix sockets #153

Merged
merged 11 commits into from
Oct 16, 2021
Merged

Conversation

cgerling
Copy link
Contributor

@cgerling cgerling commented Oct 13, 2021

Closes https://github.com/keathley/finch/issues/139

This PR doesn't add support to connect with UNIX sockets through HTTPS, I wasn't sure how to do it without changing a lot of stuff so let me know if there is a "right way" to implement it

lib/finch.ex Outdated
@@ -54,7 +54,8 @@ defmodule Finch do
doc: """
These options are passed to `Mint.HTTP.connect/4` whenever a new connection is established. \
`:mode` is not configurable as Finch must control this setting. Typically these options are \
used to configure proxying, https settings, or connect timeouts.
used to configure proxying, https settings, or connect timeouts. \
When connecting to unix sockets a hostname must be provided.
Copy link
Contributor Author

@cgerling cgerling Oct 13, 2021

Choose a reason for hiding this comment

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

Not sure if it should add "localhost" as the default hostname for this scenario or just leave it up to the client to specify one, any thoughts?

Copy link
Owner

Choose a reason for hiding this comment

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

I think it would be a much nicer API if we could add this as the default for socket connections

@cgerling cgerling force-pushed the add-support-to-unix-sockets branch 2 times, most recently from 83cc0f7 to 147fb37 Compare October 13, 2021 11:56
Copy link
Owner

@sneako sneako left a comment

Choose a reason for hiding this comment

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

Thanks for getting the ball rolling here! This is a great start, and it has helped uncover an issue with the API we were hoping to provide

lib/finch.ex Outdated
@@ -54,7 +54,8 @@ defmodule Finch do
doc: """
These options are passed to `Mint.HTTP.connect/4` whenever a new connection is established. \
`:mode` is not configurable as Finch must control this setting. Typically these options are \
used to configure proxying, https settings, or connect timeouts.
used to configure proxying, https settings, or connect timeouts. \
When connecting to unix sockets a hostname must be provided.
Copy link
Owner

Choose a reason for hiding this comment

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

I think it would be a much nicer API if we could add this as the default for socket connections

lib/finch.ex Outdated
@@ -133,6 +135,9 @@ defmodule Finch do
:default ->
{:ok, destination}

{:local, unix_socket} ->
{:ok, {:http, {:local, unix_socket}, 0}}
Copy link
Owner

Choose a reason for hiding this comment

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

This is making me think that we might have to use a different format for the pool configuration, rather than just {:local, unix_socket}. We can't assume it will be :http so I guess we should revisit the previous suggestion of using a scheme like http+unix:// or https+unix:// but I am definitely open to new ideas as well.

To sum it up, the issue is that pools are started based on the pool configuration. When a pool is started, it registers itself with the Registry, using the {scheme, host, port} as the key. Then when we make a request, based on the request uri, we get the same {scheme, host, port} tuple and use that to query the Registry for the corresponding pool. Therefore, in order to match the request to the correctly configured pool, we need to be able to extract the full {scheme, host, port} tuple from the key that we provide in the pool configuration map.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, it's a real shame that http+unix:// isn't standardised. See whatwg/url#577.

As was mentioned before, I think a bit of a problem with the http+unix scheme is the socket path vs resource path distinction needs to be made and it means either escaping the socket path which is ugly or figuring out the socket path which seems brittle.

Another idea is to explicitly mention schema in the pool config:

pools = %{
  {:local, :http, path} # or {:http, {:local, path}}, {:http, path}, etc
}

Finch.build(:get, "http://localhost/v1.41/_ping", unix_socket: "/var/run/docker.sock")
|> Finch.request()

notice we have the http:// in our url so we can match that with the pool. But yeah, on the other hand it is a bit ugly that we're arbitrarily setting the hostname which seems to be ignored. (On the flip side, if there's a server implementation that cares about the hostname, this approach is beneficial.)

Copy link
Owner

Choose a reason for hiding this comment

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

Ah right, good point about distinguishing between the socket path and the resource path :( I also considered adding the protocol to the tuple that we provide in the pool config, but I did not like the fact that it would be so different from the args that are passed to Finch.build/5. Maybe that is not such a big deal though?

Copy link
Contributor

Choose a reason for hiding this comment

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

Using socket should just work with the lazy :default pool, right? I think it will and so I think that most users would not need to even explicitly configure it. And for those that do, it seems so niche use case that it is perhaps fine that it is a little ugly :)

Copy link
Owner

@sneako sneako Oct 14, 2021

Choose a reason for hiding this comment

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

Good point, in that case {:http, {:local, socket_path}} seems the best to me. Maybe we should also allow {:http, hostname, {:local, socket_path}} in case the server requires a hostname other than localhost (maybe this would be necessary for TLS?) Scratch that, the hostname should be provided via conn_opts if it should be something other than localhost.

@cgerling cgerling force-pushed the add-support-to-unix-sockets branch 3 times, most recently from 6247f99 to a98bfee Compare October 15, 2021 10:41
@cgerling
Copy link
Contributor Author

This is ready for another review @sneako @wojtekmach

Copy link
Contributor

@wojtekmach wojtekmach left a comment

Choose a reason for hiding this comment

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

LGTM!

lib/finch.ex Outdated Show resolved Hide resolved

start_supervised!({Finch, name: MyFinch})

Finch.build(:get, "http://localhost/", [], nil, unix_socket: socket_path)
Copy link
Owner

Choose a reason for hiding this comment

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

Maybe we should add assert {:ok, %{status: 200}} = to this case and the next one?

Copy link
Contributor Author

@cgerling cgerling Oct 15, 2021

Choose a reason for hiding this comment

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

I think it's good to ensure that the response was successfully parsed, I've added the asserts

@sneako
Copy link
Owner

sneako commented Oct 15, 2021

Great work @cgerling ! Just a couple minor comments, but overall this looks good!

@sneako
Copy link
Owner

sneako commented Oct 15, 2021

Ah and it looks like there are a few things that credo is complaining about too (don't worry about the failing tests on 1.7.4/19.x, we need to fix that after some recent changes)

@cgerling cgerling requested a review from sneako October 15, 2021 15:44
@sneako
Copy link
Owner

sneako commented Oct 16, 2021

Thanks @cgerling !

@sneako sneako merged commit ebbe8f0 into sneako:main Oct 16, 2021
@cgerling cgerling deleted the add-support-to-unix-sockets branch July 8, 2022 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support unix sockets
3 participants