Skip to content

Commit 438f472

Browse files
authored
Merge pull request moby#4300 from vvoland/http-fallback-insecure-host-0.12
[0.12 backport] util/resolver: Perform Insecure HTTPS + HTTP fallback in one `docker.RegistryHost`
2 parents b022d6d + bc12a9c commit 438f472

File tree

1 file changed

+47
-24
lines changed

1 file changed

+47
-24
lines changed

util/resolver/resolver.go

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ const (
2222
defaultPath = "/v2"
2323
)
2424

25-
func fillInsecureOpts(host string, c config.RegistryConfig, h docker.RegistryHost) ([]docker.RegistryHost, error) {
26-
var hosts []docker.RegistryHost
27-
25+
func fillInsecureOpts(host string, c config.RegistryConfig, h docker.RegistryHost) (*docker.RegistryHost, error) {
2826
tc, err := loadTLSConfig(c)
2927
if err != nil {
3028
return nil, err
@@ -40,33 +38,31 @@ func fillInsecureOpts(host string, c config.RegistryConfig, h docker.RegistryHos
4038
}
4139
}
4240

43-
if isHTTP {
44-
h2 := h
45-
h2.Scheme = "http"
46-
hosts = append(hosts, h2)
47-
}
41+
httpsTransport := newDefaultTransport()
42+
httpsTransport.TLSClientConfig = tc
43+
4844
if c.Insecure != nil && *c.Insecure {
4945
h2 := h
50-
transport := newDefaultTransport()
51-
transport.TLSClientConfig = tc
46+
47+
var transport http.RoundTripper = httpsTransport
48+
if isHTTP {
49+
transport = &httpFallback{super: transport}
50+
}
5251
h2.Client = &http.Client{
5352
Transport: tracing.NewTransport(transport),
5453
}
5554
tc.InsecureSkipVerify = true
56-
hosts = append(hosts, h2)
55+
return &h2, nil
56+
} else if isHTTP {
57+
h2 := h
58+
h2.Scheme = "http"
59+
return &h2, nil
5760
}
5861

59-
if len(hosts) == 0 {
60-
transport := newDefaultTransport()
61-
transport.TLSClientConfig = tc
62-
63-
h.Client = &http.Client{
64-
Transport: tracing.NewTransport(transport),
65-
}
66-
hosts = append(hosts, h)
62+
h.Client = &http.Client{
63+
Transport: tracing.NewTransport(httpsTransport),
6764
}
68-
69-
return hosts, nil
65+
return &h, nil
7066
}
7167

7268
func loadTLSConfig(c config.RegistryConfig) (*tls.Config, error) {
@@ -133,12 +129,12 @@ func NewRegistryConfig(m map[string]config.RegistryConfig) docker.RegistryHosts
133129
for _, rawMirror := range c.Mirrors {
134130
h := newMirrorRegistryHost(rawMirror)
135131
mirrorHost := h.Host
136-
hosts, err := fillInsecureOpts(mirrorHost, m[mirrorHost], h)
132+
host, err := fillInsecureOpts(mirrorHost, m[mirrorHost], h)
137133
if err != nil {
138134
return nil, err
139135
}
140136

141-
out = append(out, hosts...)
137+
out = append(out, *host)
142138
}
143139

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

161-
out = append(out, hosts...)
157+
out = append(out, *hosts)
158+
162159
return out, nil
163160
},
164161
docker.ConfigureDefaultRegistries(
@@ -210,3 +207,29 @@ func newDefaultTransport() *http.Transport {
210207
TLSNextProto: make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
211208
}
212209
}
210+
211+
type httpFallback struct {
212+
super http.RoundTripper
213+
fallback bool
214+
}
215+
216+
func (f *httpFallback) RoundTrip(r *http.Request) (*http.Response, error) {
217+
if !f.fallback {
218+
resp, err := f.super.RoundTrip(r)
219+
var tlsErr tls.RecordHeaderError
220+
if errors.As(err, &tlsErr) && string(tlsErr.RecordHeader[:]) == "HTTP/" {
221+
// Server gave HTTP response to HTTPS client
222+
f.fallback = true
223+
} else {
224+
return resp, err
225+
}
226+
}
227+
228+
plainHTTPUrl := *r.URL
229+
plainHTTPUrl.Scheme = "http"
230+
231+
plainHTTPRequest := *r
232+
plainHTTPRequest.URL = &plainHTTPUrl
233+
234+
return f.super.RoundTrip(&plainHTTPRequest)
235+
}

0 commit comments

Comments
 (0)