diff --git a/registry/config.go b/registry/config.go index 14d000c745..218a12683a 100644 --- a/registry/config.go +++ b/registry/config.go @@ -298,12 +298,17 @@ func isCIDRMatch(cidrs []*registry.NetIPNet, URLHost string) bool { // // It is used by the daemon to validate the daemon configuration. func ValidateMirror(mirrorURL string) (string, error) { + // Fast path for missing scheme, as url.Parse splits by ":", which can + // cause the hostname to be considered the "scheme" when using "hostname:port". + if scheme, _, ok := strings.Cut(mirrorURL, "://"); !ok || scheme == "" { + return "", invalidParamf("invalid mirror: no scheme specified for %q: must use either 'https://' or 'http://'", mirrorURL) + } uri, err := url.Parse(mirrorURL) if err != nil { return "", invalidParamWrapf(err, "invalid mirror: %q is not a valid URI", mirrorURL) } if uri.Scheme != "http" && uri.Scheme != "https" { - return "", invalidParamf("invalid mirror: unsupported scheme %q in %q", uri.Scheme, uri) + return "", invalidParamf("invalid mirror: unsupported scheme %q in %q: must use either 'https://' or 'http://'", uri.Scheme, uri) } if uri.RawQuery != "" || uri.Fragment != "" { return "", invalidParamf("invalid mirror: query or fragment at end of the URI %q", uri) diff --git a/registry/config_test.go b/registry/config_test.go index 17a9a52d73..699e763be6 100644 --- a/registry/config_test.go +++ b/registry/config_test.go @@ -77,9 +77,17 @@ func TestValidateMirror(t *testing.T) { input: "!invalid!://%as%", expectedErr: `invalid mirror: "!invalid!://%as%" is not a valid URI: parse "!invalid!://%as%": first path segment in URL cannot contain colon`, }, + { + input: "mirror-1.example.com", + expectedErr: `invalid mirror: no scheme specified for "mirror-1.example.com": must use either 'https://' or 'http://'`, + }, + { + input: "mirror-1.example.com:5000", + expectedErr: `invalid mirror: no scheme specified for "mirror-1.example.com:5000": must use either 'https://' or 'http://'`, + }, { input: "ftp://mirror-1.example.com", - expectedErr: `invalid mirror: unsupported scheme "ftp" in "ftp://mirror-1.example.com"`, + expectedErr: `invalid mirror: unsupported scheme "ftp" in "ftp://mirror-1.example.com": must use either 'https://' or 'http://'`, }, { input: "http://mirror-1.example.com/?q=foo", @@ -235,7 +243,7 @@ func TestNewServiceConfig(t *testing.T) { opts: ServiceOptions{ Mirrors: []string{"example.com:5000"}, }, - errStr: `invalid mirror: unsupported scheme "example.com" in "example.com:5000"`, + errStr: `invalid mirror: no scheme specified for "example.com:5000": must use either 'https://' or 'http://'`, }, { doc: "valid mirror",