Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions src/main/java/land/oras/Registry.java
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ private boolean hasBlob(ContainerRef containerRef) {
private HttpClient.ResponseWrapper<String> headBlob(ContainerRef containerRef) {
URI uri = URI.create(
"%s://%s".formatted(getScheme(), containerRef.forRegistry(this).getBlobsPath(this)));
LOG.debug("Checking blob existence with HEAD request to: {}", uri);
HttpClient.ResponseWrapper<String> response = client.head(
uri,
Map.of(Const.ACCEPT_HEADER, Const.APPLICATION_OCTET_STREAM_HEADER_VALUE),
Expand Down Expand Up @@ -561,8 +562,19 @@ public Manifest getManifest(ContainerRef containerRef) {
throw new OrasException(
"Expected manifest but got index. Probably a multi-platform image instead of artifact");
}
ManifestDescriptor manifestDescriptor = ManifestDescriptor.of(descriptor);
return Manifest.fromJson(descriptor.getJson()).withDescriptor(manifestDescriptor);
String json = descriptor.getJson();
String digest = descriptor.getDigest();
if (digest == null) {
LOG.debug("Digest missing from header, using from reference");
digest = containerRef.getDigest();
if (digest == null) {
LOG.debug("Digest missing from reference, computing from content");
digest = containerRef.getAlgorithm().digest(json.getBytes(StandardCharsets.UTF_8));
LOG.debug("Computed index digest: {}", digest);
}
}
ManifestDescriptor manifestDescriptor = ManifestDescriptor.of(descriptor, digest);
return Manifest.fromJson(json).withDescriptor(manifestDescriptor);
}

@Override
Expand Down Expand Up @@ -734,9 +746,13 @@ private void handleError(HttpClient.ResponseWrapper<?> responseWrapper) {
private void logResponse(HttpClient.ResponseWrapper<?> response) {
LOG.debug("Status Code: {}", response.statusCode());
LOG.debug("Headers: {}", response.headers());
String contentType = response.headers().get(Const.CONTENT_TYPE_HEADER.toLowerCase());
boolean isBinaryResponse = contentType != null && contentType.contains("octet-stream");
// Only log non-binary responses
if (response.response() instanceof String) {
if (response.response() instanceof String && !isBinaryResponse) {
LOG.debug("Response: {}", response.response());
} else {
LOG.debug("Not logging binary response of content type: {}", contentType);
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/main/java/land/oras/auth/HttpClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,10 @@ private <T> ResponseWrapper<T> redoRequest(
}
try {
builder = builder.setHeader(Const.AUTHORIZATION_HEADER, "Bearer " + bearerToken);
if (builder.build().method() == "HEAD") {
LOG.debug("Redoing HEAD request to GET with new token");
builder = builder.GET();
}
HttpResponse<T> newResponse = client.send(builder.build(), handler);

// Follow redirect
Expand Down
19 changes: 18 additions & 1 deletion src/test/java/land/oras/PublicECRITCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;

@Execution(ExecutionMode.CONCURRENT)
@Execution(ExecutionMode.SAME_THREAD) // Avoid 429 Too Many Requests for unauthenticated requests to public ECR
class PublicECRITCase {

@Test
Expand All @@ -44,4 +44,21 @@ void shouldPullAnonymousIndex() {
Index index2 = registry.getIndex(containerRef2);
assertNotNull(index2);
}

@Test
void shouldPullManifest() {
Registry registry = Registry.builder().build();
ContainerRef containerRef = ContainerRef.parse(
"public.ecr.aws/docker/library/alpine@sha256:59855d3dceb3ae53991193bd03301e082b2a7faa56a514b03527ae0ec2ce3a95");
Manifest manifest = registry.getManifest(containerRef);
assertNotNull(manifest);
}

@Test
void shouldPullLayer() {
Registry registry = Registry.builder().build();
ContainerRef containerRef = ContainerRef.parse(
"public.ecr.aws/docker/library/alpine@sha256:589002ba0eaed121a1dbf42f6648f29e5be55d5c8a6ee0f8eaa0285cc21ac153");
registry.getBlob(containerRef);
}
}