diff --git a/app/assets/javascripts/discourse/app/lib/uploads.js b/app/assets/javascripts/discourse/app/lib/uploads.js index 03c7977893..6b75f07e90 100644 --- a/app/assets/javascripts/discourse/app/lib/uploads.js +++ b/app/assets/javascripts/discourse/app/lib/uploads.js @@ -116,6 +116,13 @@ export function validateUploadedFile(file, opts) { } } + if (file.size === 0) { + /* eslint-disable no-console */ + console.warn("File with a 0 byte size detected, cancelling upload.", file); + bootbox.alert(I18n.t("post.errors.file_size_zero")); + return false; + } + // everything went fine return true; } diff --git a/app/assets/javascripts/discourse/app/services/media-optimization-worker.js b/app/assets/javascripts/discourse/app/services/media-optimization-worker.js index d60f5c5af4..4badc8499a 100644 --- a/app/assets/javascripts/discourse/app/services/media-optimization-worker.js +++ b/app/assets/javascripts/discourse/app/services/media-optimization-worker.js @@ -42,6 +42,10 @@ export default class MediaOptimizationWorkerService extends Service { this.siteSettings .composer_media_optimization_image_bytes_optimization_threshold ) { + this.logIfDebug( + `The file ${file.name} was less than the image optimization bytes threshold (${this.siteSettings.composer_media_optimization_image_bytes_optimization_threshold} bytes), skipping.`, + file + ); return Promise.resolve(); } await this.ensureAvailableWorker(); @@ -185,10 +189,10 @@ export default class MediaOptimizationWorkerService extends Service { this.installPromise = null; } - logIfDebug(message) { + logIfDebug(...messages) { if (this.siteSettings.composer_media_optimization_debug_mode) { // eslint-disable-next-line no-console - console.log(message); + console.log(...messages); } } } diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index f84a0ebd0a..891320f7e3 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -200,6 +200,10 @@ class UploadsController < ApplicationController end def validate_file_size(file_name:, file_size:) + if file_size.zero? + raise ExternalUploadValidationError.new(I18n.t("upload.size_zero_failure")) + end + if file_size_too_big?(file_name, file_size) raise ExternalUploadValidationError.new( I18n.t( diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 20934c5e47..aa3ad9939f 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -3104,6 +3104,7 @@ en: edit: "Sorry, there was an error editing your post. Please try again." upload: "Sorry, there was an error uploading that file. Please try again." file_too_large: "Sorry, that file is too big (maximum size is %{max_size_kb}kb). Why not upload your large file to a cloud sharing service, then paste the link?" + file_size_zero: "Sorry, it looks like something has gone wrong, the file you are trying to upload is 0 bytes. Please try again." file_too_large_humanized: "Sorry, that file is too big (maximum size is %{max_size}). Why not upload your large file to a cloud sharing service, then paste the link?" too_many_uploads: "Sorry, you can only upload one file at a time." too_many_dragged_and_dropped_files: diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index fa7ecdf317..5482275479 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -4088,6 +4088,7 @@ en: external_upload_not_found: "The upload was not found in the external store. %{additional_detail}" checksum_mismatch_failure: "The checksum of the file you uploaded does not match. The file contents may have changed on upload. Please try again." cannot_promote_failure: "The upload cannot be completed, it may have already completed or previously failed." + size_zero_failure: "Sorry, it looks like something has gone wrong, the file you are trying to upload is 0 bytes. Please try again." attachments: too_large: "Sorry, the file you are trying to upload is too big (maximum size is %{max_size_kb}KB)." too_large_humanized: "Sorry, the file you are trying to upload is too big (maximum size is %{max_size})." diff --git a/public/javascripts/media-optimization-worker.js b/public/javascripts/media-optimization-worker.js index c34c3c5c13..e831b2d901 100644 --- a/public/javascripts/media-optimization-worker.js +++ b/public/javascripts/media-optimization-worker.js @@ -25,10 +25,10 @@ function resizeWithAspect( }; } -function logIfDebug(message) { +function logIfDebug(...messages) { if (DedicatedWorkerGlobalScope.debugMode) { // eslint-disable-next-line no-console - console.log(message); + console.log(...messages); } } diff --git a/spec/requests/uploads_controller_spec.rb b/spec/requests/uploads_controller_spec.rb index a68e730354..46b0e19875 100644 --- a/spec/requests/uploads_controller_spec.rb +++ b/spec/requests/uploads_controller_spec.rb @@ -825,6 +825,22 @@ describe UploadsController do expect(response.body).to include(I18n.t("upload.attachments.too_large_humanized", max_size: "1 MB")) end + it 'returns a sensible error if the file size is 0 bytes' do + SiteSetting.authorized_extensions = "*" + stub_create_multipart_request + + post "/uploads/create-multipart.json", **{ + params: { + file_name: "test.zip", + file_size: 0, + upload_type: "composer", + } + } + + expect(response.status).to eq(422) + expect(response.body).to include(I18n.t("upload.size_zero_failure")) + end + def stub_create_multipart_request FileStore::S3Store.any_instance.stubs(:temporary_upload_path).returns( "uploads/default/#{test_bucket_prefix}/temp/28fccf8259bbe75b873a2bd2564b778c/test.png"