mirror of https://github.com/mastodon/mastodon
Fix remote files not using Content-Type header, streaming (#14184)
parent
65506bac3f
commit
7aaf2b44ec
@ -0,0 +1,10 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ResponseWithLimit
|
||||||
|
def initialize(response, limit)
|
||||||
|
@response = response
|
||||||
|
@limit = limit
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :response, :limit
|
||||||
|
end
|
@ -0,0 +1,27 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Paperclip
|
||||||
|
module MediaTypeSpoofDetectorExtensions
|
||||||
|
def calculated_content_type
|
||||||
|
@calculated_content_type ||= type_from_mime_magic || type_from_file_command
|
||||||
|
end
|
||||||
|
|
||||||
|
def type_from_mime_magic
|
||||||
|
@type_from_mime_magic ||= begin
|
||||||
|
begin
|
||||||
|
File.open(@file.path) do |file|
|
||||||
|
MimeMagic.by_magic(file)&.type
|
||||||
|
end
|
||||||
|
rescue Errno::ENOENT
|
||||||
|
''
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def type_from_file_command
|
||||||
|
@type_from_file_command ||= FileCommandContentTypeDetector.new(@file.path).detect
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Paperclip::MediaTypeSpoofDetector.prepend(Paperclip::MediaTypeSpoofDetectorExtensions)
|
@ -0,0 +1,55 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Paperclip
|
||||||
|
class ResponseWithLimitAdapter < AbstractAdapter
|
||||||
|
def self.register
|
||||||
|
Paperclip.io_adapters.register self do |target|
|
||||||
|
target.is_a?(ResponseWithLimit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(target, options = {})
|
||||||
|
super
|
||||||
|
cache_current_values
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def cache_current_values
|
||||||
|
@original_filename = filename_from_content_disposition || filename_from_path || 'data'
|
||||||
|
@size = @target.response.content_length
|
||||||
|
@tempfile = copy_to_tempfile(@target)
|
||||||
|
@content_type = @target.response.mime_type || ContentTypeDetector.new(@tempfile.path).detect
|
||||||
|
end
|
||||||
|
|
||||||
|
def copy_to_tempfile(source)
|
||||||
|
bytes_read = 0
|
||||||
|
|
||||||
|
source.response.body.each do |chunk|
|
||||||
|
bytes_read += chunk.bytesize
|
||||||
|
|
||||||
|
destination.write(chunk)
|
||||||
|
chunk.clear
|
||||||
|
|
||||||
|
raise Mastodon::LengthValidationError if bytes_read > source.limit
|
||||||
|
end
|
||||||
|
|
||||||
|
destination.rewind
|
||||||
|
destination
|
||||||
|
rescue Mastodon::LengthValidationError
|
||||||
|
destination.close(true)
|
||||||
|
raise
|
||||||
|
ensure
|
||||||
|
source.response.connection.close
|
||||||
|
end
|
||||||
|
|
||||||
|
def filename_from_content_disposition
|
||||||
|
disposition = @target.response.headers['content-disposition']
|
||||||
|
disposition&.match(/filename="([^"]*)"/)&.captures&.first
|
||||||
|
end
|
||||||
|
|
||||||
|
def filename_from_path
|
||||||
|
@target.response.uri.path.split('/').last
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue