0
0
Fork 0

Validate HTTP response length while receiving (#6891)

to_s method of HTTP::Response keeps blocking while it receives the whole
content, no matter how it is big. This means it may waste time to receive
unacceptably large files. It may also consume memory and disk in the
process. This solves the inefficency by checking response length while
receiving.
This commit is contained in:
Akihiko Odaki 2018-03-26 21:02:10 +09:00 committed by Eugen Rochko
parent 18965cb0e6
commit 40e5d2303b
18 changed files with 115 additions and 26 deletions

View file

@ -55,7 +55,6 @@ class Account < ApplicationRecord
include AccountHeader
include AccountInteractions
include Attachmentable
include Remotable
include Paginable
enum protocol: [:ostatus, :activitypub]

View file

@ -2,4 +2,5 @@
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
include Remotable
end

View file

@ -4,6 +4,7 @@ module AccountAvatar
extend ActiveSupport::Concern
IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif'].freeze
LIMIT = 2.megabytes
class_methods do
def avatar_styles(file)
@ -19,7 +20,8 @@ module AccountAvatar
# Avatar upload
has_attached_file :avatar, styles: ->(f) { avatar_styles(f) }, convert_options: { all: '-strip' }, processors: [:lazy_thumbnail]
validates_attachment_content_type :avatar, content_type: IMAGE_MIME_TYPES
validates_attachment_size :avatar, less_than: 2.megabytes
validates_attachment_size :avatar, less_than: LIMIT
remotable_attachment :avatar, LIMIT
end
def avatar_original_url

View file

@ -4,6 +4,7 @@ module AccountHeader
extend ActiveSupport::Concern
IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif'].freeze
LIMIT = 2.megabytes
class_methods do
def header_styles(file)
@ -19,7 +20,8 @@ module AccountHeader
# Header upload
has_attached_file :header, styles: ->(f) { header_styles(f) }, convert_options: { all: '-strip' }, processors: [:lazy_thumbnail]
validates_attachment_content_type :header, content_type: IMAGE_MIME_TYPES
validates_attachment_size :header, less_than: 2.megabytes
validates_attachment_size :header, less_than: LIMIT
remotable_attachment :header, LIMIT
end
def header_original_url

View file

@ -3,8 +3,8 @@
module Remotable
extend ActiveSupport::Concern
included do
attachment_definitions.each_key do |attachment_name|
class_methods do
def remotable_attachment(attachment_name, limit)
attribute_name = "#{attachment_name}_remote_url".to_sym
method_name = "#{attribute_name}=".to_sym
alt_method_name = "reset_#{attachment_name}!".to_sym
@ -33,7 +33,7 @@ module Remotable
File.extname(filename)
end
send("#{attachment_name}=", StringIO.new(response.to_s))
send("#{attachment_name}=", StringIO.new(response.body_with_limit(limit)))
send("#{attachment_name}_file_name=", basename + extname)
self[attribute_name] = url if has_attribute?(attribute_name)

View file

@ -19,6 +19,8 @@
#
class CustomEmoji < ApplicationRecord
LIMIT = 50.kilobytes
SHORTCODE_RE_FRAGMENT = '[a-zA-Z0-9_]{2,}'
SCAN_RE = /(?<=[^[:alnum:]:]|\n|^)
@ -29,14 +31,14 @@ class CustomEmoji < ApplicationRecord
has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce -strip' } }
validates_attachment :image, content_type: { content_type: 'image/png' }, presence: true, size: { in: 0..50.kilobytes }
validates_attachment :image, content_type: { content_type: 'image/png' }, presence: true, size: { less_than: LIMIT }
validates :shortcode, uniqueness: { scope: :domain }, format: { with: /\A#{SHORTCODE_RE_FRAGMENT}\z/ }, length: { minimum: 2 }
scope :local, -> { where(domain: nil) }
scope :remote, -> { where.not(domain: nil) }
scope :alphabetic, -> { order(domain: :asc, shortcode: :asc) }
include Remotable
remotable_attachment :image, LIMIT
def local?
domain.nil?

View file

@ -56,6 +56,8 @@ class MediaAttachment < ApplicationRecord
},
}.freeze
LIMIT = 8.megabytes
belongs_to :account, inverse_of: :media_attachments, optional: true
belongs_to :status, inverse_of: :media_attachments, optional: true
@ -64,10 +66,9 @@ class MediaAttachment < ApplicationRecord
processors: ->(f) { file_processors f },
convert_options: { all: '-quality 90 -strip' }
include Remotable
validates_attachment_content_type :file, content_type: IMAGE_MIME_TYPES + VIDEO_MIME_TYPES
validates_attachment_size :file, less_than: 8.megabytes
validates_attachment_size :file, less_than: LIMIT
remotable_attachment :file, LIMIT
validates :account, presence: true
validates :description, length: { maximum: 420 }, if: :local?

View file

@ -26,6 +26,7 @@
class PreviewCard < ApplicationRecord
IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif'].freeze
LIMIT = 1.megabytes
self.inheritance_column = false
@ -36,11 +37,11 @@ class PreviewCard < ApplicationRecord
has_attached_file :image, styles: { original: { geometry: '400x400>', file_geometry_parser: FastGeometryParser } }, convert_options: { all: '-quality 80 -strip' }
include Attachmentable
include Remotable
validates :url, presence: true, uniqueness: true
validates_attachment_content_type :image, content_type: IMAGE_MIME_TYPES
validates_attachment_size :image, less_than: 1.megabytes
validates_attachment_size :image, less_than: LIMIT
remotable_attachment :image, LIMIT
before_save :extract_dimensions, if: :link?