Skip to content

Commit 8507c7f

Browse files
authored
Merge pull request #7 from thaJeztah/cleanup_splitDockerDomain
2 parents a3fb784 + 89ee7ec commit 8507c7f

File tree

2 files changed

+77
-14
lines changed

2 files changed

+77
-14
lines changed

normalize.go

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -123,20 +123,51 @@ func ParseDockerRef(ref string) (Named, error) {
123123
// splitDockerDomain splits a repository name to domain and remote-name.
124124
// If no valid domain is found, the default domain is used. Repository name
125125
// needs to be already validated before.
126-
func splitDockerDomain(name string) (domain, remainder string) {
127-
i := strings.IndexRune(name, '/')
128-
if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != localhost && strings.ToLower(name[:i]) == name[:i]) {
129-
domain, remainder = defaultDomain, name
130-
} else {
131-
domain, remainder = name[:i], name[i+1:]
132-
}
133-
if domain == legacyDefaultDomain {
134-
domain = defaultDomain
135-
}
136-
if domain == defaultDomain && !strings.ContainsRune(remainder, '/') {
137-
remainder = officialRepoPrefix + remainder
138-
}
139-
return
126+
func splitDockerDomain(name string) (domain, remoteName string) {
127+
maybeDomain, maybeRemoteName, ok := strings.Cut(name, "/")
128+
if !ok {
129+
// Fast-path for single element ("familiar" names), such as "ubuntu"
130+
// or "ubuntu:latest". Familiar names must be handled separately, to
131+
// prevent them from being handled as "hostname:port".
132+
//
133+
// Canonicalize them as "docker.io/library/name[:tag]"
134+
135+
// FIXME(thaJeztah): account for bare "localhost" or "example.com" names, which SHOULD be considered a domain.
136+
return defaultDomain, officialRepoPrefix + name
137+
}
138+
139+
switch {
140+
case maybeDomain == localhost:
141+
// localhost is a reserved namespace and always considered a domain.
142+
domain, remoteName = maybeDomain, maybeRemoteName
143+
case maybeDomain == legacyDefaultDomain:
144+
// canonicalize the Docker Hub and legacy "Docker Index" domains.
145+
domain, remoteName = defaultDomain, maybeRemoteName
146+
case strings.ContainsAny(maybeDomain, ".:"):
147+
// Likely a domain or IP-address:
148+
//
149+
// - contains a "." (e.g., "example.com" or "127.0.0.1")
150+
// - contains a ":" (e.g., "example:5000", "::1", or "[::1]:5000")
151+
domain, remoteName = maybeDomain, maybeRemoteName
152+
case strings.ToLower(maybeDomain) != maybeDomain:
153+
// Uppercase namespaces are not allowed, so if the first element
154+
// is not lowercase, we assume it to be a domain-name.
155+
domain, remoteName = maybeDomain, maybeRemoteName
156+
default:
157+
// None of the above: it's not a domain, so use the default, and
158+
// use the name input the remote-name.
159+
domain, remoteName = defaultDomain, name
160+
}
161+
162+
if domain == defaultDomain && !strings.ContainsRune(remoteName, '/') {
163+
// Canonicalize "familiar" names, but only on Docker Hub, not
164+
// on other domains:
165+
//
166+
// "docker.io/ubuntu[:tag]" => "docker.io/library/ubuntu[:tag]"
167+
remoteName = officialRepoPrefix + remoteName
168+
}
169+
170+
return domain, remoteName
140171
}
141172

142173
// familiarizeName returns a shortened version of the name familiar

normalize_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ func TestValidateReferenceName(t *testing.T) {
1313
"docker/docker",
1414
"library/debian",
1515
"debian",
16+
"localhost/library/debian",
17+
"localhost/debian",
18+
"LOCALDOMAIN/library/debian",
19+
"LOCALDOMAIN/debian",
1620
"docker.io/docker/docker",
1721
"docker.io/library/debian",
1822
"docker.io/debian",
@@ -147,6 +151,34 @@ func TestParseRepositoryInfo(t *testing.T) {
147151
}
148152

149153
tests := []tcase{
154+
{
155+
RemoteName: "fooo",
156+
FamiliarName: "localhost/fooo",
157+
FullName: "localhost/fooo",
158+
AmbiguousName: "localhost/fooo",
159+
Domain: "localhost",
160+
},
161+
{
162+
RemoteName: "fooo/bar",
163+
FamiliarName: "localhost/fooo/bar",
164+
FullName: "localhost/fooo/bar",
165+
AmbiguousName: "localhost/fooo/bar",
166+
Domain: "localhost",
167+
},
168+
{
169+
RemoteName: "fooo",
170+
FamiliarName: "LOCALDOMAIN/fooo",
171+
FullName: "LOCALDOMAIN/fooo",
172+
AmbiguousName: "LOCALDOMAIN/fooo",
173+
Domain: "LOCALDOMAIN",
174+
},
175+
{
176+
RemoteName: "fooo/bar",
177+
FamiliarName: "LOCALDOMAIN/fooo/bar",
178+
FullName: "LOCALDOMAIN/fooo/bar",
179+
AmbiguousName: "LOCALDOMAIN/fooo/bar",
180+
Domain: "LOCALDOMAIN",
181+
},
150182
{
151183
RemoteName: "fooo/bar",
152184
FamiliarName: "fooo/bar",

0 commit comments

Comments
 (0)