diff --git a/src/windows/FileTransferProxy.js b/src/windows/FileTransferProxy.js index 57c9ccd..5211464 100644 --- a/src/windows/FileTransferProxy.js +++ b/src/windows/FileTransferProxy.js @@ -106,55 +106,134 @@ exec(win, fail, 'FileTransfer', 'upload', mimeType = storageFile.contentType; } - storageFile.openAsync(Windows.Storage.FileAccessMode.read) - .then(function (stream) { + // check if download isn't already cancelled + var uploadOp = fileTransferOps[uploadId]; + if (uploadOp && uploadOp.state === FileTransferOperation.CANCELLED) { + // Here we should call errorCB with ABORT_ERR error + errorCallback(new FTErr(FTErr.ABORT_ERR, nativePathToCordova(filePath), server)); + return; + } - // check if upload isn't already cancelled - var uploadOp = fileTransferOps[uploadId]; - if (uploadOp && uploadOp.state == FileTransferOperation.CANCELLED) { - // Here we should call errorCB with ABORT_ERR error - errorCallback(new FTErr(FTErr.ABORT_ERR, filePath, server)); - return; + // setting request headers for uploader + var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader(); + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + uploader.setRequestHeader(header, headers[header]); } + } - var blob = MSApp.createBlobFromRandomAccessStream(mimeType, stream); - - var formData = new FormData(); - formData.append(fileKey, blob, fileName); - // add params - for(var key in params) { - formData.append(key,params[key]); + // adding params supplied to request payload + var transferParts = []; + for (var key in params) { + if (params.hasOwnProperty(key)) { + var contentPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart(); + contentPart.setHeader("Content-Disposition", "form-data; name=\"" + key + "\""); + contentPart.setText(params[key]); + transferParts.push(contentPart); } + } - var uploadOperation; - try { - // Create XHR promise for uploading data to server - uploadOperation = WinJS.xhr({ type: "POST", url: server, data: formData, headers: headers }); - fileTransferOps[uploadId].promise = uploadOperation; - } catch (e) { - // it will fail if URL is malformed, so we handle this situation - errorCallback(new FTErr(FTErr.INVALID_URL_ERR, filePath, server, null, null, e)); - return; - } + // Adding file to upload to request payload + var fileToUploadPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart(fileKey, fileName); + fileToUploadPart.setFile(storageFile); + transferParts.push(fileToUploadPart); - uploadOperation.then(function (response) { - storageFile.getBasicPropertiesAsync().done(function(basicProperties) { - var ftResult = new FileUploadResult(basicProperties.size, response.status, response.responseText); - successCallback(ftResult); - }); - }, function(err) { - if ('status' in err) { - errorCallback(new FTErr(FTErr.CONNECTION_ERR, filePath, server, err.status, err.responseText, err)); - } else { - errorCallback(new FTErr(FTErr.INVALID_URL_ERR, filePath, server, null, null, err)); + // create download object. This will throw an exception if URL is malformed + var uri = new Windows.Foundation.Uri(server); + try { + uploader.createUploadAsync(uri, transferParts).then( + function (upload) { + + // update internal TransferOperation object with newly created promise + var uploadOperation = upload.startAsync(); + fileTransferOps[uploadId].promise = uploadOperation; + + uploadOperation.then( + function (result) { + // Update TransferOperation object with new state, delete promise property + // since it is not actual anymore + var currentUploadOp = fileTransferOps[uploadId]; + if (currentUploadOp) { + currentUploadOp.state = FileTransferOperation.DONE; + currentUploadOp.promise = null; + } + + var response = result.getResponseInformation(); + // creating a data reader, attached to response stream to get server's response + var reader = new Windows.Storage.Streams.DataReader(result.getResultStreamAt(0)); + reader.loadAsync(result.progress.bytesReceived).then(function(size) { + var responseText = reader.readString(size); + var ftResult = new FileUploadResult(size, response.statusCode, responseText); + successCallback(ftResult); + reader.close(); + }); + }, + function (error) { + + var source = nativePathToCordova(filePath); + + // Handle download error here. + // Wrap this routines into promise due to some async methods + var getTransferError = new WinJS.Promise(function(resolve) { + if (error.message === 'Canceled') { + // If download was cancelled, message property will be specified + resolve(new FTErr(FTErr.ABORT_ERR, source, server, null, null, error)); + } else { + // in the other way, try to get response property + var response = upload.getResponseInformation(); + if (!response) { + resolve(new FTErr(FTErr.CONNECTION_ERR, source, server)); + } else { + var reader = new Windows.Storage.Streams.DataReader(upload.getResultStreamAt(0)); + reader.loadAsync(upload.progress.bytesReceived).then(function (size) { + var responseText = reader.readString(size); + resolve(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, server, response.statusCode, responseText, error)); + reader.close(); + }); + } + } + }); + + // Update TransferOperation object with new state, delete promise property + // since it is not actual anymore + var currentUploadOp = fileTransferOps[uploadId]; + if (currentUploadOp) { + currentUploadOp.state = FileTransferOperation.CANCELLED; + currentUploadOp.promise = null; + } + + // Cleanup, remove incompleted file + getTransferError.then(function(transferError) { + storageFile.deleteAsync().then(function() { + errorCallback(transferError); + }); + }); + + + }, + function (evt) { + + + var progressEvent = new ProgressEvent('progress', { + loaded: evt.progress.bytesSent, + total: evt.progress.totalBytesToSend, + target: evt.resultFile + }); + progressEvent.lengthComputable = true; + successCallback(progressEvent, { keepCallback: true }); + } + ); + + }, + function (err) { + var errorObj = new FTErr(FTErr.INVALID_URL_ERR); + errorObj.exception = err; + errorCallback(errorObj); } - }, function(evt) { - // progress event handler, calls successCallback with empty ProgressEvent - // We can't specify ProgressEvent data here since evt not provides any helpful information - var progressEvent = new ProgressEvent('progress'); - successCallback(progressEvent, { keepCallback: true }); - }); - }); + ); + } catch (e) { + errorCallback(new FTErr(FTErr.INVALID_URL_ERR)); + } }, function(err) { errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, server, server, null, null, err)); });