@@ -52,11 +52,92 @@ exports.unsigned_upload = function unsigned_upload(file, upload_preset, callback
5252} ;
5353
5454exports . upload = function upload ( file , callback , options = { } ) {
55+ callback = typeof callback === "function" ? callback : function ( ) {
56+ } ;
57+
58+ if ( isBlob ( file ) ) {
59+ let uploadSourcePromise = getBlobArrayBuffer ( file ) . then ( ( arrayBuffer ) => toUploadSource ( Buffer . from ( arrayBuffer ) , options , {
60+ contentType : file . type ,
61+ filename : file . name
62+ } ) ) ;
63+
64+ if ( options . disable_promises ) {
65+ uploadSourcePromise . then ( ( uploadSource ) => call_upload_api ( uploadSource , callback , options ) ) . catch ( ( error ) => callback ( {
66+ error
67+ } ) ) ;
68+ return ;
69+ }
70+
71+ return uploadSourcePromise . then ( ( uploadSource ) => call_upload_api ( uploadSource , callback , options ) ) . catch ( ( error ) => {
72+ callback ( {
73+ error
74+ } ) ;
75+ throw error ;
76+ } ) ;
77+ }
78+
79+ if ( isUploadData ( file ) ) {
80+ file = toUploadSource ( file , options ) ;
81+ }
82+
83+ return call_upload_api ( file , callback , options ) ;
84+ } ;
85+
86+ function call_upload_api ( file , callback , options ) {
5587 return call_api ( "upload" , callback , options , function ( ) {
5688 let params = build_upload_params ( options ) ;
5789 return isRemoteUrl ( file ) ? [ params , { file : file } ] : [ params , { } , file ] ;
5890 } ) ;
59- } ;
91+ }
92+
93+ function isUint8Array ( file ) {
94+ return typeof Uint8Array !== "undefined" && file instanceof Uint8Array ;
95+ }
96+
97+ function isArrayBuffer ( file ) {
98+ return typeof ArrayBuffer !== "undefined" && file instanceof ArrayBuffer ;
99+ }
100+
101+ function isBlob ( file ) {
102+ return typeof Blob !== "undefined" && file instanceof Blob ;
103+ }
104+
105+ function getBlobArrayBuffer ( file ) {
106+ if ( typeof file . arrayBuffer === "function" ) {
107+ return file . arrayBuffer ( ) ;
108+ }
109+
110+ if ( typeof FileReader !== "undefined" ) {
111+ return new Promise ( ( resolve , reject ) => {
112+ let reader = new FileReader ( ) ;
113+ reader . onload = function ( ) {
114+ resolve ( reader . result ) ;
115+ } ;
116+ reader . onerror = function ( ) {
117+ reject ( reader . error || new Error ( "Failed to read the Blob" ) ) ;
118+ } ;
119+ reader . readAsArrayBuffer ( file ) ;
120+ } ) ;
121+ }
122+
123+ return Promise . reject ( new Error ( "Blob upload requires Blob.arrayBuffer() or FileReader support" ) ) ;
124+ }
125+
126+ function isUploadData ( file ) {
127+ return Buffer . isBuffer ( file ) || isUint8Array ( file ) || isArrayBuffer ( file ) ;
128+ }
129+
130+ function isUploadSource ( file ) {
131+ return isObject ( file ) && Buffer . isBuffer ( file . data ) ;
132+ }
133+
134+ function toUploadSource ( file , options = { } , extra = { } ) {
135+ return {
136+ data : Buffer . isBuffer ( file ) ? file : Buffer . from ( file ) ,
137+ filename : options . filename || extra . filename || "file" ,
138+ contentType : extra . contentType || "application/octet-stream"
139+ } ;
140+ }
60141
61142exports . upload_large = function upload_large ( path , callback , options = { } ) {
62143 if ( ( path != null ) && isRemoteUrl ( path ) ) {
@@ -566,9 +647,8 @@ function post(url, post_data, boundary, file, callback, options) {
566647 let finish_buffer = Buffer . from ( "--" + boundary + "--" , 'ascii' ) ;
567648 let oauth_token = options . oauth_token || config ( ) . oauth_token ;
568649 if ( ( file != null ) || options . stream ) {
569- // eslint-disable-next-line no-nested-ternary
570- let filename = options . stream ? options . filename ? options . filename : "file" : basename ( file ) ;
571- file_header = Buffer . from ( encodeFilePart ( boundary , 'application/octet-stream' , 'file' , filename ) , 'binary' ) ;
650+ let { filename, contentType } = getFileUploadOptions ( file , options ) ;
651+ file_header = Buffer . from ( encodeFilePart ( boundary , contentType , 'file' , filename ) , 'binary' ) ;
572652 }
573653 const parsedUrl = new URL ( url ) ;
574654 let post_options = {
@@ -643,19 +723,44 @@ function post(url, post_data, boundary, file, callback, options) {
643723 }
644724 if ( file != null ) {
645725 post_request . write ( file_header ) ;
646- fs . createReadStream ( file ) . on ( 'error' , function ( error ) {
647- callback ( {
648- error : error
649- } ) ;
650- return post_request . abort ( ) ;
651- } ) . pipe ( upload_stream ) ;
726+ if ( isUploadSource ( file ) ) {
727+ upload_stream . end ( file . data ) ;
728+ } else {
729+ fs . createReadStream ( file ) . on ( 'error' , function ( error ) {
730+ callback ( {
731+ error : error
732+ } ) ;
733+ return post_request . abort ( ) ;
734+ } ) . pipe ( upload_stream ) ;
735+ }
652736 } else {
653737 post_request . write ( finish_buffer ) ;
654738 post_request . end ( ) ;
655739 }
656740 return true ;
657741}
658742
743+ function getFileUploadOptions ( file , options = { } ) {
744+ if ( options . stream ) {
745+ return {
746+ filename : options . filename || "file" ,
747+ contentType : "application/octet-stream"
748+ } ;
749+ }
750+
751+ if ( isUploadSource ( file ) ) {
752+ return {
753+ filename : file . filename || "file" ,
754+ contentType : file . contentType || "application/octet-stream"
755+ } ;
756+ }
757+
758+ return {
759+ filename : basename ( file ) ,
760+ contentType : "application/octet-stream"
761+ } ;
762+ }
763+
659764function encodeFieldPart ( boundary , name , value ) {
660765 return [
661766 `--${ boundary } \r\n` ,
0 commit comments