From 85110ea2648729e24f72471a8534070ee9f03564 Mon Sep 17 00:00:00 2001 From: Myles Horton Date: Tue, 6 Oct 2015 13:35:48 -0700 Subject: [PATCH] retry requests to get passed occasional 403 errors closes #3238 --- .../getlantern/flashlight/util/http.go | 19 +++++++++++------- src/github.com/getlantern/fronted/direct.go | 20 ++++++++++++++++++- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/github.com/getlantern/flashlight/util/http.go b/src/github.com/getlantern/flashlight/util/http.go index 935dd76e2c..637aea19c2 100644 --- a/src/github.com/getlantern/flashlight/util/http.go +++ b/src/github.com/getlantern/flashlight/util/http.go @@ -95,32 +95,35 @@ func (df *dualFetcher) Do(req *http.Request) (*http.Response, error) { responses := make(chan *http.Response, 2) errs := make(chan error, 2) - request := func(client HTTPFetcher, req *http.Request) bool { + request := func(client HTTPFetcher, req *http.Request) error { if resp, err := client.Do(req); err != nil { log.Errorf("Could not complete request with: %v, %v", frontedUrl, err) errs <- err + return err } else { if success(resp) { log.Debugf("Got successful HTTP call!") responses <- resp - return true + return nil } else { // If the local proxy can't connect to any upstread proxies, for example, // it will return a 502. - errs <- fmt.Errorf("Bad response code: %v", resp.StatusCode) + err := fmt.Errorf("Bad response code: %v", resp.StatusCode) + errs <- err + return err } } - return false } go func() { - client := direct.NewDirectHttpClient() if req, err := http.NewRequest("GET", frontedUrl, nil); err != nil { log.Errorf("Could not create request for: %v, %v", frontedUrl, err) errs <- err } else { log.Debug("Sending request via DDF") - if request(client, req) { + if err := request(direct, req); err != nil { + log.Errorf("Fronted request failed: %v", err) + } else { log.Debug("Fronted request succeeded") } } @@ -131,7 +134,9 @@ func (df *dualFetcher) Do(req *http.Request) (*http.Response, error) { errs <- err } else { log.Debug("Sending chained request") - if request(client, req) { + if err := request(client, req); err != nil { + log.Errorf("Chained request failed %v", err) + } else { log.Debug("Switching to chained fronter for future requests since it succeeded") df.cf.fetcher = &chainedFetcher{} } diff --git a/src/github.com/getlantern/fronted/direct.go b/src/github.com/getlantern/fronted/direct.go index 65c9a49d72..2e356b16b3 100644 --- a/src/github.com/getlantern/fronted/direct.go +++ b/src/github.com/getlantern/fronted/direct.go @@ -106,7 +106,7 @@ func (ddf *directTransport) RoundTrip(req *http.Request) (resp *http.Response, e return ddf.Transport.RoundTrip(norm) } -// NewHttpClient creates a new http.Client that does direct domain fronting. +// NewDirectHttpClient creates a new http.Client that does direct domain fronting. func (d *direct) NewDirectHttpClient() *http.Client { trans := &directTransport{} trans.Dial = d.Dial @@ -117,6 +117,24 @@ func (d *direct) NewDirectHttpClient() *http.Client { } } +// Do continually retries a given request until it succeeds because some fronting providers +// will return a 403 for some domains. +func (d *direct) Do(req *http.Request) (*http.Response, error) { + for i := 0; i < 6; i++ { + client := d.NewDirectHttpClient() + if resp, err := client.Do(req); err != nil { + log.Errorf("Could not complete request %v", err) + continue + } else if resp.StatusCode > 199 && resp.StatusCode < 400 { + return resp, err + } else { + _ = resp.Body.Close() + continue + } + } + return nil, errors.New("Could not complete request even with retries") +} + // Dial persistently dials masquerades until one succeeds. func (d *direct) Dial(network, addr string) (net.Conn, error) { for i := 0; i < 40; i++ {