@@ -7,7 +7,7 @@ const Authorize = require('./authorize');
77const config = require ( './config' ) ;
88
99/**
10- * This file exposes a get/put/delete interface on top of XMLHttpRequest.
10+ * This file exposes a get/put/delete interface on top of fetch() or XMLHttpRequest.
1111 * It requires to be configured with parameters about the remotestorage server to
1212 * connect to.
1313 * Each instance of WireClient is always associated with a single remotestorage
@@ -486,8 +486,80 @@ WireClient.prototype = {
486486WireClient . isArrayBufferView = isArrayBufferView ;
487487
488488// Shared request function used by WireClient, GoogleDrive and Dropbox.
489- // TODO: Should we use fetch ?
490489WireClient . request = function ( method , url , options ) {
490+ if ( typeof fetch === 'function' ) {
491+ return WireClient . _fetchRequest ( method , url , options ) ;
492+ } else if ( typeof XMLHttpRequest === 'function' ) {
493+ return WireClient . _xhrRequest ( method , url , options ) ;
494+ } else {
495+ log ( '[WireClient] add a polyfill for fetch or XMLHttpRequest' ) ;
496+ return Promise . reject ( '[WireClient] add a polyfill for fetch or XMLHttpRequest' ) ;
497+ }
498+ } ;
499+
500+ /** options includes body, headers and responseType */
501+ WireClient . _fetchRequest = function ( method , url , options ) {
502+ var syntheticXhr ;
503+ var responseHeaders = { } ;
504+ var abortController ;
505+ if ( typeof AbortController === 'function' ) {
506+ abortController = new AbortController ( ) ;
507+ }
508+ var networkPromise = fetch ( url , {
509+ method : method ,
510+ headers : options . headers ,
511+ body : options . body ,
512+ signal : abortController ? abortController . signal : undefined
513+ } ) . then ( function ( response ) {
514+ log ( '[WireClient fetch]' , response ) ;
515+
516+ response . headers . forEach ( function ( value , headerName ) {
517+ responseHeaders [ headerName . toUpperCase ( ) ] = value ;
518+ } ) ;
519+
520+ syntheticXhr = {
521+ readyState : 4 ,
522+ status : response . status ,
523+ statusText : response . statusText ,
524+ response : undefined ,
525+ getResponseHeader : function ( headerName ) {
526+ return responseHeaders [ headerName . toUpperCase ( ) ] || null ;
527+ } ,
528+ // responseText: 'foo',
529+ responseType : options . responseType ,
530+ responseURL : url ,
531+ } ;
532+ switch ( options . responseType ) {
533+ case 'arraybuffer' :
534+ return response . arrayBuffer ( ) ;
535+ case 'blob' :
536+ return response . blob ( ) ;
537+ case 'json' :
538+ return response . json ( ) ;
539+ case '' :
540+ case 'text' :
541+ return response . text ( ) ;
542+ default : // document
543+ throw new Error ( "responseType 'document' is not currently supported using fetch" ) ;
544+ }
545+ } ) . then ( function ( processedBody ) {
546+ syntheticXhr . response = processedBody ;
547+ return syntheticXhr ;
548+ } ) ;
549+
550+ var timeoutPromise = new Promise ( function ( resolve , reject ) {
551+ setTimeout ( function ( ) {
552+ reject ( 'timeout' ) ;
553+ if ( abortController ) {
554+ abortController . abort ( ) ;
555+ }
556+ } , config . requestTimeout ) ;
557+ } ) ;
558+
559+ return Promise . race ( [ networkPromise , timeoutPromise ] ) ;
560+ } ;
561+
562+ WireClient . _xhrRequest = function ( method , url , options ) {
491563 return new Promise ( ( resolve , reject ) => {
492564
493565 log ( '[WireClient]' , method , url ) ;
@@ -550,7 +622,7 @@ WireClient._rs_init = function (remoteStorage) {
550622} ;
551623
552624WireClient . _rs_supported = function ( ) {
553- return ! ! XMLHttpRequest ;
625+ return typeof fetch === 'function' || typeof XMLHttpRequest === 'function' ;
554626} ;
555627
556628WireClient . _rs_cleanup = function ( ) {
0 commit comments