Skip to content

Add a SafeHttpClient method #82

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

Merged
merged 11 commits into from
Feb 4, 2020
Merged

Add a SafeHttpClient method #82

merged 11 commits into from
Feb 4, 2020

Conversation

biilmann
Copy link
Member

This adds a tracing method to a client that will make sure
any request to a reserved IP is canceled at DNSDone time

This adds a tracing method to a client that will make sure
any request to a reserved IP is canceled at DNSDone time
Copy link
Member

@rybit rybit left a comment

Choose a reason for hiding this comment

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

Generally I like the approach but I think that you can do a few small things to make it more clear:

  • override only the transport
  • use anonymous functions
  • use an optional logger

Like this (mostly untested)

type noLocalTransport struct {
	inner  http.RoundTripper
	errlog logrus.FieldLogger
}

func (no noLocalTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	ctx, cancel := context.WithCancel(req.Context())

	ctx = httptrace.WithClientTrace(ctx, &httptrace.ClientTrace{
		DNSDone: func(info httptrace.DNSDoneInfo) {
			if endpoint := isLocal(info); endpoint != "" {
				cancel()
				if no.errlog != nil {
					no.errlog.WithFields(logrus.Fields{
						"original_url":     req.URL.String(),
						"blocked_endpoint": endpoint,
					})
				}
			}
		},
	})

	req = req.WithContext(ctx)
	return no.inner.RoundTrip(req)
}

func isLocal(info httptrace.DNSDoneInfo) string {
	return "what was blocked"
}

func newLocalBlocker(trans http.RoundTripper, log logrus.FieldLogger) *noLocalTransport {
	if trans == nil {
		trans = http.DefaultTransport
	}

	ret := &noLocalTransport{
		inner:  trans,
		errlog: log.WithField("transport", "local_blocker"),
	}

	return ret
}

I think that it does less setting on the transport object. I am mostly afraid of some kind of concurrency nightmare in the transport.

func TestSafeHTTPClient(t *testing.T) {
client := &http.Client{}

counter := &countServer{}
Copy link
Member

Choose a reason for hiding this comment

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

I'd use the httptest lib instead. https://golang.org/pkg/net/http/httptest/#Server

http/http.go Outdated
}
}

func SafeHttpClient(client *http.Client) *http.Client {
Copy link
Member

Choose a reason for hiding this comment

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

s/Http/HTTP

@biilmann
Copy link
Member Author

I like that suggestion - plopped that implementation in there

@mheffner mheffner requested a review from rybit February 3, 2020 23:51
Copy link
Contributor

@mraerino mraerino left a comment

Choose a reason for hiding this comment

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

This only needs minor adjustments.
The tests have room for improvement in general.

Also, outer users should be able to allow localhost for testing:
https://github.com/netlify/gotrue/blob/22a973955d0644e0a9163dda4dd8667fce7fcfe7/api/hook_test.go#L48-L49

http/http.go Outdated

ctx = httptrace.WithClientTrace(ctx, &httptrace.ClientTrace{
ConnectStart: func(network, addr string) {
fmt.Printf("Checking network %v\n", addr)
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be removed because it pollutes logs

http/http.go Outdated

if isPrivateIP(ip) {
cancel()
fmt.Println("Canceleing dur to private ip range")
Copy link
Contributor

Choose a reason for hiding this comment

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

would be great to log these and previous errors on the errlog field of the noLocalTransport

@vbrown608
Copy link
Contributor

I'm going to update the tests a bit

@vbrown608 vbrown608 requested a review from mraerino February 4, 2020 16:20
Copy link
Contributor

@mraerino mraerino left a comment

Choose a reason for hiding this comment

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

This looks really good.

There is still one case it does not cover:
We want to be able to allow certain ips/ranges inside of tests in other packages.

I propose adding a variadic arg to SafeRountripper and SafeHTTPClient for blocks you want to allow.
I'm thinking of this signature:

func SafeHTTPClient(client *http.Client, log logrus.FieldLogger, allowedBlocks ...*net.IPNet) *http.Client {
...

Another way could be to expose a method on the roundtripper to allow blocks temporarily.

@mraerino
Copy link
Contributor

mraerino commented Feb 4, 2020

There also is a typo in SafeRountripper you know? 😛

@vbrown608
Copy link
Contributor

Ah, I thought you intended for that to be a follow-up (along with un-inlining this functionality in gotrue). I can put it in here.

@vbrown608 vbrown608 requested a review from mraerino February 4, 2020 22:21
Copy link
Contributor

@mraerino mraerino left a comment

Choose a reason for hiding this comment

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

🚢

@vbrown608 vbrown608 merged commit 0aa04a3 into master Feb 4, 2020
@vbrown608 vbrown608 deleted the safe-http-client branch February 4, 2020 23:13
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.

4 participants