@@ -330,7 +330,7 @@ v2Router.delete("/:name+/blobs/uploads/:id", async (req, env: Env) => {
330
330
331
331
// this is the first thing that the client asks for in an upload
332
332
v2Router . post ( "/:name+/blobs/uploads/" , async ( req , env : Env ) => {
333
- const { name } = req . params ;
333
+ const { name } = req . params ;
334
334
const [ uploadObject , err ] = await wrap < UploadObject | RegistryError , Error > ( env . REGISTRY_CLIENT . startUpload ( name ) ) ;
335
335
336
336
if ( err ) {
@@ -525,31 +525,49 @@ v2Router.get("/:name+/tags/list", async (req, env: Env) => {
525
525
526
526
const { n : nStr = 50 , last } = req . query ;
527
527
const n = + nStr ;
528
- if ( isNaN ( n ) ) {
528
+ if ( isNaN ( n ) || n <= 0 ) {
529
529
throw new ServerError ( "invalid 'n' parameter" , 400 ) ;
530
530
}
531
531
532
- const tags = await env . REGISTRY . list ( {
532
+ let tags = await env . REGISTRY . list ( {
533
533
prefix : `${ name } /manifests` ,
534
534
limit : n ,
535
535
startAfter : last ? `${ name } /manifests/${ last } ` : undefined ,
536
536
} ) ;
537
+ // Filter out sha256 manifest
538
+ let manifestTags = tags . objects . filter ( ( tag ) => ! tag . key . startsWith ( `${ name } /manifests/sha256:` ) ) ;
539
+ // If results are truncated and the manifest filter removed some result, extend the search to reach the n number of results expected by the client
540
+ while ( tags . objects . length > 0 && tags . truncated && manifestTags . length !== n ) {
541
+ tags = await env . REGISTRY . list ( {
542
+ prefix : `${ name } /manifests` ,
543
+ limit : n - manifestTags . length ,
544
+ cursor : tags . cursor ,
545
+ } ) ;
546
+ // Filter out sha256 manifest
547
+ manifestTags = manifestTags . concat (
548
+ tags . objects . filter ( ( tag ) => ! tag . key . startsWith ( `${ name } /manifests/sha256:` ) ) ,
549
+ ) ;
550
+ }
537
551
538
- const keys = tags . objects . map ( ( object ) => object . key . split ( "/" ) . pop ( ) ! ) ;
552
+ const keys = manifestTags . map ( ( object ) => object . key . split ( "/" ) . pop ( ) ! ) ;
539
553
const url = new URL ( req . url ) ;
540
554
url . searchParams . set ( "n" , `${ n } ` ) ;
541
555
url . searchParams . set ( "last" , keys . length ? keys [ keys . length - 1 ] : "" ) ;
556
+ const responseHeaders : { "Content-Type" : string ; "Link" ?: string } = {
557
+ "Content-Type" : "application/json" ,
558
+ } ;
559
+ // Only supply a next link if the previous result is truncated
560
+ if ( tags . truncated ) {
561
+ responseHeaders . Link = `${ url . toString ( ) } ; rel=next` ;
562
+ }
542
563
return new Response (
543
564
JSON . stringify ( {
544
565
name,
545
566
tags : keys ,
546
567
} ) ,
547
568
{
548
569
status : 200 ,
549
- headers : {
550
- "Content-Type" : "application/json" ,
551
- "Link" : `${ url . toString ( ) } ; rel=next` ,
552
- } ,
570
+ headers : responseHeaders ,
553
571
} ,
554
572
) ;
555
573
} ) ;
0 commit comments