From 463075a351d2b5e8aee6e809b64e31a44d018ddf Mon Sep 17 00:00:00 2001 From: MAEDA Go Date: Thu, 15 Oct 2026 00:03:37 +0900 Subject: [PATCH] Prevent serving partially written thumbnails --- lib/redmine/thumbnail.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/redmine/thumbnail.rb b/lib/redmine/thumbnail.rb index d6f354aff..7d585437f 100644 --- a/lib/redmine/thumbnail.rb +++ b/lib/redmine/thumbnail.rb @@ -44,15 +44,18 @@ module Redmine directory = File.dirname(target) FileUtils.mkdir_p directory + # Write to a temporary file first so that concurrent requests never + # serve a partially written thumbnail + output = File.join(directory, "#{Redmine::Utils.random_hex(8)}.#{File.basename(target)}") size_option = "#{size}x#{size}>" if mime_type == 'application/pdf' return nil unless gs_available? return nil unless valid_pdf_magic?(source) - cmd = "#{shell_quote CONVERT_BIN} #{shell_quote "#{source}[0]"} -thumbnail #{shell_quote size_option} #{shell_quote "png:#{target}"}" + cmd = "#{shell_quote CONVERT_BIN} #{shell_quote "#{source}[0]"} -thumbnail #{shell_quote size_option} #{shell_quote "png:#{output}"}" else - cmd = "#{shell_quote CONVERT_BIN} #{shell_quote source} -auto-orient -thumbnail #{shell_quote size_option} #{shell_quote target}" + cmd = "#{shell_quote CONVERT_BIN} #{shell_quote source} -auto-orient -thumbnail #{shell_quote size_option} #{shell_quote output}" end pid = nil @@ -70,6 +73,7 @@ module Redmine return nil end end + File.rename(output, target) rescue Timeout::Error if pid begin @@ -82,6 +86,8 @@ module Redmine end logger.error("Creating thumbnail timed out:\nCommand: #{cmd}") return nil + ensure + FileUtils.rm_f(output) end end target -- 2.55.0