@@ -179,7 +179,8 @@ describe("transitive-manifest-risk-report", () => {
179179 } ) ;
180180
181181 it ( "fetches full npm packuments for the requested manifest version" , async ( ) => {
182- const fetchCalls : Array < { url : string ; accept : string | null } > = [ ] ;
182+ const fetchCalls : Array < { url : string ; accept : string | null ; signal : AbortSignal | null } > =
183+ [ ] ;
183184 const manifest = await fetchNpmManifest ( {
184185 packageName : "@scope/package" ,
185186 version : "1.0.0" ,
@@ -188,6 +189,7 @@ describe("transitive-manifest-risk-report", () => {
188189 fetchCalls . push ( {
189190 url : String ( url ) ,
190191 accept : new Headers ( init ?. headers ) . get ( "accept" ) ,
192+ signal : init ?. signal instanceof AbortSignal ? init . signal : null ,
191193 } ) ;
192194 return new Response (
193195 JSON . stringify ( {
@@ -216,6 +218,7 @@ describe("transitive-manifest-risk-report", () => {
216218 {
217219 url : "https://registry.example.test/@scope%2fpackage" ,
218220 accept : "application/json" ,
221+ signal : expect . any ( AbortSignal ) ,
219222 } ,
220223 ] ) ;
221224 expect ( manifest ) . toEqual ( {
@@ -231,6 +234,37 @@ describe("transitive-manifest-risk-report", () => {
231234 } ) ;
232235 } ) ;
233236
237+ it ( "cancels stalled npm registry body reads when the request aborts" , async ( ) => {
238+ const controller = new AbortController ( ) ;
239+ let canceled = false ;
240+ const response = {
241+ headers : new Headers ( ) ,
242+ body : {
243+ getReader ( ) {
244+ return {
245+ read ( ) {
246+ return new Promise < ReadableStreamReadResult < Uint8Array > > ( ( ) => { } ) ;
247+ } ,
248+ async cancel ( ) {
249+ canceled = true ;
250+ } ,
251+ releaseLock ( ) {
252+ throw new Error ( "releaseLock should not run while a read is pending" ) ;
253+ } ,
254+ } ;
255+ } ,
256+ } ,
257+ } as unknown as Response ;
258+
259+ const readPromise = readBoundedNpmRegistryText ( response , 8 , {
260+ signal : controller . signal ,
261+ } ) ;
262+ controller . abort ( new Error ( "npm registry request timed out" ) ) ;
263+
264+ await expect ( readPromise ) . rejects . toThrow ( "npm registry request timed out" ) ;
265+ expect ( canceled ) . toBe ( true ) ;
266+ } ) ;
267+
234268 it ( "rejects npm registry bodies that exceed the content-length cap" , async ( ) => {
235269 let canceled = false ;
236270 const response = new Response (
@@ -247,7 +281,7 @@ describe("transitive-manifest-risk-report", () => {
247281 ) ;
248282
249283 await expect ( readBoundedNpmRegistryText ( response , 8 ) ) . rejects . toThrow (
250- "npm registry response exceeded 8 bytes (content-length 12) " ,
284+ "npm registry response exceeded 8 bytes" ,
251285 ) ;
252286 expect ( canceled ) . toBe ( true ) ;
253287 } ) ;
@@ -260,7 +294,7 @@ describe("transitive-manifest-risk-report", () => {
260294 } ) ;
261295
262296 await expect ( readBoundedNpmRegistryText ( response , 8 ) ) . rejects . toThrow (
263- "npm registry response exceeded 8 bytes (content-length 12) " ,
297+ "npm registry response exceeded 8 bytes" ,
264298 ) ;
265299 } ) ;
266300
@@ -306,7 +340,7 @@ describe("transitive-manifest-risk-report", () => {
306340 ) ;
307341
308342 await expect ( readBoundedNpmRegistryText ( response , 8 ) ) . rejects . toThrow (
309- "npm registry response exceeded 8 bytes while reading response body " ,
343+ "npm registry response exceeded 8 bytes" ,
310344 ) ;
311345 } ) ;
312346} ) ;
0 commit comments