Skip to content

Commit

Permalink
util/resolver: Http fallback in the same host
Browse files Browse the repository at this point in the history
If both Insecure and PlainHTTP is requested for the host, use a
transport that falls back to HTTP in case of an HTTP request to a HTTPS
client error.

This also changes the order - before that an HTTP connection was
attempted first. Now an HTTPS connection with insecure TLS check will be
attempted first and will only fallback to HTTP if the former fails.

This fixes push to an insecure HTTPS-only registry.

Signed-off-by: Paweł Gronowski <[email protected]>
  • Loading branch information
vvoland committed Oct 3, 2023
1 parent b9fcd76 commit 1096d71
Showing 1 changed file with 38 additions and 7 deletions.
45 changes: 38 additions & 7 deletions util/resolver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,25 @@ 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)
} else if isHTTP {
h2 := h
h2.Scheme = "http"
hosts = append(hosts, h2)
}

if len(hosts) == 0 {
Expand Down Expand Up @@ -210,3 +215,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 1096d71

Please sign in to comment.