@@ -55,6 +55,7 @@ public partial class ApiController
5555 public IReservedNamespaceService ReservedNamespaceService { get ; set ; }
5656 public IPackageUploadService PackageUploadService { get ; set ; }
5757 public IPackageDeleteService PackageDeleteService { get ; set ; }
58+ public ISymbolPackageFileService SymbolPackageFileService { get ; set ; }
5859 public ISymbolPackageService SymbolPackageService { get ; set ; }
5960 public ISymbolPackageUploadService SymbolPackageUploadService { get ; set ; }
6061 public IContentObjectService ContentObjectService { get ; set ; }
@@ -85,6 +86,7 @@ public ApiController(
8586 IReservedNamespaceService reservedNamespaceService ,
8687 IPackageUploadService packageUploadService ,
8788 IPackageDeleteService packageDeleteService ,
89+ ISymbolPackageFileService symbolPackageFileService ,
8890 ISymbolPackageService symbolPackageService ,
8991 ISymbolPackageUploadService symbolPackageUploadService ,
9092 IContentObjectService contentObjectService )
@@ -109,6 +111,7 @@ public ApiController(
109111 ReservedNamespaceService = reservedNamespaceService ;
110112 PackageUploadService = packageUploadService ;
111113 StatisticsService = null ;
114+ SymbolPackageFileService = symbolPackageFileService ;
112115 SymbolPackageService = symbolPackageService ;
113116 SymbolPackageUploadService = symbolPackageUploadService ;
114117 ContentObjectService = contentObjectService ;
@@ -136,21 +139,35 @@ public ApiController(
136139 IReservedNamespaceService reservedNamespaceService ,
137140 IPackageUploadService packageUploadService ,
138141 IPackageDeleteService packageDeleteService ,
142+ ISymbolPackageFileService symbolPackageFileService ,
139143 ISymbolPackageService symbolPackageService ,
140144 ISymbolPackageUploadService symbolPackageUploadServivce ,
141145 IContentObjectService contentObjectService )
142146 : this ( apiScopeEvaluator , entitiesContext , packageService , packageFileService , userService , contentService ,
143147 indexingService , searchService , autoCuratePackage , statusService , messageService , auditingService ,
144148 configurationService , telemetryService , authenticationService , credentialBuilder , securityPolicies ,
145- reservedNamespaceService , packageUploadService , packageDeleteService , symbolPackageService , symbolPackageUploadServivce ,
146- contentObjectService )
149+ reservedNamespaceService , packageUploadService , packageDeleteService , symbolPackageFileService ,
150+ symbolPackageService , symbolPackageUploadServivce , contentObjectService )
147151 {
148152 StatisticsService = statisticsService ;
149153 }
150154
155+
156+ [ HttpGet ]
157+ [ ActionName ( "GetSymbolPackageApi" ) ]
158+ public virtual async Task < ActionResult > GetSymbolPackage ( string id , string version )
159+ {
160+ return await GetPackageInternal ( id , version , isSymbolPackage : true ) ;
161+ }
162+
151163 [ HttpGet ]
152164 [ ActionName ( "GetPackageApi" ) ]
153165 public virtual async Task < ActionResult > GetPackage ( string id , string version )
166+ {
167+ return await GetPackageInternal ( id , version , isSymbolPackage : false ) ;
168+ }
169+
170+ protected internal async Task < ActionResult > GetPackageInternal ( string id , string version , bool isSymbolPackage = false )
154171 {
155172 // some security paranoia about URL hacking somehow creating e.g. open redirects
156173 // validate user input: explicit calls to the same validators used during Package Registrations
@@ -160,61 +177,86 @@ public virtual async Task<ActionResult> GetPackage(string id, string version)
160177 return new HttpStatusCodeWithBodyResult ( HttpStatusCode . BadRequest , "The format of the package id is invalid" ) ;
161178 }
162179
163- // if version is non- null, check if it's semantically correct and normalize it.
164- if ( ! String . IsNullOrEmpty ( version ) )
180+ Package package = null ;
181+ try
165182 {
166- NuGetVersion dummy ;
167- if ( ! NuGetVersion . TryParse ( version , out dummy ) )
183+ if ( ! string . IsNullOrEmpty ( version ) )
168184 {
169- return new HttpStatusCodeWithBodyResult ( HttpStatusCode . BadRequest , "The package version is not a valid semantic version" ) ;
170- }
185+ // if version is non-null, check if it's semantically correct and normalize it.
186+ NuGetVersion dummy ;
187+ if ( ! NuGetVersion . TryParse ( version , out dummy ) )
188+ {
189+ return new HttpStatusCodeWithBodyResult ( HttpStatusCode . BadRequest , "The package version is not a valid semantic version" ) ;
190+ }
171191
172- // Normalize the version
173- version = NuGetVersionFormatter . Normalize ( version ) ;
174- }
175- else
176- {
177- // If version is null, get the latest version from the database.
178- // This ensures that on package restore scenario where version will be non null, we don't hit the database.
179- try
192+ // Normalize the version
193+ version = NuGetVersionFormatter . Normalize ( version ) ;
194+
195+ if ( isSymbolPackage )
196+ {
197+ package = PackageService . FindPackageByIdAndVersionStrict ( id , version ) ;
198+ }
199+ }
200+ else
180201 {
181- var package = PackageService . FindPackageByIdAndVersion (
202+ // If version is null, get the latest version from the database.
203+ // This ensures that on package restore scenario where version will be non null, we don't hit the database.
204+ package = PackageService . FindPackageByIdAndVersion (
182205 id ,
183206 version ,
184207 SemVerLevelKey . SemVer2 ,
185208 allowPrerelease : false ) ;
186209
187210 if ( package == null )
188211 {
189- return new HttpStatusCodeWithBodyResult ( HttpStatusCode . NotFound , String . Format ( CultureInfo . CurrentCulture , Strings . PackageWithIdAndVersionNotFound , id , version ) ) ;
212+ return new HttpStatusCodeWithBodyResult ( HttpStatusCode . NotFound , string . Format ( CultureInfo . CurrentCulture , Strings . PackageWithIdAndVersionNotFound , id , version ) ) ;
190213 }
191- version = package . NormalizedVersion ;
192214
215+ version = package . NormalizedVersion ;
193216 }
194- catch ( SqlException e )
195- {
196- QuietLog . LogHandledException ( e ) ;
217+ }
218+ catch ( SqlException e )
219+ {
220+ QuietLog . LogHandledException ( e ) ;
197221
198- // Database was unavailable and we don't have a version, return a 503
199- return new HttpStatusCodeWithBodyResult ( HttpStatusCode . ServiceUnavailable , Strings . DatabaseUnavailable_TrySpecificVersion ) ;
200- }
201- catch ( DataException e )
202- {
203- QuietLog . LogHandledException ( e ) ;
222+ // Database was unavailable and we don't have a version, return a 503
223+ return new HttpStatusCodeWithBodyResult ( HttpStatusCode . ServiceUnavailable , Strings . DatabaseUnavailable_TrySpecificVersion ) ;
224+ }
225+ catch ( DataException e )
226+ {
227+ QuietLog . LogHandledException ( e ) ;
204228
205- // Database was unavailable and we don't have a version, return a 503
206- return new HttpStatusCodeWithBodyResult ( HttpStatusCode . ServiceUnavailable , Strings . DatabaseUnavailable_TrySpecificVersion ) ;
207- }
229+ // Database was unavailable and we don't have a version, return a 503
230+ return new HttpStatusCodeWithBodyResult ( HttpStatusCode . ServiceUnavailable , Strings . DatabaseUnavailable_TrySpecificVersion ) ;
208231 }
209232
210- if ( ConfigurationService . Features . TrackPackageDownloadCountInLocalDatabase )
233+ if ( isSymbolPackage )
211234 {
212- await PackageService . IncrementDownloadCountAsync ( id , version ) ;
235+ var latestSymbolPackage = package ?
236+ . SymbolPackages
237+ . OrderByDescending ( sp => sp . Created )
238+ . FirstOrDefault ( ) ;
239+
240+ if ( latestSymbolPackage == null || latestSymbolPackage . StatusKey != PackageStatus . Available )
241+ {
242+ return new HttpStatusCodeWithBodyResult ( HttpStatusCode . NotFound , string . Format ( CultureInfo . CurrentCulture , Strings . SymbolsPackage_PackageNotAvailable , id , version ) ) ;
243+ }
244+
245+ return await SymbolPackageFileService . CreateDownloadSymbolPackageActionResultAsync (
246+ HttpContext . Request . Url ,
247+ id , version ) ;
213248 }
249+ else
250+ {
251+ if ( ConfigurationService . Features . TrackPackageDownloadCountInLocalDatabase )
252+ {
253+ await PackageService . IncrementDownloadCountAsync ( id , version ) ;
254+ }
214255
215- return await PackageFileService . CreateDownloadPackageActionResultAsync (
216- HttpContext . Request . Url ,
217- id , version ) ;
256+ return await PackageFileService . CreateDownloadPackageActionResultAsync (
257+ HttpContext . Request . Url ,
258+ id , version ) ;
259+ }
218260 }
219261
220262 [ HttpGet ]
@@ -303,7 +345,7 @@ private async Task<HttpStatusCodeWithBodyResult> VerifyPackageKeyInternalAsync(U
303345 if ( package == null )
304346 {
305347 return new HttpStatusCodeWithBodyResult (
306- HttpStatusCode . NotFound , String . Format ( CultureInfo . CurrentCulture , Strings . PackageWithIdAndVersionNotFound , id , version ) ) ;
348+ HttpStatusCode . NotFound , string . Format ( CultureInfo . CurrentCulture , Strings . PackageWithIdAndVersionNotFound , id , version ) ) ;
307349 }
308350
309351 // Write an audit record
@@ -806,7 +848,7 @@ public virtual async Task<ActionResult> DeletePackage(string id, string version)
806848 if ( package == null )
807849 {
808850 return new HttpStatusCodeWithBodyResult (
809- HttpStatusCode . NotFound , String . Format ( CultureInfo . CurrentCulture , Strings . PackageWithIdAndVersionNotFound , id , version ) ) ;
851+ HttpStatusCode . NotFound , string . Format ( CultureInfo . CurrentCulture , Strings . PackageWithIdAndVersionNotFound , id , version ) ) ;
810852 }
811853
812854 // Check if the current user's scopes allow listing/unlisting the current package ID
@@ -838,7 +880,7 @@ public virtual async Task<ActionResult> PublishPackage(string id, string version
838880 if ( package == null )
839881 {
840882 return new HttpStatusCodeWithBodyResult (
841- HttpStatusCode . NotFound , String . Format ( CultureInfo . CurrentCulture , Strings . PackageWithIdAndVersionNotFound , id , version ) ) ;
883+ HttpStatusCode . NotFound , string . Format ( CultureInfo . CurrentCulture , Strings . PackageWithIdAndVersionNotFound , id , version ) ) ;
842884 }
843885
844886 // Check if the current user's scopes allow listing/unlisting the current package ID
0 commit comments