diff --git a/app/views/settings/_display.html.erb b/app/views/settings/_display.html.erb index 30e6525f7..17c4ed817 100644 --- a/app/views/settings/_display.html.erb +++ b/app/views/settings/_display.html.erb @@ -28,6 +28,8 @@

<%= setting_text_field :thumbnails_size, :size => 6 %>

+

<%= setting_text_field :thumbnails_timeout, :size => 6 %>

+

<%= setting_select :new_item_menu_tab, [[l(:label_none), '0'], [l(:label_new_project_issue_tab_enabled), '1'], [l(:label_new_object_tab_enabled), '2']] %>

diff --git a/config/locales/en.yml b/config/locales/en.yml index c842e4d7b..3c83c6176 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -494,6 +494,7 @@ en: setting_session_timeout: Session inactivity timeout setting_thumbnails_enabled: Display attachment thumbnails setting_thumbnails_size: Thumbnails size (in pixels) + setting_thumbnails_timeout: Thumbnails creation timeout (in seconds) setting_non_working_week_days: Non-working days setting_jsonp_enabled: Enable JSONP support setting_default_projects_tracker_ids: Default trackers for new projects diff --git a/config/settings.yml b/config/settings.yml index bd3795756..798146f24 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -325,6 +325,9 @@ thumbnails_enabled: thumbnails_size: format: int default: 100 +thumbnails_timeout: + format: int + default: 10 non_working_week_days: serialized: true default: diff --git a/lib/redmine/thumbnail.rb b/lib/redmine/thumbnail.rb index 4c886a5b3..bf18fead5 100644 --- a/lib/redmine/thumbnail.rb +++ b/lib/redmine/thumbnail.rb @@ -18,6 +18,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. require 'fileutils' +require 'timeout' module Redmine module Thumbnail @@ -51,8 +52,25 @@ module Redmine else cmd = "#{shell_quote CONVERT_BIN} #{shell_quote source} -auto-orient -thumbnail #{shell_quote size_option} #{shell_quote target}" end - unless system(cmd) - logger.error("Creating thumbnail failed (#{$?}):\nCommand: #{cmd}") + + pid = nil + begin + Timeout.timeout(Setting.thumbnails_timeout.to_i) do + pid = Process.spawn(cmd) + _, status = Process.wait2(pid) + unless status.success? + logger.error("Creating thumbnail failed (#{status.exitstatus}):\nCommand: #{cmd}") + return nil + end + end + rescue Timeout::Error + begin + Process.kill('TERM', pid) + Timeout.timeout(1) { Process.wait(pid) } + rescue Timeout::Error + Process.kill('KILL', pid) + end + logger.error("Creating thumbnail timed out:\nCommand: #{cmd}") return nil end end diff --git a/test/unit/attachment_test.rb b/test/unit/attachment_test.rb index 2e37672ab..b88350fba 100644 --- a/test/unit/attachment_test.rb +++ b/test/unit/attachment_test.rb @@ -626,6 +626,25 @@ class AttachmentTest < ActiveSupport::TestCase ensure set_tmp_attachments_directory end + + def test_thumbnail_should_timeout + dummy_pid = 37530 + Process.stubs(:spawn).returns(dummy_pid) + Process.stubs(:wait2).raises(Timeout::Error) + Process.stubs(:kill).returns(1) + Process.stubs(:wait).returns(dummy_pid) + Rails.logger.expects(:error).with(regexp_matches(/Creating thumbnail timed out/)) + + set_fixtures_attachments_directory + Attachment.clear_thumbnails + + attachment = Attachment.find(16) + thumbnail = attachment.thumbnail + + assert_nil thumbnail + ensure + set_tmp_attachments_directory + end else puts '(ImageMagick convert not available)' end