kt-paperclip 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +17 -0
  3. data/.github/issue_template.md +3 -0
  4. data/.gitignore +19 -0
  5. data/.hound.yml +1050 -0
  6. data/.rubocop.yml +1 -0
  7. data/.travis.yml +47 -0
  8. data/Appraisals +24 -0
  9. data/CONTRIBUTING.md +86 -0
  10. data/Gemfile +18 -0
  11. data/LICENSE +24 -0
  12. data/NEWS +515 -0
  13. data/README.md +1053 -0
  14. data/RELEASING.md +17 -0
  15. data/Rakefile +52 -0
  16. data/UPGRADING +17 -0
  17. data/features/basic_integration.feature +85 -0
  18. data/features/migration.feature +29 -0
  19. data/features/rake_tasks.feature +62 -0
  20. data/features/step_definitions/attachment_steps.rb +110 -0
  21. data/features/step_definitions/html_steps.rb +15 -0
  22. data/features/step_definitions/rails_steps.rb +257 -0
  23. data/features/step_definitions/s3_steps.rb +14 -0
  24. data/features/step_definitions/web_steps.rb +106 -0
  25. data/features/support/env.rb +12 -0
  26. data/features/support/fakeweb.rb +11 -0
  27. data/features/support/file_helpers.rb +34 -0
  28. data/features/support/fixtures/boot_config.txt +15 -0
  29. data/features/support/fixtures/gemfile.txt +5 -0
  30. data/features/support/fixtures/preinitializer.txt +20 -0
  31. data/features/support/paths.rb +28 -0
  32. data/features/support/rails.rb +39 -0
  33. data/features/support/selectors.rb +19 -0
  34. data/gemfiles/4.2.gemfile +20 -0
  35. data/gemfiles/5.0.gemfile +20 -0
  36. data/gemfiles/5.1.gemfile +20 -0
  37. data/gemfiles/5.2.gemfile +20 -0
  38. data/gemfiles/6.0.gemfile +20 -0
  39. data/lib/generators/paperclip/USAGE +8 -0
  40. data/lib/generators/paperclip/paperclip_generator.rb +36 -0
  41. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +15 -0
  42. data/lib/paperclip.rb +215 -0
  43. data/lib/paperclip/attachment.rb +617 -0
  44. data/lib/paperclip/attachment_registry.rb +60 -0
  45. data/lib/paperclip/callbacks.rb +42 -0
  46. data/lib/paperclip/content_type_detector.rb +80 -0
  47. data/lib/paperclip/errors.rb +34 -0
  48. data/lib/paperclip/file_command_content_type_detector.rb +28 -0
  49. data/lib/paperclip/filename_cleaner.rb +15 -0
  50. data/lib/paperclip/geometry.rb +157 -0
  51. data/lib/paperclip/geometry_detector_factory.rb +45 -0
  52. data/lib/paperclip/geometry_parser_factory.rb +31 -0
  53. data/lib/paperclip/glue.rb +17 -0
  54. data/lib/paperclip/has_attached_file.rb +116 -0
  55. data/lib/paperclip/helpers.rb +60 -0
  56. data/lib/paperclip/interpolations.rb +201 -0
  57. data/lib/paperclip/interpolations/plural_cache.rb +18 -0
  58. data/lib/paperclip/io_adapters/abstract_adapter.rb +75 -0
  59. data/lib/paperclip/io_adapters/attachment_adapter.rb +47 -0
  60. data/lib/paperclip/io_adapters/data_uri_adapter.rb +22 -0
  61. data/lib/paperclip/io_adapters/empty_string_adapter.rb +19 -0
  62. data/lib/paperclip/io_adapters/file_adapter.rb +26 -0
  63. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +16 -0
  64. data/lib/paperclip/io_adapters/identity_adapter.rb +17 -0
  65. data/lib/paperclip/io_adapters/nil_adapter.rb +37 -0
  66. data/lib/paperclip/io_adapters/registry.rb +36 -0
  67. data/lib/paperclip/io_adapters/stringio_adapter.rb +36 -0
  68. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +44 -0
  69. data/lib/paperclip/io_adapters/uri_adapter.rb +68 -0
  70. data/lib/paperclip/locales/en.yml +18 -0
  71. data/lib/paperclip/logger.rb +21 -0
  72. data/lib/paperclip/matchers.rb +64 -0
  73. data/lib/paperclip/matchers/have_attached_file_matcher.rb +54 -0
  74. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +101 -0
  75. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +59 -0
  76. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +97 -0
  77. data/lib/paperclip/media_type_spoof_detector.rb +90 -0
  78. data/lib/paperclip/missing_attachment_styles.rb +84 -0
  79. data/lib/paperclip/processor.rb +56 -0
  80. data/lib/paperclip/processor_helpers.rb +52 -0
  81. data/lib/paperclip/rails_environment.rb +21 -0
  82. data/lib/paperclip/railtie.rb +31 -0
  83. data/lib/paperclip/schema.rb +81 -0
  84. data/lib/paperclip/storage.rb +3 -0
  85. data/lib/paperclip/storage/filesystem.rb +99 -0
  86. data/lib/paperclip/storage/fog.rb +252 -0
  87. data/lib/paperclip/storage/s3.rb +461 -0
  88. data/lib/paperclip/style.rb +106 -0
  89. data/lib/paperclip/tempfile.rb +42 -0
  90. data/lib/paperclip/tempfile_factory.rb +22 -0
  91. data/lib/paperclip/thumbnail.rb +131 -0
  92. data/lib/paperclip/url_generator.rb +76 -0
  93. data/lib/paperclip/validators.rb +73 -0
  94. data/lib/paperclip/validators/attachment_content_type_validator.rb +88 -0
  95. data/lib/paperclip/validators/attachment_file_name_validator.rb +75 -0
  96. data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +28 -0
  97. data/lib/paperclip/validators/attachment_presence_validator.rb +28 -0
  98. data/lib/paperclip/validators/attachment_size_validator.rb +109 -0
  99. data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +29 -0
  100. data/lib/paperclip/version.rb +3 -0
  101. data/lib/tasks/paperclip.rake +140 -0
  102. data/paperclip.gemspec +50 -0
  103. data/shoulda_macros/paperclip.rb +134 -0
  104. data/spec/database.yml +4 -0
  105. data/spec/paperclip/attachment_definitions_spec.rb +13 -0
  106. data/spec/paperclip/attachment_processing_spec.rb +79 -0
  107. data/spec/paperclip/attachment_registry_spec.rb +158 -0
  108. data/spec/paperclip/attachment_spec.rb +1590 -0
  109. data/spec/paperclip/content_type_detector_spec.rb +47 -0
  110. data/spec/paperclip/file_command_content_type_detector_spec.rb +40 -0
  111. data/spec/paperclip/filename_cleaner_spec.rb +13 -0
  112. data/spec/paperclip/geometry_detector_spec.rb +38 -0
  113. data/spec/paperclip/geometry_parser_spec.rb +73 -0
  114. data/spec/paperclip/geometry_spec.rb +255 -0
  115. data/spec/paperclip/glue_spec.rb +42 -0
  116. data/spec/paperclip/has_attached_file_spec.rb +78 -0
  117. data/spec/paperclip/integration_spec.rb +702 -0
  118. data/spec/paperclip/interpolations_spec.rb +270 -0
  119. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +160 -0
  120. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +140 -0
  121. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +88 -0
  122. data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +17 -0
  123. data/spec/paperclip/io_adapters/file_adapter_spec.rb +131 -0
  124. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +137 -0
  125. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +8 -0
  126. data/spec/paperclip/io_adapters/nil_adapter_spec.rb +25 -0
  127. data/spec/paperclip/io_adapters/registry_spec.rb +35 -0
  128. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +64 -0
  129. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +146 -0
  130. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +221 -0
  131. data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +19 -0
  132. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +108 -0
  133. data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +69 -0
  134. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +88 -0
  135. data/spec/paperclip/media_type_spoof_detector_spec.rb +120 -0
  136. data/spec/paperclip/meta_class_spec.rb +30 -0
  137. data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +88 -0
  138. data/spec/paperclip/paperclip_spec.rb +196 -0
  139. data/spec/paperclip/plural_cache_spec.rb +37 -0
  140. data/spec/paperclip/processor_helpers_spec.rb +57 -0
  141. data/spec/paperclip/processor_spec.rb +26 -0
  142. data/spec/paperclip/rails_environment_spec.rb +30 -0
  143. data/spec/paperclip/rake_spec.rb +103 -0
  144. data/spec/paperclip/schema_spec.rb +252 -0
  145. data/spec/paperclip/storage/filesystem_spec.rb +79 -0
  146. data/spec/paperclip/storage/fog_spec.rb +560 -0
  147. data/spec/paperclip/storage/s3_live_spec.rb +188 -0
  148. data/spec/paperclip/storage/s3_spec.rb +1695 -0
  149. data/spec/paperclip/style_spec.rb +251 -0
  150. data/spec/paperclip/tempfile_factory_spec.rb +33 -0
  151. data/spec/paperclip/tempfile_spec.rb +35 -0
  152. data/spec/paperclip/thumbnail_spec.rb +504 -0
  153. data/spec/paperclip/url_generator_spec.rb +221 -0
  154. data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +322 -0
  155. data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +159 -0
  156. data/spec/paperclip/validators/attachment_presence_validator_spec.rb +85 -0
  157. data/spec/paperclip/validators/attachment_size_validator_spec.rb +235 -0
  158. data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +48 -0
  159. data/spec/paperclip/validators_spec.rb +164 -0
  160. data/spec/spec_helper.rb +45 -0
  161. data/spec/support/assertions.rb +84 -0
  162. data/spec/support/fake_model.rb +24 -0
  163. data/spec/support/fake_rails.rb +12 -0
  164. data/spec/support/fixtures/12k.png +0 -0
  165. data/spec/support/fixtures/50x50.png +0 -0
  166. data/spec/support/fixtures/5k.png +0 -0
  167. data/spec/support/fixtures/animated +0 -0
  168. data/spec/support/fixtures/animated.gif +0 -0
  169. data/spec/support/fixtures/animated.unknown +0 -0
  170. data/spec/support/fixtures/bad.png +1 -0
  171. data/spec/support/fixtures/empty.html +1 -0
  172. data/spec/support/fixtures/empty.xlsx +0 -0
  173. data/spec/support/fixtures/fog.yml +8 -0
  174. data/spec/support/fixtures/rotated.jpg +0 -0
  175. data/spec/support/fixtures/s3.yml +8 -0
  176. data/spec/support/fixtures/spaced file.jpg +0 -0
  177. data/spec/support/fixtures/spaced file.png +0 -0
  178. data/spec/support/fixtures/text.txt +1 -0
  179. data/spec/support/fixtures/twopage.pdf +0 -0
  180. data/spec/support/fixtures/uppercase.PNG +0 -0
  181. data/spec/support/matchers/accept.rb +5 -0
  182. data/spec/support/matchers/exist.rb +5 -0
  183. data/spec/support/matchers/have_column.rb +23 -0
  184. data/spec/support/mock_attachment.rb +24 -0
  185. data/spec/support/mock_interpolator.rb +24 -0
  186. data/spec/support/mock_url_generator_builder.rb +26 -0
  187. data/spec/support/model_reconstruction.rb +72 -0
  188. data/spec/support/reporting.rb +11 -0
  189. data/spec/support/test_data.rb +13 -0
  190. data/spec/support/version_helper.rb +9 -0
  191. metadata +586 -0
@@ -0,0 +1,75 @@
1
+ require "active_support/core_ext/module/delegation"
2
+
3
+ module Paperclip
4
+ class AbstractAdapter
5
+ OS_RESTRICTED_CHARACTERS = %r{[/:]}.freeze
6
+
7
+ attr_reader :content_type, :original_filename, :size, :tempfile
8
+ delegate :binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :readbyte, :rewind, :unlink, to: :@tempfile
9
+ alias :length :size
10
+
11
+ def initialize(target, options = {})
12
+ @target = target
13
+ @options = options
14
+ end
15
+
16
+ def fingerprint
17
+ @fingerprint ||= begin
18
+ digest = @options.fetch(:hash_digest).new
19
+ File.open(path, "rb") do |f|
20
+ buf = ""
21
+ digest.update(buf) while f.read(16384, buf)
22
+ end
23
+ digest.hexdigest
24
+ end
25
+ end
26
+
27
+ def read(length = nil, buffer = nil)
28
+ @tempfile.read(length, buffer)
29
+ end
30
+
31
+ def inspect
32
+ "#{self.class}: #{original_filename}"
33
+ end
34
+
35
+ def original_filename=(new_filename)
36
+ return unless new_filename
37
+
38
+ @original_filename = new_filename.gsub(OS_RESTRICTED_CHARACTERS, "_")
39
+ end
40
+
41
+ def nil?
42
+ false
43
+ end
44
+
45
+ def assignment?
46
+ true
47
+ end
48
+
49
+ private
50
+
51
+ def destination
52
+ @destination ||= TempfileFactory.new.generate(@original_filename.to_s)
53
+ end
54
+
55
+ def copy_to_tempfile(src)
56
+ link_or_copy_file(src.path, destination.path)
57
+ destination
58
+ end
59
+
60
+ def link_or_copy_file(src, dest)
61
+ begin
62
+ Paperclip.log("Trying to link #{src} to #{dest}")
63
+ FileUtils.ln(src, dest, force: true) # overwrite existing
64
+ rescue Errno::EXDEV, Errno::EPERM, Errno::ENOENT, Errno::EEXIST => e
65
+ Paperclip.log(
66
+ "Link failed with #{e.message}; copying link #{src} to #{dest}"
67
+ )
68
+ FileUtils.cp(src, dest)
69
+ end
70
+
71
+ @destination.close
72
+ @destination.open.binmode
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,47 @@
1
+ module Paperclip
2
+ class AttachmentAdapter < AbstractAdapter
3
+ def self.register
4
+ Paperclip.io_adapters.register self do |target|
5
+ Paperclip::Attachment === target || Paperclip::Style === target
6
+ end
7
+ end
8
+
9
+ def initialize(target, options = {})
10
+ super
11
+ @target, @style = case target
12
+ when Paperclip::Attachment
13
+ [target, :original]
14
+ when Paperclip::Style
15
+ [target.attachment, target.name]
16
+ end
17
+
18
+ cache_current_values
19
+ end
20
+
21
+ private
22
+
23
+ def cache_current_values
24
+ self.original_filename = @target.original_filename
25
+ @content_type = @target.content_type
26
+ @tempfile = copy_to_tempfile(@target)
27
+ @size = @tempfile.size || @target.size
28
+ end
29
+
30
+ def copy_to_tempfile(source)
31
+ if source.staged?
32
+ link_or_copy_file(source.staged_path(@style), destination.path)
33
+ else
34
+ begin
35
+ source.copy_to_local_file(@style, destination.path)
36
+ rescue Errno::EACCES
37
+ # clean up lingering tempfile if we cannot access source file
38
+ destination.close(true)
39
+ raise
40
+ end
41
+ end
42
+ destination
43
+ end
44
+ end
45
+ end
46
+
47
+ Paperclip::AttachmentAdapter.register
@@ -0,0 +1,22 @@
1
+ module Paperclip
2
+ class DataUriAdapter < StringioAdapter
3
+ def self.register
4
+ Paperclip.io_adapters.register self do |target|
5
+ String === target && target =~ REGEXP
6
+ end
7
+ end
8
+
9
+ REGEXP = /\Adata:([-\w]+\/[-\w\+\.]+)?;base64,(.*)/m.freeze
10
+
11
+ def initialize(target_uri, options = {})
12
+ super(extract_target(target_uri), options)
13
+ end
14
+
15
+ private
16
+
17
+ def extract_target(uri)
18
+ data_uri_parts = uri.match(REGEXP) || []
19
+ StringIO.new(Base64.decode64(data_uri_parts[2] || ""))
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ module Paperclip
2
+ class EmptyStringAdapter < AbstractAdapter
3
+ def self.register
4
+ Paperclip.io_adapters.register self do |target|
5
+ target.is_a?(String) && target.empty?
6
+ end
7
+ end
8
+
9
+ def nil?
10
+ false
11
+ end
12
+
13
+ def assignment?
14
+ false
15
+ end
16
+ end
17
+ end
18
+
19
+ Paperclip::EmptyStringAdapter.register
@@ -0,0 +1,26 @@
1
+ module Paperclip
2
+ class FileAdapter < AbstractAdapter
3
+ def self.register
4
+ Paperclip.io_adapters.register self do |target|
5
+ File === target || ::Tempfile === target
6
+ end
7
+ end
8
+
9
+ def initialize(target, options = {})
10
+ super
11
+ cache_current_values
12
+ end
13
+
14
+ private
15
+
16
+ def cache_current_values
17
+ self.original_filename = @target.original_filename if @target.respond_to?(:original_filename)
18
+ self.original_filename ||= File.basename(@target.path)
19
+ @tempfile = copy_to_tempfile(@target)
20
+ @content_type = ContentTypeDetector.new(@target.path).detect
21
+ @size = File.size(@target)
22
+ end
23
+ end
24
+ end
25
+
26
+ Paperclip::FileAdapter.register
@@ -0,0 +1,16 @@
1
+ module Paperclip
2
+ class HttpUrlProxyAdapter < UriAdapter
3
+ def self.register
4
+ Paperclip.io_adapters.register self do |target|
5
+ String === target && target =~ REGEXP
6
+ end
7
+ end
8
+
9
+ REGEXP = /\Ahttps?:\/\//.freeze
10
+
11
+ def initialize(target, options = {})
12
+ escaped = URI.escape(target)
13
+ super(URI(target == URI.unescape(target) ? escaped : target), options)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module Paperclip
2
+ class IdentityAdapter < AbstractAdapter
3
+ def self.register
4
+ Paperclip.io_adapters.register Paperclip::IdentityAdapter.new do |target|
5
+ Paperclip.io_adapters.registered?(target)
6
+ end
7
+ end
8
+
9
+ def initialize; end
10
+
11
+ def new(target, _)
12
+ target
13
+ end
14
+ end
15
+ end
16
+
17
+ Paperclip::IdentityAdapter.register
@@ -0,0 +1,37 @@
1
+ module Paperclip
2
+ class NilAdapter < AbstractAdapter
3
+ def self.register
4
+ Paperclip.io_adapters.register self do |target|
5
+ target.nil? || ((Paperclip::Attachment === target) && !target.present?)
6
+ end
7
+ end
8
+
9
+ def initialize(_target, _options = {}); end
10
+
11
+ def original_filename
12
+ ""
13
+ end
14
+
15
+ def content_type
16
+ ""
17
+ end
18
+
19
+ def size
20
+ 0
21
+ end
22
+
23
+ def nil?
24
+ true
25
+ end
26
+
27
+ def read(*_args)
28
+ nil
29
+ end
30
+
31
+ def eof?
32
+ true
33
+ end
34
+ end
35
+ end
36
+
37
+ Paperclip::NilAdapter.register
@@ -0,0 +1,36 @@
1
+ module Paperclip
2
+ class AdapterRegistry
3
+ class NoHandlerError < Paperclip::Error; end
4
+
5
+ attr_reader :registered_handlers
6
+
7
+ def initialize
8
+ @registered_handlers = []
9
+ end
10
+
11
+ def register(handler_class, &block)
12
+ @registered_handlers << [block, handler_class]
13
+ end
14
+
15
+ def unregister(handler_class)
16
+ @registered_handlers.reject! { |_, klass| klass == handler_class }
17
+ end
18
+
19
+ def handler_for(target)
20
+ @registered_handlers.each do |tester, handler|
21
+ return handler if tester.call(target)
22
+ end
23
+ raise NoHandlerError.new("No handler found for #{target.inspect}")
24
+ end
25
+
26
+ def registered?(target)
27
+ @registered_handlers.any? do |_tester, handler|
28
+ handler === target
29
+ end
30
+ end
31
+
32
+ def for(target, options = {})
33
+ handler_for(target).new(target, options)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ module Paperclip
2
+ class StringioAdapter < AbstractAdapter
3
+ def self.register
4
+ Paperclip.io_adapters.register self do |target|
5
+ StringIO === target
6
+ end
7
+ end
8
+
9
+ def initialize(target, options = {})
10
+ super
11
+ cache_current_values
12
+ end
13
+
14
+ attr_writer :content_type
15
+
16
+ private
17
+
18
+ def cache_current_values
19
+ self.original_filename = @target.original_filename if @target.respond_to?(:original_filename)
20
+ self.original_filename ||= "data"
21
+ @tempfile = copy_to_tempfile(@target)
22
+ @content_type = ContentTypeDetector.new(@tempfile.path).detect
23
+ @size = @target.size
24
+ end
25
+
26
+ def copy_to_tempfile(source)
27
+ while data = source.read(16 * 1024)
28
+ destination.write(data)
29
+ end
30
+ destination.rewind
31
+ destination
32
+ end
33
+ end
34
+ end
35
+
36
+ Paperclip::StringioAdapter.register
@@ -0,0 +1,44 @@
1
+ module Paperclip
2
+ class UploadedFileAdapter < AbstractAdapter
3
+ def self.register
4
+ Paperclip.io_adapters.register self do |target|
5
+ target.class.name.include?("UploadedFile")
6
+ end
7
+ end
8
+
9
+ def initialize(target, options = {})
10
+ super
11
+ cache_current_values
12
+
13
+ @tempfile = if @target.respond_to?(:tempfile)
14
+ copy_to_tempfile(@target.tempfile)
15
+ else
16
+ copy_to_tempfile(@target)
17
+ end
18
+ end
19
+
20
+ class << self
21
+ attr_accessor :content_type_detector
22
+ end
23
+
24
+ private
25
+
26
+ def cache_current_values
27
+ self.original_filename = @target.original_filename
28
+ @content_type = determine_content_type
29
+ @size = File.size(@target.path)
30
+ end
31
+
32
+ def content_type_detector
33
+ self.class.content_type_detector || Paperclip::ContentTypeDetector
34
+ end
35
+
36
+ def determine_content_type
37
+ content_type = @target.content_type.to_s.strip
38
+ content_type = content_type_detector.new(@target.path).detect if content_type_detector
39
+ content_type
40
+ end
41
+ end
42
+ end
43
+
44
+ Paperclip::UploadedFileAdapter.register
@@ -0,0 +1,68 @@
1
+ require "open-uri"
2
+
3
+ module Paperclip
4
+ class UriAdapter < AbstractAdapter
5
+ attr_writer :content_type
6
+
7
+ def self.register
8
+ Paperclip.io_adapters.register self do |target|
9
+ target.is_a?(URI)
10
+ end
11
+ end
12
+
13
+ def initialize(target, options = {})
14
+ super
15
+ @content = download_content
16
+ cache_current_values
17
+ @tempfile = copy_to_tempfile(@content)
18
+ end
19
+
20
+ private
21
+
22
+ def cache_current_values
23
+ self.content_type = content_type_from_content || "text/html"
24
+
25
+ self.original_filename = filename_from_content_disposition ||
26
+ filename_from_path || default_filename
27
+ @size = @content.size
28
+ end
29
+
30
+ def content_type_from_content
31
+ @content.meta["content-type"].presence
32
+ end
33
+
34
+ def filename_from_content_disposition
35
+ if @content.meta.key?("content-disposition") && @content.meta["content-disposition"].match(/filename/i)
36
+ # can include both filename and filename* values according to RCF6266. filename should come first
37
+ _, filename = @content.meta["content-disposition"].split(/filename\*?\s*=\s*/i)
38
+
39
+ # filename can be enclosed in quotes or not
40
+ matches = filename.match(/"(.*)"/)
41
+ matches ? matches[1] : filename.split(";")[0]
42
+ end
43
+ end
44
+
45
+ def filename_from_path
46
+ @target.path.split("/").last
47
+ end
48
+
49
+ def default_filename
50
+ "index.html"
51
+ end
52
+
53
+ def download_content
54
+ options = { read_timeout: Paperclip.options[:read_timeout] }.compact
55
+
56
+ open(@target, **options)
57
+ end
58
+
59
+ def copy_to_tempfile(src)
60
+ while data = src.read(16 * 1024)
61
+ destination.write(data)
62
+ end
63
+ src.close
64
+ destination.rewind
65
+ destination
66
+ end
67
+ end
68
+ end