Skip to content

Commit

Permalink
Merge pull request #4299 from vvoland/http-fallback-insecure-host
Browse files Browse the repository at this point in the history
util/resolver: Perform Insecure HTTPS + HTTP fallback in one `docker.RegistryHost`
  • Loading branch information
tonistiigi authored Oct 12, 2023
2 parents 86e25b3 + 0f339a8 commit 4c93208
Showing 1 changed file with 47 additions and 24 deletions.
71 changes: 47 additions & 24 deletions util/resolver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ const (
defaultPath = "/v2"
)

func fillInsecureOpts(host string, c config.RegistryConfig, h docker.RegistryHost) ([]docker.RegistryHost, error) {
var hosts []docker.RegistryHost

func fillInsecureOpts(host string, c config.RegistryConfig, h docker.RegistryHost) (*docker.RegistryHost, error) {
tc, err := loadTLSConfig(c)
if err != nil {
return nil, err
Expand All @@ -40,33 +38,31 @@ func fillInsecureOpts(host string, c config.RegistryConfig, h docker.RegistryHos
}
}

if isHTTP {
h2 := h
h2.Scheme = "http"
hosts = append(hosts, h2)
}
httpsTransport := newDefaultTransport()
httpsTransport.TLSClientConfig = tc

if c.Insecure != nil && *c.Insecure {
h2 := h
transport := newDefaultTransport()
transport.TLSClientConfig = tc

var transport http.RoundTripper = httpsTransport
if isHTTP {
transport = &httpFallback{super: transport}
}
h2.Client = &http.Client{
Transport: tracing.NewTransport(transport),
}
tc.InsecureSkipVerify = true
hosts = append(hosts, h2)
return &h2, nil
} else if isHTTP {
h2 := h
h2.Scheme = "http"
return &h2, nil
}

if len(hosts) == 0 {
transport := newDefaultTransport()
transport.TLSClientConfig = tc

h.Client = &http.Client{
Transport: tracing.NewTransport(transport),
}
hosts = append(hosts, h)
h.Client = &http.Client{
Transport: tracing.NewTransport(httpsTransport),
}

return hosts, nil
return &h, nil
}

func loadTLSConfig(c config.RegistryConfig) (*tls.Config, error) {
Expand Down Expand Up @@ -133,12 +129,12 @@ func NewRegistryConfig(m map[string]config.RegistryConfig) docker.RegistryHosts
for _, rawMirror := range c.Mirrors {
h := newMirrorRegistryHost(rawMirror)
mirrorHost := h.Host
hosts, err := fillInsecureOpts(mirrorHost, m[mirrorHost], h)
host, err := fillInsecureOpts(mirrorHost, m[mirrorHost], h)
if err != nil {
return nil, err
}

out = append(out, hosts...)
out = append(out, *host)
}

if host == "docker.io" {
Expand All @@ -158,7 +154,8 @@ func NewRegistryConfig(m map[string]config.RegistryConfig) docker.RegistryHosts
return nil, err
}

out = append(out, hosts...)
out = append(out, *hosts)

return out, nil
},
docker.ConfigureDefaultRegistries(
Expand Down Expand Up @@ -210,3 +207,29 @@ func newDefaultTransport() *http.Transport {
TLSNextProto: make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
}
}

type httpFallback struct {
super http.RoundTripper
fallback bool
}

func (f *httpFallback) RoundTrip(r *http.Request) (*http.Response, error) {
if !f.fallback {
resp, err := f.super.RoundTrip(r)
var tlsErr tls.RecordHeaderError
if errors.As(err, &tlsErr) && string(tlsErr.RecordHeader[:]) == "HTTP/" {
// Server gave HTTP response to HTTPS client
f.fallback = true
} else {
return resp, err
}
}

plainHTTPUrl := *r.URL
plainHTTPUrl.Scheme = "http"

plainHTTPRequest := *r
plainHTTPRequest.URL = &plainHTTPUrl

return f.super.RoundTrip(&plainHTTPRequest)
}

0 comments on commit 4c93208

Please sign in to comment.