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

Config.DialContext hook and http.RoundTripper support #31

Open
wants to merge 37 commits into
base: master
Choose a base branch
from

Conversation

ydnar
Copy link

@ydnar ydnar commented Jun 21, 2018

This PR implements two related features that we needed in production to enable downloads of files from FTP(S) servers that filter connections to IP allow-lists.

  1. Config.DialContext hook, mirrored from the implementation in net/http.Transport. If set, this is used instead of net.Dial to establish TCP connections.
  2. Support for the http.RoundTripper interface on Config to allow an http.Client download ftp:// URLs.

A few additional things for 2021:

  • A go.mod file (required for Go 1.16+ support).
  • Moves CI from Travis to GitHub Actions.
  • Generates the testing key and certificate on the fly (previously hard-coded).
  • Upgrades the test ftpd servers to current versions.

Copy link
Contributor

@muirmanders muirmanders left a comment

Choose a reason for hiding this comment

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

Thank you for your contribution. Can you help me understand why Config.DialContext hook is needed?

client.go Outdated Show resolved Hide resolved
client.go Outdated
@@ -369,15 +379,18 @@ func (c *Client) openConn(idx int, host string) (pconn *persistentConn, err erro

var conn net.Conn

ctx := context.Background()
if c.config.Timeout != 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

config.Timeout has a default so it will never be 0.

Copy link
Author

Choose a reason for hiding this comment

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

Saw that. I’m not sure I agree with the design decision (versus defaulting timeout if zero at runtime), but it’s your library. Happy to change.

Copy link
Author

Choose a reason for hiding this comment

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

Done (719b580). I also noted where the library should wire up a parent Context in the future to allow overall FTP operations to be governed by a caller’s Context.

client.go Outdated Show resolved Hide resolved
persistent_connection.go Outdated Show resolved Hide resolved
transport.go Outdated
// Transport implements the http.RoundTripper interface.
// Typical usage would be to register a Transport to handle
// ftp:// and/or ftps:// URLs with http.Transport.RegisterProtocol.
type Transport struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we name this HTTPTransport so it isn't confused for an ftp transport?

Copy link
Author

Choose a reason for hiding this comment

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

I think bare Transport works better because it is an FTP transport that happens to implement the http.RoundTripper interface.

Copy link
Author

Choose a reason for hiding this comment

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

Eliminated the separate Transport struct in favor of a method on Config.

transport.go Outdated Show resolved Hide resolved
transport.go Outdated Show resolved Hide resolved
examples_test.go Outdated Show resolved Hide resolved
@ydnar
Copy link
Author

ydnar commented Jul 10, 2018

To answer your question (“why do you need a DialContext hook?”):

Our systems connect to many (i.e. hundreds) of systems that allow-list our IP addresses. We maintain proxy hosts with static IPs at various cloud providers and our production hosts connect to the remote hosts via an SSH+SOCKS5 tunnel.

We need to be able to connect to remote FTP servers and control how the network connection is established. Our backend has dialers (with a DialContext method) that connect via one of our proxies. The proxy dialers also have a Dial method for legacy code, but nearly all of our network code accepts a Context for fine-grained control over timeouts.

Your FTP library was the most mature/robust, so we forked it to add the DialContext hook for our purposes.

@ydnar
Copy link
Author

ydnar commented Jul 11, 2018

While we’re on the subject of naming things, it feels itchy to me that the Dial and DialConfig functions are named as such, rather than NewClient, since neither actually dial a network connection.

Would you be opposed to adding a top-level function NewClient that mirrors the DialConfig signature?

@muirmanders
Copy link
Contributor

itchy to me that the Dial and DialConfig

Agreed.

Would you be opposed to adding a top-level function NewClient

Bad name is bad, but having a bad name and another name doesn't help much at this point. Once modules are the thing we can do a v2 and go crazy renaming.

parallel_walk_test.go Outdated Show resolved Hide resolved
@ydnar
Copy link
Author

ydnar commented Aug 22, 2018

Re: NewClient vs Dial / DialConfig we’ve introduced the desired API and marked the previous API as deprecated and indicated the API clients should use going forward. I’m trying to think of a couple examples of API warts that the Go team moved around as their package APIs matured…

ydnar added 10 commits March 20, 2021 09:23
This enables clients to specify their own connection logic, to permit
creation of connections through a proxy (for IP whitelisting).
Not all net.Conn implementations provide a valid RemoteAddr(), in
particular crypto/ssh.Conn:

https://godoc.org/golang.org/x/crypto/ssh#Client.Dial
This enables clients to handle GET requests of ftp:// or ftps:// URLs
with a normal http.Client using http.Transport.RegisterProtocol().
Also note where parent Context should be wired up in future.
@ydnar ydnar requested a review from muirmanders March 20, 2021 19:01
@ydnar ydnar changed the title Config.DialContext hook and Transport type Config.DialContext hook and http.RoundTripper support Mar 20, 2021
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.

None yet

2 participants