Skip to content

Commit

Permalink
Recreate HTTP client on timeout error
Browse files Browse the repository at this point in the history
  • Loading branch information
ameshkov committed Jun 21, 2021
1 parent 368bde1 commit a7725e8
Showing 1 changed file with 13 additions and 4 deletions.
17 changes: 13 additions & 4 deletions upstream/upstream_doh.go
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"io/ioutil"
"net/http"
"os"
"sync"
"time"

Expand All @@ -17,11 +18,11 @@ import (
type dnsOverHTTPS struct {
boot *bootstrapper

// mu exists for lazy initialization purposes and protects client from
// clientGuard exists for lazy initialization purposes and protects client from
// data race during lazy initialization. It provides the exchange with
// invalid upstream possibility, which is needed for now. Should be
// refactored further.
mu sync.Mutex
clientGuard sync.Mutex

// The Client's Transport typically has internal state (cached TCP
// connections), so Clients should be reused instead of created as
Expand Down Expand Up @@ -69,6 +70,14 @@ func (p *dnsOverHTTPS) exchangeHTTPSClient(m *dns.Msg, client *http.Client) (*dn
defer resp.Body.Close()
}
if err != nil {
if os.IsTimeout(err) {
// If this is a timeout error, trying to forcibly re-create the HTTP client instance
// See https://github.com/AdguardTeam/AdGuardHome/issues/3217 for more details on this
p.clientGuard.Lock()
p.client = nil
p.clientGuard.Unlock()
}

return nil, errorx.Decorate(err, "couldn't do a GET request to '%s'", p.boot.URL)
}

Expand All @@ -95,8 +104,8 @@ func (p *dnsOverHTTPS) exchangeHTTPSClient(m *dns.Msg, client *http.Client) (*dn
func (p *dnsOverHTTPS) getClient() (c *http.Client, err error) {
startTime := time.Now()

p.mu.Lock()
defer p.mu.Unlock()
p.clientGuard.Lock()
defer p.clientGuard.Unlock()
if p.client != nil {
return p.client, nil
}
Expand Down

0 comments on commit a7725e8

Please sign in to comment.