uploads: fix "ArgumentError: string contains null byte" error

Fix an error when trying to upload a file larger than the file size
limit. In this case we tried to dump the whole HTTP response into the
error message, which included the binary file itself, which caused this
exception because it contained null bytes.
This commit is contained in:
evazion
2022-02-15 17:34:49 -06:00
parent 16b8d4b607
commit 87a00a1182
3 changed files with 26 additions and 12 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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