99 * @module LargeFileUploadTask
1010 */
1111
12+ import { GraphClientError } from "../GraphClientError" ;
1213import { Client } from "../index" ;
1314import { Range } from "../Range" ;
15+ import { ResponseType } from "../ResponseType" ;
16+ import { GraphResponseHandler } from "../GraphResponseHandler" ;
17+ import { UploadResult } from "./FileUploadUtil/UploadResult" ;
1418
1519/**
1620 * @interface
@@ -50,6 +54,7 @@ export interface LargeFileUploadTaskOptions {
5054export interface LargeFileUploadSession {
5155 url : string ;
5256 expiry : Date ;
57+ isCancelled ?: boolean ;
5358}
5459
5560/**
@@ -124,6 +129,7 @@ export class LargeFileUploadTask {
124129 const largeFileUploadSession : LargeFileUploadSession = {
125130 url : session . uploadUrl ,
126131 expiry : new Date ( session . expirationDateTime ) ,
132+ isCancelled : false
127133 } ;
128134 return largeFileUploadSession ;
129135 }
@@ -215,22 +221,35 @@ export class LargeFileUploadTask {
215221 * @returns The promise resolves to uploaded response
216222 */
217223 public async upload ( ) : Promise < any > {
218- // eslint-disable-next-line no-constant-condition
219- while ( true ) {
224+ while ( ! this . uploadSession . isCancelled ) {
220225 const nextRange = this . getNextRange ( ) ;
221226 if ( nextRange . maxValue === - 1 ) {
222227 const err = new Error ( "Task with which you are trying to upload is already completed, Please check for your uploaded file" ) ;
223228 err . name = "Invalid Session" ;
224229 throw err ;
225230 }
226231 const fileSlice = this . sliceFile ( nextRange ) ;
227- const response = await this . uploadSlice ( fileSlice , nextRange , this . file . size ) ;
228- // Upon completion of upload process incase of onedrive, driveItem is returned, which contains id
229- if ( response . id !== undefined ) {
230- return response ;
231- } else {
232- this . updateTaskStatus ( response ) ;
232+ const rawResponse = await this . uploadSliceGetRawResponse ( fileSlice , nextRange , this . file . size ) ;
233+ if ( ! rawResponse ) {
234+ throw new GraphClientError ( "Something went wrong! Large file upload slice response is null." ) ;
233235 }
236+
237+ const responseBody = await GraphResponseHandler . getResponse ( rawResponse ) ;
238+ if ( rawResponse . status == 201 || ( rawResponse . status == 200 && responseBody . id ) ) {
239+ const result = new UploadResult ( ) ;
240+ return result . setUploadResult ( rawResponse ) ;
241+ }
242+
243+ /* Handling an API issue where the case of Outlook upload 'nextExpectedRanges' property is not uniform.
244+ * https://github.com/microsoftgraph/msgraph-sdk-serviceissues/issues/39
245+ */
246+ const res : UploadStatusResponse = {
247+ expirationDateTime : responseBody . expirationDateTime ,
248+ nextExpectedRanges : responseBody . NextExpectedRanges || responseBody . nextExpectedRanges ,
249+ } ;
250+
251+ this . updateTaskStatus ( res ) ;
252+ this . updateTaskStatus ( responseBody ) ;
234253 }
235254 }
236255
@@ -251,6 +270,23 @@ export class LargeFileUploadTask {
251270 } )
252271 . put ( fileSlice ) ;
253272 }
273+ /**
274+ * @public
275+ * @async
276+ * Uploads given slice to the server
277+ * @param {ArrayBuffer | Blob | File } fileSlice - The file slice
278+ * @param {Range } range - The range value
279+ * @param {number } totalSize - The total size of a complete file
280+ */
281+ public async uploadSliceGetRawResponse ( fileSlice : unknown , range : Range , totalSize : number ) : Promise < Response > {
282+ return await this . client
283+ . api ( this . uploadSession . url )
284+ . headers ( {
285+ "Content-Length" : `${ range . maxValue - range . minValue + 1 } ` ,
286+ "Content-Range" : `bytes ${ range . minValue } -${ range . maxValue } /${ totalSize } ` ,
287+ } ) . responseType ( ResponseType . RAW )
288+ . put ( fileSlice ) ;
289+ }
254290
255291 /**
256292 * @public
@@ -259,7 +295,11 @@ export class LargeFileUploadTask {
259295 * @returns The promise resolves to cancelled response
260296 */
261297 public async cancel ( ) : Promise < any > {
262- return await this . client . api ( this . uploadSession . url ) . delete ( ) ;
298+ const deleteResponse = await this . client . api ( this . uploadSession . url ) . responseType ( ResponseType . RAW ) . delete ( )
299+ if ( deleteResponse . status && deleteResponse . status == 204 ) {
300+ this . uploadSession . isCancelled = true ;
301+ }
302+ return deleteResponse ;
263303 }
264304
265305 /**
@@ -284,4 +324,14 @@ export class LargeFileUploadTask {
284324 await this . getStatus ( ) ;
285325 return await this . upload ( ) ;
286326 }
327+
328+ /**
329+ * @public
330+ * @async
331+ * Get the upload session information
332+ * @returns The large file upload large file session
333+ */
334+ public getUploadSession ( ) : LargeFileUploadSession {
335+ return this . uploadSession ;
336+ }
287337}
0 commit comments