response_with_limit_adapter.rb 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. # frozen_string_literal: true
  2. module Paperclip
  3. class ResponseWithLimitAdapter < AbstractAdapter
  4. def self.register
  5. Paperclip.io_adapters.register self do |target|
  6. target.is_a?(ResponseWithLimit)
  7. end
  8. end
  9. def initialize(target, options = {})
  10. super
  11. cache_current_values
  12. end
  13. private
  14. def cache_current_values
  15. @target.response.require_limit_not_exceeded!(@target.limit)
  16. @original_filename = truncated_filename
  17. @tempfile = copy_to_tempfile(@target)
  18. @content_type = ContentTypeDetector.new(@tempfile.path).detect
  19. @size = File.size(@tempfile)
  20. end
  21. def copy_to_tempfile(source)
  22. bytes_read = 0
  23. source.response.body.each do |chunk|
  24. bytes_read += chunk.bytesize
  25. raise Mastodon::LengthValidationError, "Body size exceeds limit of #{source.limit}" if bytes_read > source.limit
  26. destination.write(chunk)
  27. chunk.clear
  28. end
  29. destination.rewind
  30. destination
  31. rescue
  32. destination.close(true)
  33. raise
  34. ensure
  35. source.response.connection.close
  36. end
  37. def truncated_filename
  38. filename = filename_from_content_disposition.presence || filename_from_path.presence || 'data'
  39. extension = File.extname(filename)
  40. basename = File.basename(filename, extension)
  41. [basename[...20], extension[..4]].compact_blank.join
  42. end
  43. def filename_from_content_disposition
  44. disposition = @target.response.headers['content-disposition']
  45. disposition&.match(/filename="([^"]*)"/)&.captures&.first
  46. end
  47. def filename_from_path
  48. @target.response.uri.path.split('/').last
  49. end
  50. end
  51. end