X Tutup
Skip to content

Commit 4c4a7ac

Browse files
committed
Merge pull request #298 from docker-java/issue-290
Fix issue #290
2 parents ae107a5 + 78f6caa commit 4c4a7ac

File tree

2 files changed

+188
-24
lines changed

2 files changed

+188
-24
lines changed

src/main/java/com/github/dockerjava/core/NameParser.java

Lines changed: 62 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,24 @@
55

66
import java.util.regex.Pattern;
77

8+
import org.apache.commons.lang.builder.EqualsBuilder;
9+
import org.apache.commons.lang.builder.ToStringBuilder;
10+
import org.apache.commons.lang.builder.ToStringStyle;
11+
812
import com.github.dockerjava.api.model.AuthConfig;
913

1014
public class NameParser {
1115

12-
private static final Pattern VALID_HEX_PATTERN = Pattern.compile("^([a-f0-9]{64})$");
16+
private static final int RepositoryNameTotalLengthMax = 255;
17+
18+
private static final Pattern RepositoryNameComponentRegexp = Pattern.compile("[a-z0-9]+(?:[._-][a-z0-9]+)*");
1319

14-
private static final Pattern VALID_NAMESPACE_PATTERN = Pattern.compile("^([a-z0-9_]{4,30})$");
20+
private static final Pattern RepositoryNameComponentAnchoredRegexp = Pattern.compile("^"
21+
+ RepositoryNameComponentRegexp.pattern() + "$");
1522

16-
private static final Pattern VALID_REPO_PATTERN = Pattern.compile("^([a-z0-9-_.]+)$");
23+
// private static final Pattern RepositoryNameRegexp = Pattern.compile("(?:" +
24+
// RepositoryNameComponentRegexp.pattern()
25+
// + "/)*" + RepositoryNameComponentRegexp.pattern());
1726

1827
public static ReposTag parseRepositoryTag(String name) {
1928
int n = name.lastIndexOf(':');
@@ -36,30 +45,43 @@ public ReposTag(String repos, String tag) {
3645
this.repos = repos;
3746
this.tag = tag;
3847
}
39-
}
4048

41-
public static void validateRepositoryName(String repositoryName) {
42-
String name;
43-
String namespace;
44-
String[] nameParts = repositoryName.split("/", 2);
45-
if (nameParts.length < 2) {
46-
namespace = "library";
47-
name = nameParts[0];
48-
if (VALID_HEX_PATTERN.matcher(name).matches()) {
49-
throw new InvalidRepositoryNameException(String.format(
50-
"Invalid repository name (%s), cannot specify 64-byte hexadecimal strings", name));
49+
@Override
50+
public boolean equals(Object obj) {
51+
if (obj instanceof ReposTag) {
52+
ReposTag other = (ReposTag) obj;
53+
return new EqualsBuilder().append(repos, other.repos).append(tag, other.tag).isEquals();
54+
} else {
55+
return false;
5156
}
52-
} else {
53-
namespace = nameParts[0];
54-
name = nameParts[1];
5557
}
56-
if (!VALID_NAMESPACE_PATTERN.matcher(namespace).matches()) {
57-
throw new InvalidRepositoryNameException(String.format(
58-
"Invalid namespace name (%s), only [a-z0-9_] are allowed, size between 4 and 30", namespace));
58+
59+
@Override
60+
public String toString() {
61+
return ToStringBuilder.reflectionToString(this, ToStringStyle.SIMPLE_STYLE);
62+
}
63+
}
64+
65+
/*
66+
* see https://github.com/docker/distribution/blob/master/registry/api/v2/names.go
67+
*/
68+
public static void validateRepoName(String name) {
69+
if (name.isEmpty()) {
70+
throw new InvalidRepositoryNameException(String.format("Invalid empty repository name \"%s\"", name));
5971
}
60-
if (!VALID_REPO_PATTERN.matcher(name).matches()) {
61-
throw new InvalidRepositoryNameException(String.format(
62-
"Invalid repository name (%s), only [a-z0-9-_.] are allowed", name));
72+
73+
if (name.length() > RepositoryNameTotalLengthMax) {
74+
throw new InvalidRepositoryNameException(String.format("Repository name \"%s\" is longer than "
75+
+ RepositoryNameTotalLengthMax, name));
76+
}
77+
78+
String[] components = name.split("/");
79+
80+
for (String component : components) {
81+
if (!RepositoryNameComponentAnchoredRegexp.matcher(component).matches()) {
82+
throw new InvalidRepositoryNameException(String.format(
83+
"Repository name \"%s\" is invalid. Component: %s", name, component));
84+
}
6385
}
6486
}
6587

@@ -82,7 +104,7 @@ public static HostnameReposName resolveRepositoryName(String reposName) {
82104
reposName));
83105
}
84106

85-
validateRepositoryName(reposName);
107+
validateRepoName(reposName);
86108
return new HostnameReposName(hostname, reposName);
87109
}
88110

@@ -96,5 +118,21 @@ public HostnameReposName(String hostname, String reposName) {
96118
this.reposName = reposName;
97119
}
98120

121+
@Override
122+
public boolean equals(Object obj) {
123+
if (obj instanceof HostnameReposName) {
124+
HostnameReposName other = (HostnameReposName) obj;
125+
return new EqualsBuilder().append(hostname, other.hostname).append(reposName, other.reposName)
126+
.isEquals();
127+
} else {
128+
return false;
129+
}
130+
}
131+
132+
@Override
133+
public String toString() {
134+
return ToStringBuilder.reflectionToString(this, ToStringStyle.SIMPLE_STYLE);
135+
}
136+
99137
}
100138
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Created on 17.08.2015
3+
*/
4+
package com.github.dockerjava.core;
5+
6+
import org.apache.commons.lang.StringUtils;
7+
import org.testng.annotations.Test;
8+
9+
import static org.testng.Assert.assertEquals;
10+
11+
import com.github.dockerjava.api.model.AuthConfig;
12+
import com.github.dockerjava.core.NameParser.HostnameReposName;
13+
import com.github.dockerjava.core.NameParser.ReposTag;
14+
15+
/**
16+
*
17+
*
18+
* @author marcus
19+
*
20+
*/
21+
public class NameParserTest {
22+
23+
@Test
24+
public void testValidateRepoName() throws Exception {
25+
NameParser.validateRepoName("repository");
26+
NameParser.validateRepoName("namespace/repository");
27+
NameParser.validateRepoName("namespace-with-dashes/repository");
28+
NameParser.validateRepoName("namespace/repository-with-dashes");
29+
NameParser.validateRepoName("namespace.with.dots/repository");
30+
NameParser.validateRepoName("namespace/repository.with.dots");
31+
NameParser.validateRepoName("namespace_with_underscores/repository");
32+
NameParser.validateRepoName("namespace/repository_with_underscores");
33+
}
34+
35+
@Test(expectedExceptions = InvalidRepositoryNameException.class)
36+
public void testValidateRepoNameEmpty() throws Exception {
37+
NameParser.validateRepoName("");
38+
}
39+
40+
@Test(expectedExceptions = InvalidRepositoryNameException.class)
41+
public void testValidateRepoNameExceedsMaxLength() throws Exception {
42+
NameParser.validateRepoName(StringUtils.repeat("repository", 255));
43+
}
44+
45+
@Test(expectedExceptions = InvalidRepositoryNameException.class)
46+
public void testValidateRepoNameEndWithDash() throws Exception {
47+
NameParser.validateRepoName("repository-");
48+
}
49+
50+
@Test(expectedExceptions = InvalidRepositoryNameException.class)
51+
public void testValidateRepoNameStartWithDash() throws Exception {
52+
NameParser.validateRepoName("-repository");
53+
}
54+
55+
@Test(expectedExceptions = InvalidRepositoryNameException.class)
56+
public void testValidateRepoNameEndWithDot() throws Exception {
57+
NameParser.validateRepoName("repository.");
58+
}
59+
60+
@Test(expectedExceptions = InvalidRepositoryNameException.class)
61+
public void testValidateRepoNameStartWithDot() throws Exception {
62+
NameParser.validateRepoName(".repository");
63+
}
64+
65+
@Test(expectedExceptions = InvalidRepositoryNameException.class)
66+
public void testValidateRepoNameEndWithUnderscore() throws Exception {
67+
NameParser.validateRepoName("repository_");
68+
}
69+
70+
@Test(expectedExceptions = InvalidRepositoryNameException.class)
71+
public void testValidateRepoNameStartWithUnderscore() throws Exception {
72+
NameParser.validateRepoName("_repository");
73+
}
74+
75+
@Test(expectedExceptions = InvalidRepositoryNameException.class)
76+
public void testValidateRepoNameWithColon() throws Exception {
77+
NameParser.validateRepoName("repository:with:colon");
78+
}
79+
80+
@Test
81+
public void testResolveSimpleRepositoryName() throws Exception {
82+
HostnameReposName resolved = NameParser.resolveRepositoryName("repository");
83+
assertEquals(resolved, new HostnameReposName(AuthConfig.DEFAULT_SERVER_ADDRESS, "repository"));
84+
}
85+
86+
@Test
87+
public void testResolveRepositoryNameWithNamespace() throws Exception {
88+
HostnameReposName resolved = NameParser.resolveRepositoryName("namespace/repository");
89+
assertEquals(resolved, new HostnameReposName(AuthConfig.DEFAULT_SERVER_ADDRESS, "namespace/repository"));
90+
}
91+
92+
@Test
93+
public void testResolveRepositoryNameWithNamespaceAndHostname() throws Exception {
94+
HostnameReposName resolved = NameParser.resolveRepositoryName("localhost:5000/namespace/repository");
95+
assertEquals(resolved, new HostnameReposName("localhost:5000", "namespace/repository"));
96+
}
97+
98+
@Test(expectedExceptions = InvalidRepositoryNameException.class)
99+
public void testResolveRepositoryNameWithIndex() throws Exception {
100+
NameParser.resolveRepositoryName("index.docker.io/repository");
101+
}
102+
103+
@Test
104+
public void testResolveReposTagWithoutTagSimple() throws Exception {
105+
ReposTag resolved = NameParser.parseRepositoryTag("repository");
106+
assertEquals(resolved, new ReposTag("repository", ""));
107+
108+
resolved = NameParser.parseRepositoryTag("namespace/repository");
109+
assertEquals(resolved, new ReposTag("namespace/repository", ""));
110+
111+
resolved = NameParser.parseRepositoryTag("localhost:5000/namespace/repository");
112+
assertEquals(resolved, new ReposTag("localhost:5000/namespace/repository", ""));
113+
}
114+
115+
@Test
116+
public void testResolveReposTagWithTag() throws Exception {
117+
ReposTag resolved = NameParser.parseRepositoryTag("repository:tag");
118+
assertEquals(resolved, new ReposTag("repository", "tag"));
119+
120+
resolved = NameParser.parseRepositoryTag("namespace/repository:tag");
121+
assertEquals(resolved, new ReposTag("namespace/repository", "tag"));
122+
123+
resolved = NameParser.parseRepositoryTag("localhost:5000/namespace/repository:tag");
124+
assertEquals(resolved, new ReposTag("localhost:5000/namespace/repository", "tag"));
125+
}
126+
}

0 commit comments

Comments
 (0)
X Tutup