55 */
66
77var Fetch = {
8- xhrs : [ ] ,
8+ // Map of integer fetch id to XHR request object
9+ xhrs : { } ,
910
1011 // The web worker that runs proxied file I/O requests. (this field is populated on demand, start as undefined to save code size)
1112 // worker: undefined,
@@ -314,21 +315,22 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) {
314315 xhr . setRequestHeader ( keyStr , valueStr ) ;
315316 }
316317 }
317- Fetch . xhrs . push ( xhr ) ;
318- var id = Fetch . xhrs . length ;
319- HEAPU32 [ fetch + { { { C_STRUCTS . emscripten_fetch_t . id } } } >> 2 ] = id ;
318+ var id = HEAPU32 [ fetch + { { { C_STRUCTS . emscripten_fetch_t . id } } } >> 2 ] ;
319+ Fetch . xhrs [ id ] = xhr ;
320320 var data = ( dataPtr && dataLength ) ? HEAPU8 . slice ( dataPtr , dataPtr + dataLength ) : null ;
321321 // TODO: Support specifying custom headers to the request.
322322
323323 // Share the code to save the response, as we need to do so both on success
324324 // and on error (despite an error, there may be a response, like a 404 page).
325325 // This receives a condition, which determines whether to save the xhr's
326326 // response, or just 0.
327- function saveResponse ( condition ) {
327+ function saveResponseAndStatus ( ) {
328328 var ptr = 0 ;
329329 var ptrLen = 0 ;
330- if ( condition ) {
331- ptrLen = xhr . response ? xhr . response . byteLength : 0 ;
330+ if ( xhr . response && fetchAttrLoadToMemory && HEAPU32 [ fetch + { { { C_STRUCTS . emscripten_fetch_t . data } } } >> 2 ] === 0 ) {
331+ ptrLen = xhr . response . byteLength ;
332+ }
333+ if ( ptrLen > 0 ) {
332334#if FETCH_DEBUG
333335 console . log ( 'fetch: allocating ' + ptrLen + ' bytes in Emscripten heap for xhr data' ) ;
334336#endif
@@ -339,12 +341,8 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) {
339341 }
340342 HEAPU32 [ fetch + { { { C_STRUCTS . emscripten_fetch_t . data } } } >> 2 ] = ptr ;
341343 Fetch . setu64 ( fetch + { { { C_STRUCTS . emscripten_fetch_t . numBytes } } } , ptrLen ) ;
342- }
343-
344- xhr . onload = ( e ) => {
345- saveResponse ( fetchAttrLoadToMemory && ! fetchAttrStreamData ) ;
346- var len = xhr . response ? xhr . response . byteLength : 0 ;
347344 Fetch . setu64 ( fetch + { { { C_STRUCTS . emscripten_fetch_t . dataOffset } } } , 0 ) ;
345+ var len = xhr . response ? xhr . response . byteLength : 0 ;
348346 if ( len ) {
349347 // If the final XHR.onload handler receives the bytedata to compute total length, report that,
350348 // otherwise don't write anything out here, which will retain the latest byte size reported in
@@ -354,9 +352,17 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) {
354352 HEAPU16 [ fetch + { { { C_STRUCTS . emscripten_fetch_t . readyState } } } >> 1 ] = xhr . readyState ;
355353 HEAPU16 [ fetch + { { { C_STRUCTS . emscripten_fetch_t . status } } } >> 1 ] = xhr . status ;
356354 if ( xhr . statusText ) stringToUTF8 ( xhr . statusText , fetch + { { { C_STRUCTS . emscripten_fetch_t . statusText } } } , 64 ) ;
355+ }
356+
357+ xhr . onload = ( e ) => {
358+ // check if xhr was aborted by user and don't try to call back
359+ if ( ! ( id in Fetch . xhrs ) ) {
360+ return ;
361+ }
362+ saveResponseAndStatus ( ) ;
357363 if ( xhr . status >= 200 && xhr . status < 300 ) {
358364#if FETCH_DEBUG
359- console . log ( 'fetch: xhr of URL "' + xhr . url_ + '" / responseURL "' + xhr . responseURL + '" succeeded with status 200' ) ;
365+ console . log ( 'fetch: xhr of URL "' + xhr . url_ + '" / responseURL "' + xhr . responseURL + '" succeeded with status ' + xhr . status ) ;
360366#endif
361367 if ( onsuccess ) onsuccess ( fetch , xhr , e ) ;
362368 } else {
@@ -367,27 +373,34 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) {
367373 }
368374 } ;
369375 xhr . onerror = ( e ) => {
370- saveResponse ( fetchAttrLoadToMemory ) ;
371- var status = xhr . status ; // XXX TODO: Overwriting xhr.status doesn't work here, so don't override anywhere else either.
376+ // check if xhr was aborted by user and don't try to call back
377+ if ( ! ( id in Fetch . xhrs ) ) {
378+ return ;
379+ }
372380#if FETCH_DEBUG
373- console . error ( 'fetch: xhr of URL "' + xhr . url_ + '" / responseURL "' + xhr . responseURL + '" finished with error, readyState ' + xhr . readyState + ' and status ' + status ) ;
381+ console . error ( 'fetch: xhr of URL "' + xhr . url_ + '" / responseURL "' + xhr . responseURL + '" finished with error, readyState ' + xhr . readyState + ' and status ' + xhr . status ) ;
374382#endif
375- Fetch . setu64 ( fetch + { { { C_STRUCTS . emscripten_fetch_t . dataOffset } } } , 0 ) ;
376- Fetch . setu64 ( fetch + { { { C_STRUCTS . emscripten_fetch_t . totalBytes } } } , xhr . response ? xhr . response . byteLength : 0 ) ;
377- HEAPU16 [ fetch + { { { C_STRUCTS . emscripten_fetch_t . readyState } } } >> 1 ] = xhr . readyState ;
378- HEAPU16 [ fetch + { { { C_STRUCTS . emscripten_fetch_t . status } } } >> 1 ] = status ;
383+ saveResponseAndStatus ( ) ;
379384 if ( onerror ) onerror ( fetch , xhr , e ) ;
380385 } ;
381386 xhr . ontimeout = ( e ) => {
387+ // check if xhr was aborted by user and don't try to call back
388+ if ( ! ( id in Fetch . xhrs ) ) {
389+ return ;
390+ }
382391#if FETCH_DEBUG
383392 console . error ( 'fetch: xhr of URL "' + xhr . url_ + '" / responseURL "' + xhr . responseURL + '" timed out, readyState ' + xhr . readyState + ' and status ' + xhr . status ) ;
384393#endif
385394 if ( onerror ) onerror ( fetch , xhr , e ) ;
386395 } ;
387396 xhr . onprogress = ( e ) => {
397+ // check if xhr was aborted by user and don't try to call back
398+ if ( ! ( id in Fetch . xhrs ) ) {
399+ return ;
400+ }
388401 var ptrLen = ( fetchAttrLoadToMemory && fetchAttrStreamData && xhr . response ) ? xhr . response . byteLength : 0 ;
389402 var ptr = 0 ;
390- if ( fetchAttrLoadToMemory && fetchAttrStreamData ) {
403+ if ( ptrLen > 0 && fetchAttrLoadToMemory && fetchAttrStreamData ) {
391404#if FETCH_DEBUG
392405 console . log ( 'fetch: allocating ' + ptrLen + ' bytes in Emscripten heap for xhr data' ) ;
393406#endif
@@ -413,6 +426,11 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) {
413426 }
414427 } ;
415428 xhr . onreadystatechange = ( e ) => {
429+ // check if xhr was aborted by user and don't try to call back
430+ if ( ! ( id in Fetch . xhrs ) ) {
431+ { { { runtimeKeepalivePop ( ) } } }
432+ return ;
433+ }
416434 HEAPU16 [ fetch + { { { C_STRUCTS . emscripten_fetch_t . readyState } } } >> 1 ] = xhr . readyState ;
417435 if ( xhr . readyState >= 2 ) {
418436 HEAPU16 [ fetch + { { { C_STRUCTS . emscripten_fetch_t . status } } } >> 1 ] = xhr . status ;
@@ -567,21 +585,27 @@ function startFetch(fetch, successcb, errorcb, progresscb, readystatechangecb) {
567585}
568586
569587function fetchGetResponseHeadersLength ( id ) {
570- return lengthBytesUTF8 ( Fetch . xhrs [ id - 1 ] . getAllResponseHeaders ( ) ) + 1 ;
588+ return lengthBytesUTF8 ( Fetch . xhrs [ id ] . getAllResponseHeaders ( ) ) + 1 ;
571589}
572590
573591function fetchGetResponseHeaders ( id , dst , dstSizeBytes ) {
574- var responseHeaders = Fetch . xhrs [ id - 1 ] . getAllResponseHeaders ( ) ;
592+ var responseHeaders = Fetch . xhrs [ id ] . getAllResponseHeaders ( ) ;
575593 var lengthBytes = lengthBytesUTF8 ( responseHeaders ) + 1 ;
576594 stringToUTF8 ( responseHeaders , dst , dstSizeBytes ) ;
577595 return Math . min ( lengthBytes , dstSizeBytes ) ;
578596}
579597
580598//Delete the xhr JS object, allowing it to be garbage collected.
581599function fetchFree ( id ) {
582- //Note: should just be [id], but indexes off by 1 (see: #8803)
583600#if FETCH_DEBUG
584- console . log ( "fetch: Deleting id:" + ( id - 1 ) + " of " + Fetch . xhrs ) ;
601+ console . log ( "fetch: Deleting id:" + id + " of " + Fetch . xhrs ) ;
585602#endif
586- delete Fetch . xhrs [ id - 1 ] ;
603+ var xhr = Fetch . xhrs [ id ] ;
604+ if ( xhr ) {
605+ delete Fetch . xhrs [ id ] ;
606+ // check if fetch is still in progress and should be aborted
607+ if ( xhr . readyState > 0 && xhr . readyState < 4 ) {
608+ xhr . abort ( ) ;
609+ }
610+ }
587611}
0 commit comments