3232import java .util .List ;
3333import java .util .Map ;
3434import java .util .Objects ;
35+ import java .util .Optional ;
3536import java .util .function .Supplier ;
3637import land .oras .auth .AuthProvider ;
3738import land .oras .auth .AuthStoreAuthenticationProvider ;
@@ -200,8 +201,25 @@ public Tags getTags(ContainerRef containerRef) {
200201 URI uri = URI .create ("%s://%s" .formatted (getScheme (), ref .getTagsPath (this )));
201202 HttpClient .ResponseWrapper <String > response = client .get (
202203 uri , Map .of (Const .ACCEPT_HEADER , Const .DEFAULT_JSON_MEDIA_TYPE ), Scopes .of (this , ref ), authProvider );
204+ logResponse (response );
203205 handleError (response );
204- return JsonUtils .fromJson (response .response (), Tags .class );
206+ return JsonUtils .fromJson (response .response (), Tags .class )
207+ .withLast (getLastFromLink (response ).orElse (null ));
208+ }
209+
210+ @ Override
211+ public Tags getTags (ContainerRef containerRef , int n , @ Nullable String last ) {
212+ ContainerRef ref = containerRef .forRegistry (this ).checkBlocked (this );
213+ if (ref .isInsecure (this ) && !this .isInsecure ()) {
214+ return asInsecure ().getTags (containerRef );
215+ }
216+ URI uri = URI .create ("%s://%s" .formatted (getScheme (), ref .getTagsPath (this , n , last )));
217+ HttpClient .ResponseWrapper <String > response = client .get (
218+ uri , Map .of (Const .ACCEPT_HEADER , Const .DEFAULT_JSON_MEDIA_TYPE ), Scopes .of (this , ref ), authProvider );
219+ logResponse (response );
220+ handleError (response );
221+ return JsonUtils .fromJson (response .response (), Tags .class )
222+ .withLast (getLastFromLink (response ).orElse (null ));
205223 }
206224
207225 @ Override
@@ -215,6 +233,7 @@ && getRegistriesConf().isInsecure(ContainerRef.parse(registry).forRegistry(regis
215233 URI uri = URI .create ("%s://%s" .formatted (getScheme (), ref .getRepositoriesPath (this )));
216234 HttpClient .ResponseWrapper <String > response = client .get (
217235 uri , Map .of (Const .ACCEPT_HEADER , Const .DEFAULT_JSON_MEDIA_TYPE ), Scopes .of (this , ref ), authProvider );
236+ logResponse (response );
218237 handleError (response );
219238 return JsonUtils .fromJson (response .response (), Repositories .class );
220239 }
@@ -231,6 +250,7 @@ public Referrers getReferrers(ContainerRef containerRef, @Nullable ArtifactType
231250 URI uri = URI .create ("%s://%s" .formatted (getScheme (), ref .getReferrersPath (this , artifactType )));
232251 HttpClient .ResponseWrapper <String > response = client .get (
233252 uri , Map .of (Const .ACCEPT_HEADER , Const .DEFAULT_INDEX_MEDIA_TYPE ), Scopes .of (this , ref ), authProvider );
253+ logResponse (response );
234254 handleError (response );
235255 return JsonUtils .fromJson (response .response (), Referrers .class );
236256 }
@@ -968,6 +988,35 @@ ResolvedRegistry getResolvedHeaders(ContainerRef containerRef) {
968988 return new ResolvedRegistry (ref .getRegistry (), response .headers ());
969989 }
970990
991+ private Optional <String > getLastFromLink (HttpClient .ResponseWrapper <String > response ) {
992+ String linkHeader = response .headers ().get (Const .LINK_HEADER .toLowerCase ());
993+ if (linkHeader == null ) {
994+ return Optional .empty ();
995+ }
996+
997+ int start = linkHeader .indexOf ('<' );
998+ int end = linkHeader .indexOf ('>' , start + 1 );
999+ if (start == -1 || end == -1 ) {
1000+ return Optional .empty ();
1001+ }
1002+
1003+ String uri = linkHeader .substring (start + 1 , end );
1004+ int q = uri .indexOf ('?' );
1005+ if (q == -1 ) {
1006+ return Optional .empty ();
1007+ }
1008+
1009+ String query = uri .substring (q + 1 );
1010+ for (String param : query .split ("&" )) {
1011+ int eq = param .indexOf ('=' );
1012+ if (eq > 0 && "last" .equals (param .substring (0 , eq ))) {
1013+ return Optional .of (param .substring (eq + 1 ));
1014+ }
1015+ }
1016+
1017+ return Optional .empty ();
1018+ }
1019+
9711020 /**
9721021 * Holds a resolved registry to avoid resolution on every request (specially like blob)
9731022 * @param registry The registry URL
0 commit comments