diff --git a/app/logical/danbooru/http.rb b/app/logical/danbooru/http.rb index 2508abe86..a0b8944e2 100644 --- a/app/logical/danbooru/http.rb +++ b/app/logical/danbooru/http.rb @@ -148,12 +148,12 @@ module Danbooru response = get(url) raise DownloadError, "Downloading #{response.uri} failed with code #{response.status}" if response.status != 200 - raise FileTooLargeError, response if @max_size && response.content_length.to_i > @max_size + raise FileTooLargeError, "File size too large (size: #{response.content_length.to_i.to_formatted_s(:human_size)}; max size: #{@max_size.to_formatted_s(:human_size)})" if @max_size && response.content_length.to_i > @max_size size = 0 response.body.each do |chunk| size += chunk.size - raise FileTooLargeError if @max_size && size > @max_size + raise FileTooLargeError, "File size too large (max size: #{@max_size.to_formatted_s(:human_size)})" if @max_size && size > @max_size file.write(chunk) end diff --git a/app/models/media_asset.rb b/app/models/media_asset.rb index e9dad1980..79af6f49d 100644 --- a/app/models/media_asset.rb +++ b/app/models/media_asset.rb @@ -39,7 +39,7 @@ class MediaAsset < ApplicationRecord validates :md5, uniqueness: { conditions: -> { where(status: [:processing, :active]) } } validates :file_ext, inclusion: { in: %w[jpg png gif mp4 webm swf zip], message: "Not an image or video" } - validates :file_size, numericality: { less_than_or_equal_to: Danbooru.config.max_file_size } + validates :file_size, numericality: { less_than_or_equal_to: Danbooru.config.max_file_size, message: ->(asset, _) { "too large (size: #{asset.file_size.to_formatted_s(:human_size)}; max size: #{Danbooru.config.max_file_size.to_formatted_s(:human_size)})" } } validates :duration, numericality: { less_than_or_equal_to: MAX_VIDEO_DURATION, message: "must be less than #{MAX_VIDEO_DURATION} seconds", allow_nil: true }, on: :create # XXX should allow admins to bypass validate :validate_resolution, on: :create diff --git a/test/functional/uploads_controller_test.rb b/test/functional/uploads_controller_test.rb index 6d26746b7..ea0ece1e9 100644 --- a/test/functional/uploads_controller_test.rb +++ b/test/functional/uploads_controller_test.rb @@ -177,18 +177,32 @@ class UploadsControllerTest < ActionDispatch::IntegrationTest assert_match("Not an image or video", Upload.last.error) end - should "fail if the file size is too large" do - skip "flaky test" - Danbooru.config.stubs(:max_file_size).returns(1.kilobyte) + context "for a file larger than the file size limit" do + setup do + skip "flaky test" + Danbooru.config.stubs(:max_file_size).returns(1.kilobyte) + end - file = Rack::Test::UploadedFile.new("test/files/test.jpg") - post_auth uploads_path(format: :json), @user, params: { upload: { file: file }} - perform_enqueued_jobs + should "fail for a direct file upload" do + create_upload!("test/files/test.jpg", user: @user) - assert_response 201 - assert_match("File size must be less than or equal to", Upload.last.error) + assert_response 201 + assert_match("File size too large", Upload.last.error) + end - Danbooru.config.unstub(:max_file_size) + should "fail for a source upload with a Content-Length header" do + create_upload!("https://nghttp2.org/httpbin/bytes/2000", user: @user) + + assert_response 201 + assert_match("File size too large", Upload.last.error) + end + + should "fail for a source upload without a Content-Length header" do + create_upload!("https://nghttp2.org/httpbin/stream-bytes/2000", user: @user) + + assert_response 201 + assert_match("File size too large", Upload.last.error) + end end context "for a corrupted image" do