Skip to content

Commit f5a62f1

Browse files
committed
Rewrite any prefix subdomain like *.example.com
Signed-off-by: Valentin Delaye <jonesbusy@users.noreply.github.com>
1 parent 9a83af5 commit f5a62f1

2 files changed

Lines changed: 64 additions & 7 deletions

File tree

src/main/java/land/oras/auth/RegistriesConf.java

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,19 +197,41 @@ public ContainerRef rewrite(ContainerRef ref) {
197197
return ref;
198198
}
199199
// No rewrite possible if location and prefix are not set
200-
String registry = matchingConfig.get().location();
200+
String location = matchingConfig.get().location();
201201
String prefix = matchingConfig.get().prefix();
202-
if (registry == null || registry.isBlank() || prefix == null || prefix.isBlank()) {
202+
if (location == null || location.isBlank() || prefix == null || prefix.isBlank()) {
203203
return ref;
204204
}
205205
String currentRefString = ref.toString();
206-
String rewrittenRefString = currentRefString.replaceFirst(prefix, registry);
206+
String rewrittenRefString;
207+
208+
// Replace all subdomain if prefix starts with "*." (e.g., *.example.com → my-registry.com)
209+
if (prefix.startsWith("*.")) {
210+
211+
// The subdomain replacement can include an optional path
212+
int firtSlashIndex = prefix.indexOf('/');
213+
String prefixPath = firtSlashIndex < 0 ? "" : prefix.substring(firtSlashIndex);
214+
215+
// Remove matched host + optional prefixPath
216+
String remainder = currentRefString.substring(ref.getRegistry().length());
217+
if (!prefixPath.isEmpty() && remainder.startsWith(prefixPath)) {
218+
remainder = remainder.substring(prefixPath.length());
219+
}
220+
221+
rewrittenRefString = location + remainder;
222+
}
223+
224+
// Just replace the prefix with the location (e.g., docker.io/library → my-registry.com/library)
225+
else {
226+
rewrittenRefString = location + currentRefString.substring(prefix.length());
227+
}
228+
207229
LOG.debug(
208230
"Rewriting container reference from '{}' to '{}' using registry config with prefix '{}' and location '{}'",
209231
currentRefString,
210232
rewrittenRefString,
211233
prefix,
212-
registry);
234+
location);
213235
return ContainerRef.parse(rewrittenRefString);
214236
}
215237

@@ -248,14 +270,25 @@ private boolean matches(ContainerRef ref, @Nullable String prefix) {
248270

249271
// No path restriction → host-only match
250272
if (p.path().isEmpty()) {
273+
LOG.debug("Found registry table '{}'", p);
251274
return true;
252275
}
253276

254277
// Path prefix match (namespace/repo)
255278
String refPath = String.join("/", ref.getNamespace()) + "/" + ref.getRepository();
256-
return refPath.equals(p.path()) || refPath.startsWith(p.path() + "/");
279+
boolean result = refPath.equals(p.path()) || refPath.startsWith(p.path() + "/");
280+
if (result) {
281+
LOG.debug("Found registry table '{}' matching path '{}'", p, refPath);
282+
}
283+
return result;
257284
}
258285

286+
/**
287+
* Check if the given host matches the specified prefix host, which can be a specific hostname or a wildcard pattern (e.g., *.example.com).
288+
* @param host the host to check for a match against the prefix host, which is the host component of the prefix.
289+
* @param prefixHost the prefix host to match against, which can be a specific hostname or a wildcard pattern (e.g., *.example.com).
290+
* @return true if the host matches the prefix host, false otherwise.
291+
*/
259292
private boolean hostMatches(String host, String prefixHost) {
260293
if (prefixHost.startsWith("*.")) {
261294
String domain = prefixHost.substring(2);

src/test/java/land/oras/ContainerRefTest.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import land.oras.exception.OrasException;
2828
import land.oras.utils.SupportedAlgorithm;
2929
import org.junit.jupiter.api.BeforeAll;
30-
import org.junit.jupiter.api.Disabled;
3130
import org.junit.jupiter.api.Test;
3231
import org.junit.jupiter.api.io.TempDir;
3332
import org.junit.jupiter.api.parallel.Execution;
@@ -136,7 +135,6 @@ void shouldDetermineFromAlias() throws Exception {
136135
}
137136

138137
@Test
139-
@Disabled("Not implemented yet")
140138
void shouldRewriteAllSubdomainToLocalProxy() throws Exception {
141139

142140
// language=toml
@@ -145,6 +143,10 @@ void shouldRewriteAllSubdomainToLocalProxy() throws Exception {
145143
[[registry]]
146144
prefix = "*.example.com"
147145
location = "localhost:5000/example-com"
146+
147+
[[registry]]
148+
prefix = "*.otherexample.io/library"
149+
location = "localhost:5001/docker"
148150
""";
149151

150152
Files.writeString(homeDir3.resolve(".config").resolve("containers").resolve("registries.conf"), config);
@@ -153,8 +155,30 @@ void shouldRewriteAllSubdomainToLocalProxy() throws Exception {
153155
.set("HOME", homeDir3.toAbsolutePath().toString())
154156
.execute(() -> {
155157
Registry registry = Registry.builder().defaults().build();
158+
159+
// One subdomain
156160
ContainerRef containerRef = ContainerRef.parse("toto.example.com/library/alpine:latest");
157161
assertEquals("localhost:5000", containerRef.getEffectiveRegistry(registry));
162+
ContainerRef newRef = registry.getRegistriesConf().rewrite(containerRef);
163+
assertEquals("localhost:5000/example-com/library/alpine:latest", newRef.toString());
164+
165+
// Several subdomain
166+
containerRef = ContainerRef.parse("test.foobar.example.com/library/alpine:latest");
167+
assertEquals("localhost:5000", containerRef.getEffectiveRegistry(registry));
168+
newRef = registry.getRegistriesConf().rewrite(containerRef);
169+
assertEquals("localhost:5000/example-com/library/alpine:latest", newRef.toString());
170+
171+
// With path
172+
containerRef = ContainerRef.parse("test.otherexample.io/library/alpine:latest");
173+
assertEquals("localhost:5001", containerRef.getEffectiveRegistry(registry));
174+
newRef = registry.getRegistriesConf().rewrite(containerRef);
175+
assertEquals("localhost:5001/docker/alpine:latest", newRef.toString());
176+
177+
// No rewrite if library does not match
178+
containerRef = ContainerRef.parse("test.otherexample.io/foobar/alpine:latest");
179+
assertEquals("test.otherexample.io", containerRef.getEffectiveRegistry(registry));
180+
newRef = registry.getRegistriesConf().rewrite(containerRef);
181+
assertEquals("test.otherexample.io/foobar/alpine:latest", newRef.toString());
158182
});
159183
}
160184

0 commit comments

Comments
 (0)