Merge pull request #3382 from thelounge/xpaw/upload-fixes

Some fixes in file uploading
This commit is contained in:
Pavel Djundik 2019-08-27 12:21:03 +03:00 committed by GitHub
commit 5ccd6b76c0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 19 additions and 14 deletions

View file

@ -85,6 +85,7 @@ class Uploader {
filesChanged() { filesChanged() {
const files = Array.from(this.uploadInput.files); const files = Array.from(this.uploadInput.files);
this.triggerUpload(files); this.triggerUpload(files);
this.uploadInput.value = ""; // Reset <input> element so you can upload the same file
} }
triggerUpload(files) { triggerUpload(files) {
@ -114,8 +115,9 @@ class Uploader {
this.fileQueue.push(file); this.fileQueue.push(file);
} }
// if the queue was empty and we added some files to it, start uploading them // if the queue was empty and we added some files to it, and there currently
if (wasQueueEmpty && this.fileQueue.length > 0) { // is no upload in process, request a token to start the upload process
if (wasQueueEmpty && this.xhr === null && this.fileQueue.length > 0) {
this.requestToken(); this.requestToken();
} }
} }
@ -131,10 +133,9 @@ class Uploader {
uploadNextFileInQueue(token) { uploadNextFileInQueue(token) {
const file = this.fileQueue.shift(); const file = this.fileQueue.shift();
const xhr = new XMLHttpRequest(); this.xhr = new XMLHttpRequest();
this.xhr = xhr;
xhr.upload.addEventListener( this.xhr.upload.addEventListener(
"progress", "progress",
(e) => { (e) => {
const percent = Math.floor((e.loaded / e.total) * 1000) / 10; const percent = Math.floor((e.loaded / e.total) * 1000) / 10;
@ -143,26 +144,26 @@ class Uploader {
false false
); );
xhr.onreadystatechange = () => { this.xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) { if (this.xhr.readyState === XMLHttpRequest.DONE) {
this.xhr = null;
let response; let response;
try { try {
response = JSON.parse(xhr.responseText); response = JSON.parse(this.xhr.responseText);
} catch (err) { } catch (err) {
// This is just a safe guard and should not happen if server doesn't throw any errors. // This is just a safe guard and should not happen if server doesn't throw any errors.
// Browsers break the HTTP spec by aborting the request without reading any response data, // Browsers break the HTTP spec by aborting the request without reading any response data,
// if there is still data to be uploaded. Servers will only error in extreme cases like bad // if there is still data to be uploaded. Servers will only error in extreme cases like bad
// authentication or server-side errors. // authentication or server-side errors.
response = { response = {
error: `Upload aborted: HTTP ${xhr.status}`, error: `Upload aborted: HTTP ${this.xhr.status}`,
}; };
} }
this.handleResponse(response); this.handleResponse(response);
this.xhr = null;
// this file was processed, if we still have files in the queue, upload the next one // this file was processed, if we still have files in the queue, upload the next one
if (this.fileQueue.length > 0) { if (this.fileQueue.length > 0) {
this.requestToken(); this.requestToken();
@ -172,8 +173,8 @@ class Uploader {
const formData = new FormData(); const formData = new FormData();
formData.append("file", file); formData.append("file", file);
xhr.open("POST", `uploads/new/${token}`); this.xhr.open("POST", `uploads/new/${token}`);
xhr.send(formData); this.xhr.send(formData);
} }
handleResponse(response) { handleResponse(response) {

View file

@ -122,7 +122,7 @@ class Uploader {
// if the authentication token is incorrect, bail out // if the authentication token is incorrect, bail out
if (uploadTokens.delete(req.params.token) !== true) { if (uploadTokens.delete(req.params.token) !== true) {
return abortWithError(Error("Unauthorized")); return abortWithError(Error("Invalid upload token"));
} }
// if the request does not contain any body data, bail out // if the request does not contain any body data, bail out
@ -198,6 +198,10 @@ class Uploader {
busboyInstance.on("finish", () => { busboyInstance.on("finish", () => {
doneCallback(); doneCallback();
if (!uploadUrl) {
return res.status(400).json({error: "Missing file"});
}
// upload was done, send the generated file url to the client // upload was done, send the generated file url to the client
res.status(200).json({ res.status(200).json({
url: uploadUrl, url: uploadUrl,