11// Copyright (c) Microsoft Corporation. All rights reserved.
22// Licensed under the MIT License.
33
4- using Microsoft . PowerShell . PSResourceGet . UtilClasses ;
54using System ;
65using System . Collections ;
76using System . Collections . Generic ;
7+ using System . Collections . ObjectModel ;
88using System . IO ;
9- using System . Net . Http ;
10- using NuGet . Versioning ;
11- using System . Threading . Tasks ;
12- using System . Net ;
9+ using System . Linq ;
1310using System . Management . Automation ;
14- using Newtonsoft . Json . Linq ;
15- using Newtonsoft . Json ;
16- using System . Collections . ObjectModel ;
11+ using System . Net ;
12+ using System . Net . Http ;
1713using System . Net . Http . Headers ;
18- using System . Linq ;
19- using Microsoft . PowerShell . PSResourceGet . Cmdlets ;
20- using System . Text ;
2114using System . Security . Cryptography ;
15+ using System . Text ;
2216using System . Text . Json ;
17+ using System . Text . RegularExpressions ;
18+ using System . Threading . Tasks ;
19+ using Microsoft . PowerShell . PSResourceGet . Cmdlets ;
20+ using Microsoft . PowerShell . PSResourceGet . UtilClasses ;
21+ using Newtonsoft . Json ;
22+ using Newtonsoft . Json . Linq ;
23+ using NuGet . Versioning ;
2324
2425namespace Microsoft . PowerShell . PSResourceGet
2526{
@@ -688,7 +689,7 @@ internal JObject FindAllRepositories(string containerRegistryAccessToken, out Er
688689 _cmdletPassedIn . WriteDebug ( "In ContainerRegistryServerAPICalls::FindAllRepositories()" ) ;
689690 string repositoryListUrl = string . Format ( containerRegistryRepositoryListTemplate , Registry ) ;
690691 var defaultHeaders = GetDefaultHeaders ( containerRegistryAccessToken ) ;
691- return GetHttpResponseJObjectUsingDefaultHeaders ( repositoryListUrl , HttpMethod . Get , defaultHeaders , out errRecord ) ;
692+ return GetHttpResponseJObjectUsingDefaultHeaders ( repositoryListUrl , HttpMethod . Get , defaultHeaders , out errRecord , usePagination : true ) ;
692693 }
693694
694695 /// <summary>
@@ -937,7 +938,7 @@ internal async Task<HttpContent> GetHttpContentResponseJObject(string url, Colle
937938 /// <summary>
938939 /// Get response object when using default headers in the request.
939940 /// </summary>
940- internal JObject GetHttpResponseJObjectUsingDefaultHeaders ( string url , HttpMethod method , Collection < KeyValuePair < string , string > > defaultHeaders , out ErrorRecord errRecord )
941+ internal JObject GetHttpResponseJObjectUsingDefaultHeaders ( string url , HttpMethod method , Collection < KeyValuePair < string , string > > defaultHeaders , out ErrorRecord errRecord , bool usePagination = false )
941942 {
942943 _cmdletPassedIn . WriteDebug ( "In ContainerRegistryServerAPICalls::GetHttpResponseJObjectUsingDefaultHeaders()" ) ;
943944 try
@@ -946,7 +947,8 @@ internal JObject GetHttpResponseJObjectUsingDefaultHeaders(string url, HttpMetho
946947 HttpRequestMessage request = new HttpRequestMessage ( method , url ) ;
947948 SetDefaultHeaders ( defaultHeaders ) ;
948949
949- return SendRequestAsync ( request ) . GetAwaiter ( ) . GetResult ( ) ;
950+ var response = usePagination ? SendRequestAsyncWithPagination ( request ) : SendRequestAsync ( request ) ;
951+ return response . GetAwaiter ( ) . GetResult ( ) ;
950952 }
951953 catch ( ResourceNotFoundException e )
952954 {
@@ -1152,6 +1154,72 @@ private async Task<JObject> SendRequestAsync(HttpRequestMessage message)
11521154 return JsonConvert . DeserializeObject < JObject > ( await response . Content . ReadAsStringAsync ( ) ) ;
11531155 }
11541156
1157+ private async Task < JObject > SendRequestAsyncWithPagination ( HttpRequestMessage initialMessage )
1158+ {
1159+ HttpResponseMessage response ;
1160+ string nextUrl = initialMessage . RequestUri . ToString ( ) ;
1161+ string urlBase = initialMessage . RequestUri . Scheme + "://" + initialMessage . RequestUri . Host ;
1162+ JObject finalResult = new JObject ( ) ;
1163+ JArray allRepositories = new JArray ( ) ;
1164+
1165+ do
1166+ {
1167+ var message = new HttpRequestMessage ( HttpMethod . Get , nextUrl ) ;
1168+ try
1169+ {
1170+ response = await _sessionClient . SendAsync ( message ) ;
1171+ }
1172+ catch ( Exception e )
1173+ {
1174+ throw new SendRequestException ( $ "Error occurred while sending request to Container Registry server with: { e . GetType ( ) } '{ e . Message } '", e ) ;
1175+ }
1176+
1177+ switch ( response . StatusCode )
1178+ {
1179+ case HttpStatusCode . OK :
1180+ break ;
1181+ case HttpStatusCode . Unauthorized :
1182+ throw new UnauthorizedException ( $ "Response returned status code: { response . ReasonPhrase } .") ;
1183+ case HttpStatusCode . NotFound :
1184+ throw new ResourceNotFoundException ( $ "Response returned status code package: { response . ReasonPhrase } .") ;
1185+ default :
1186+ throw new Exception ( $ "Response returned error with status code { response . StatusCode } : { response . ReasonPhrase } .") ;
1187+ }
1188+
1189+ var content = await response . Content . ReadAsStringAsync ( ) ;
1190+ var json = JObject . Parse ( content ) ;
1191+ var repositories = json [ "repositories" ] as JArray ;
1192+ if ( repositories != null )
1193+ {
1194+ allRepositories . Merge ( repositories ) ;
1195+ }
1196+
1197+ // Check for Link header to continue pagination
1198+ if ( response . Headers . TryGetValues ( "Link" , out var linkHeaders ) )
1199+ {
1200+ var linkHeader = string . Join ( "," , linkHeaders ) ;
1201+ var match = Regex . Match ( linkHeader , @"<([^>]+)>;\s*rel=""next""" ) ;
1202+ var nextUrlPart = match . Success ? match . Groups [ 1 ] . Value : null ;
1203+ if ( ! string . IsNullOrEmpty ( nextUrlPart ) )
1204+ {
1205+ nextUrl = urlBase + nextUrlPart ;
1206+ }
1207+ else
1208+ {
1209+ nextUrl = null ;
1210+ }
1211+ }
1212+ else
1213+ {
1214+ nextUrl = null ;
1215+ }
1216+
1217+ } while ( ! string . IsNullOrEmpty ( nextUrl ) ) ;
1218+
1219+ finalResult [ "repositories" ] = allRepositories ;
1220+ return finalResult ;
1221+ }
1222+
11551223 /// <summary>
11561224 /// Send request to get response headers.
11571225 /// </summary>
0 commit comments