carrierwave 0.9.0 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of carrierwave might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/README.md +362 -116
- data/lib/carrierwave/compatibility/paperclip.rb +29 -21
- data/lib/carrierwave/downloader/base.rb +83 -0
- data/lib/carrierwave/downloader/remote_file.rb +65 -0
- data/lib/carrierwave/error.rb +1 -0
- data/lib/carrierwave/locale/en.yml +7 -4
- data/lib/carrierwave/mount.rb +238 -186
- data/lib/carrierwave/mounter.rb +188 -0
- data/lib/carrierwave/orm/activerecord.rb +60 -24
- data/lib/carrierwave/processing/mini_magick.rb +139 -78
- data/lib/carrierwave/processing/rmagick.rb +68 -23
- data/lib/carrierwave/processing.rb +0 -1
- data/lib/carrierwave/sanitized_file.rb +67 -27
- data/lib/carrierwave/storage/abstract.rb +15 -2
- data/lib/carrierwave/storage/file.rb +69 -2
- data/lib/carrierwave/storage/fog.rb +180 -41
- data/lib/carrierwave/storage.rb +1 -7
- data/lib/carrierwave/test/matchers.rb +77 -12
- data/lib/carrierwave/uploader/cache.rb +74 -38
- data/lib/carrierwave/uploader/callbacks.rb +0 -2
- data/lib/carrierwave/uploader/configuration.rb +72 -6
- data/lib/carrierwave/uploader/content_type_blacklist.rb +48 -0
- data/lib/carrierwave/uploader/content_type_whitelist.rb +48 -0
- data/lib/carrierwave/uploader/default_url.rb +3 -5
- data/lib/carrierwave/uploader/download.rb +5 -69
- data/lib/carrierwave/uploader/extension_blacklist.rb +14 -10
- data/lib/carrierwave/uploader/extension_whitelist.rb +13 -10
- data/lib/carrierwave/uploader/file_size.rb +43 -0
- data/lib/carrierwave/uploader/mountable.rb +13 -8
- data/lib/carrierwave/uploader/processing.rb +15 -17
- data/lib/carrierwave/uploader/proxy.rb +16 -7
- data/lib/carrierwave/uploader/remove.rb +0 -2
- data/lib/carrierwave/uploader/serialization.rb +3 -5
- data/lib/carrierwave/uploader/store.rb +17 -24
- data/lib/carrierwave/uploader/url.rb +3 -5
- data/lib/carrierwave/uploader/versions.rb +117 -86
- data/lib/carrierwave/uploader.rb +6 -2
- data/lib/carrierwave/utilities/uri.rb +5 -6
- data/lib/carrierwave/utilities.rb +1 -3
- data/lib/carrierwave/validations/active_model.rb +3 -7
- data/lib/carrierwave/version.rb +1 -1
- data/lib/carrierwave.rb +36 -3
- data/lib/generators/templates/uploader.rb +4 -8
- data/lib/generators/uploader_generator.rb +1 -1
- metadata +195 -94
- data/lib/carrierwave/locale/cs.yml +0 -11
- data/lib/carrierwave/locale/de.yml +0 -11
- data/lib/carrierwave/locale/nl.yml +0 -11
- data/lib/carrierwave/locale/sk.yml +0 -11
- data/lib/carrierwave/processing/mime_types.rb +0 -73
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require 'securerandom'
|
2
2
|
|
3
3
|
module CarrierWave
|
4
4
|
|
@@ -8,15 +8,27 @@ module CarrierWave
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
+
class CacheCounter
|
12
|
+
@@counter = 0
|
13
|
+
|
14
|
+
def self.increment
|
15
|
+
@@counter += 1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
11
19
|
##
|
12
20
|
# Generates a unique cache id for use in the caching system
|
13
21
|
#
|
14
22
|
# === Returns
|
15
23
|
#
|
16
|
-
# [String] a cache id in the format TIMEINT-PID-RND
|
24
|
+
# [String] a cache id in the format TIMEINT-PID-COUNTER-RND
|
17
25
|
#
|
18
26
|
def self.generate_cache_id
|
19
|
-
Time.now.utc.to_i
|
27
|
+
[Time.now.utc.to_i,
|
28
|
+
SecureRandom.random_number(1_000_000_000_000_000),
|
29
|
+
'%04d' % (CarrierWave::CacheCounter.increment % 10_000),
|
30
|
+
'%04d' % SecureRandom.random_number(10_000)
|
31
|
+
].map(&:to_s).join('-')
|
20
32
|
end
|
21
33
|
|
22
34
|
module Uploader
|
@@ -26,6 +38,16 @@ module CarrierWave
|
|
26
38
|
include CarrierWave::Uploader::Callbacks
|
27
39
|
include CarrierWave::Uploader::Configuration
|
28
40
|
|
41
|
+
included do
|
42
|
+
prepend Module.new {
|
43
|
+
def initialize(*)
|
44
|
+
super
|
45
|
+
@staged = false
|
46
|
+
end
|
47
|
+
}
|
48
|
+
attr_accessor :staged
|
49
|
+
end
|
50
|
+
|
29
51
|
module ClassMethods
|
30
52
|
|
31
53
|
##
|
@@ -42,13 +64,7 @@ module CarrierWave
|
|
42
64
|
# It's recommended that you keep cache files in one place only.
|
43
65
|
#
|
44
66
|
def clean_cached_files!(seconds=60*60*24)
|
45
|
-
|
46
|
-
time = dir.scan(/(\d+)-\d+-\d+/).first.map { |t| t.to_i }
|
47
|
-
time = Time.at(*time)
|
48
|
-
if time < (Time.now.utc - seconds)
|
49
|
-
FileUtils.rm_rf(dir)
|
50
|
-
end
|
51
|
-
end
|
67
|
+
(cache_storage || storage).new(CarrierWave::Uploader::Base.new).clean_cache!(seconds)
|
52
68
|
end
|
53
69
|
end
|
54
70
|
|
@@ -74,16 +90,8 @@ module CarrierWave
|
|
74
90
|
end
|
75
91
|
|
76
92
|
def sanitized_file
|
77
|
-
|
78
|
-
|
79
|
-
sanitized = CarrierWave::Storage::Fog.new(self).retrieve!(File.basename(_content.path))
|
80
|
-
sanitized.read if sanitized.exists?
|
81
|
-
|
82
|
-
else
|
83
|
-
sanitized = SanitizedFile.new :tempfile => StringIO.new(file.read),
|
84
|
-
:filename => File.basename(path), :content_type => file.content_type
|
85
|
-
end
|
86
|
-
sanitized
|
93
|
+
ActiveSupport::Deprecation.warn('#sanitized_file is deprecated, use #file instead.')
|
94
|
+
file
|
87
95
|
end
|
88
96
|
|
89
97
|
##
|
@@ -91,10 +99,10 @@ module CarrierWave
|
|
91
99
|
#
|
92
100
|
# === Returns
|
93
101
|
#
|
94
|
-
# [String] a cache name, in the format
|
102
|
+
# [String] a cache name, in the format TIMEINT-PID-COUNTER-RND/filename.txt
|
95
103
|
#
|
96
104
|
def cache_name
|
97
|
-
File.join(cache_id, full_original_filename) if cache_id
|
105
|
+
File.join(cache_id, full_original_filename) if cache_id && original_filename
|
98
106
|
end
|
99
107
|
|
100
108
|
##
|
@@ -113,24 +121,31 @@ module CarrierWave
|
|
113
121
|
#
|
114
122
|
# [CarrierWave::FormNotMultipart] if the assigned parameter is a string
|
115
123
|
#
|
116
|
-
def cache!(new_file =
|
124
|
+
def cache!(new_file = file)
|
117
125
|
new_file = CarrierWave::SanitizedFile.new(new_file)
|
126
|
+
return if new_file.empty?
|
118
127
|
|
119
|
-
|
120
|
-
raise CarrierWave::FormNotMultipart if new_file.is_path? && ensure_multipart_form
|
128
|
+
raise CarrierWave::FormNotMultipart if new_file.is_path? && ensure_multipart_form
|
121
129
|
|
122
|
-
|
123
|
-
self.cache_id = CarrierWave.generate_cache_id unless cache_id
|
130
|
+
self.cache_id = CarrierWave.generate_cache_id unless cache_id
|
124
131
|
|
125
|
-
|
126
|
-
|
132
|
+
@staged = true
|
133
|
+
@filename = new_file.filename
|
134
|
+
self.original_filename = new_file.filename
|
135
|
+
|
136
|
+
begin
|
137
|
+
# first, create a workfile on which we perform processings
|
138
|
+
if move_to_cache
|
139
|
+
@file = new_file.move_to(File.expand_path(workfile_path, root), permissions, directory_permissions)
|
140
|
+
else
|
141
|
+
@file = new_file.copy_to(File.expand_path(workfile_path, root), permissions, directory_permissions)
|
142
|
+
end
|
127
143
|
|
128
|
-
|
129
|
-
|
130
|
-
else
|
131
|
-
@file = new_file.copy_to(cache_path, permissions, directory_permissions)
|
132
|
-
end
|
144
|
+
with_callbacks(:cache, @file) do
|
145
|
+
@file = cache_storage.cache!(@file)
|
133
146
|
end
|
147
|
+
ensure
|
148
|
+
FileUtils.rm_rf(workfile_path(''))
|
134
149
|
end
|
135
150
|
end
|
136
151
|
|
@@ -148,15 +163,31 @@ module CarrierWave
|
|
148
163
|
def retrieve_from_cache!(cache_name)
|
149
164
|
with_callbacks(:retrieve_from_cache, cache_name) do
|
150
165
|
self.cache_id, self.original_filename = cache_name.to_s.split('/', 2)
|
166
|
+
@staged = true
|
151
167
|
@filename = original_filename
|
152
|
-
@file =
|
168
|
+
@file = cache_storage.retrieve_from_cache!(full_filename(original_filename))
|
153
169
|
end
|
154
170
|
end
|
155
171
|
|
172
|
+
##
|
173
|
+
# Calculates the path where the cache file should be stored.
|
174
|
+
#
|
175
|
+
# === Parameters
|
176
|
+
#
|
177
|
+
# [for_file (String)] name of the file <optional>
|
178
|
+
#
|
179
|
+
# === Returns
|
180
|
+
#
|
181
|
+
# [String] the cache path
|
182
|
+
#
|
183
|
+
def cache_path(for_file=full_filename(original_filename))
|
184
|
+
File.join(*[cache_dir, @cache_id, for_file].compact)
|
185
|
+
end
|
186
|
+
|
156
187
|
private
|
157
188
|
|
158
|
-
def
|
159
|
-
File.
|
189
|
+
def workfile_path(for_file=original_filename)
|
190
|
+
File.join(CarrierWave.tmp_path, @cache_id, version_name.to_s, for_file)
|
160
191
|
end
|
161
192
|
|
162
193
|
attr_reader :cache_id, :original_filename
|
@@ -165,7 +196,9 @@ module CarrierWave
|
|
165
196
|
alias_method :full_original_filename, :original_filename
|
166
197
|
|
167
198
|
def cache_id=(cache_id)
|
168
|
-
|
199
|
+
# Earlier version used 3 part cache_id. Thus we should allow for
|
200
|
+
# the cache_id to have both 3 part and 4 part formats.
|
201
|
+
raise CarrierWave::InvalidParameter, "invalid cache id" unless cache_id =~ /\A(-)?[\d]+\-[\d]+(\-[\d]{4})?\-[\d]{4}\z/
|
169
202
|
@cache_id = cache_id
|
170
203
|
end
|
171
204
|
|
@@ -174,6 +207,9 @@ module CarrierWave
|
|
174
207
|
@original_filename = filename
|
175
208
|
end
|
176
209
|
|
210
|
+
def cache_storage
|
211
|
+
@cache_storage ||= (self.class.cache_storage || self.class.storage).new(self)
|
212
|
+
end
|
177
213
|
end # Cache
|
178
214
|
end # Uploader
|
179
215
|
end # CarrierWave
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'carrierwave/downloader/base'
|
2
|
+
|
1
3
|
module CarrierWave
|
2
4
|
|
3
5
|
module Uploader
|
@@ -5,7 +7,7 @@ module CarrierWave
|
|
5
7
|
extend ActiveSupport::Concern
|
6
8
|
|
7
9
|
included do
|
8
|
-
class_attribute :_storage, :instance_writer => false
|
10
|
+
class_attribute :_storage, :_cache_storage, :instance_writer => false
|
9
11
|
|
10
12
|
add_config :root
|
11
13
|
add_config :base_path
|
@@ -21,14 +23,17 @@ module CarrierWave
|
|
21
23
|
add_config :move_to_cache
|
22
24
|
add_config :move_to_store
|
23
25
|
add_config :remove_previously_stored_files_after_update
|
26
|
+
add_config :downloader
|
24
27
|
|
25
28
|
# fog
|
29
|
+
add_deprecated_config :fog_provider
|
26
30
|
add_config :fog_attributes
|
27
31
|
add_config :fog_credentials
|
28
32
|
add_config :fog_directory
|
29
33
|
add_config :fog_public
|
30
34
|
add_config :fog_authenticated_url_expiration
|
31
35
|
add_config :fog_use_ssl_for_aws
|
36
|
+
add_config :fog_aws_accelerate
|
32
37
|
|
33
38
|
# Mounting
|
34
39
|
add_config :ignore_integrity_errors
|
@@ -38,6 +43,7 @@ module CarrierWave
|
|
38
43
|
add_config :validate_processing
|
39
44
|
add_config :validate_download
|
40
45
|
add_config :mount_on
|
46
|
+
add_config :cache_only
|
41
47
|
|
42
48
|
# set default values
|
43
49
|
reset_config
|
@@ -69,20 +75,58 @@ module CarrierWave
|
|
69
75
|
# storage MyCustomStorageEngine
|
70
76
|
#
|
71
77
|
def storage(storage = nil)
|
72
|
-
|
73
|
-
|
78
|
+
case storage
|
79
|
+
when Symbol
|
80
|
+
if storage_engine = storage_engines[storage]
|
81
|
+
self._storage = eval storage_engine
|
82
|
+
else
|
83
|
+
raise CarrierWave::UnknownStorageError, "Unknown storage: #{storage}"
|
84
|
+
end
|
85
|
+
when nil
|
86
|
+
storage
|
87
|
+
else
|
88
|
+
self._storage = storage
|
74
89
|
end
|
75
90
|
_storage
|
76
91
|
end
|
77
92
|
alias_method :storage=, :storage
|
78
93
|
|
94
|
+
##
|
95
|
+
# Sets the cache storage engine to be used when storing cache files with this uploader.
|
96
|
+
# Same as .storage except for required methods being #cache!(CarrierWave::SanitizedFile),
|
97
|
+
# #retrieve_from_cache! and #delete_dir!.
|
98
|
+
#
|
99
|
+
# === Parameters
|
100
|
+
#
|
101
|
+
# [storage (Symbol, Class)] The cache storage engine to use for this uploader
|
102
|
+
#
|
103
|
+
# === Returns
|
104
|
+
#
|
105
|
+
# [Class] the cache storage engine to be used with this uploader
|
106
|
+
#
|
107
|
+
# === Examples
|
108
|
+
#
|
109
|
+
# cache_storage :file
|
110
|
+
# cache_storage CarrierWave::Storage::File
|
111
|
+
# cache_storage MyCustomStorageEngine
|
112
|
+
#
|
113
|
+
def cache_storage(storage = false)
|
114
|
+
unless storage == false
|
115
|
+
self._cache_storage = storage.is_a?(Symbol) ? eval(storage_engines[storage]) : storage
|
116
|
+
end
|
117
|
+
_cache_storage
|
118
|
+
end
|
119
|
+
alias_method :cache_storage=, :cache_storage
|
120
|
+
|
79
121
|
def add_config(name)
|
80
122
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
123
|
+
@#{name} = nil
|
124
|
+
|
81
125
|
def self.#{name}(value=nil)
|
82
126
|
@#{name} = value if value
|
83
127
|
return @#{name} if self.object_id == #{self.object_id} || defined?(@#{name})
|
84
128
|
name = superclass.#{name}
|
85
|
-
return nil if name.nil? && !instance_variable_defined?(
|
129
|
+
return nil if name.nil? && !instance_variable_defined?(:@#{name})
|
86
130
|
@#{name} = name && !name.is_a?(Module) && !name.is_a?(Symbol) && !name.is_a?(Numeric) && !name.is_a?(TrueClass) && !name.is_a?(FalseClass) ? name.dup : name
|
87
131
|
end
|
88
132
|
|
@@ -99,13 +143,33 @@ module CarrierWave
|
|
99
143
|
value = self.class.#{name} unless instance_variable_defined?(:@#{name})
|
100
144
|
if value.instance_of?(Proc)
|
101
145
|
value.arity >= 1 ? value.call(self) : value.call
|
102
|
-
else
|
146
|
+
else
|
103
147
|
value
|
104
148
|
end
|
105
149
|
end
|
106
150
|
RUBY
|
107
151
|
end
|
108
152
|
|
153
|
+
def add_deprecated_config(name)
|
154
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
155
|
+
def self.#{name}(value=nil)
|
156
|
+
ActiveSupport::Deprecation.warn "##{name} is deprecated and has no effect"
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.#{name}=(value)
|
160
|
+
ActiveSupport::Deprecation.warn "##{name} is deprecated and has no effect"
|
161
|
+
end
|
162
|
+
|
163
|
+
def #{name}=(value)
|
164
|
+
ActiveSupport::Deprecation.warn "##{name} is deprecated and has no effect"
|
165
|
+
end
|
166
|
+
|
167
|
+
def #{name}
|
168
|
+
ActiveSupport::Deprecation.warn "##{name} is deprecated and has no effect"
|
169
|
+
end
|
170
|
+
RUBY
|
171
|
+
end
|
172
|
+
|
109
173
|
def configure
|
110
174
|
yield self
|
111
175
|
end
|
@@ -122,17 +186,20 @@ module CarrierWave
|
|
122
186
|
:fog => "CarrierWave::Storage::Fog"
|
123
187
|
}
|
124
188
|
config.storage = :file
|
189
|
+
config.cache_storage = nil
|
125
190
|
config.fog_attributes = {}
|
126
191
|
config.fog_credentials = {}
|
127
192
|
config.fog_public = true
|
128
193
|
config.fog_authenticated_url_expiration = 600
|
129
194
|
config.fog_use_ssl_for_aws = true
|
195
|
+
config.fog_aws_accelerate = false
|
130
196
|
config.store_dir = 'uploads'
|
131
197
|
config.cache_dir = 'uploads/tmp'
|
132
198
|
config.delete_tmp_file_after_storage = true
|
133
199
|
config.move_to_cache = false
|
134
200
|
config.move_to_store = false
|
135
201
|
config.remove_previously_stored_files_after_update = true
|
202
|
+
config.downloader = CarrierWave::Downloader::Base
|
136
203
|
config.ignore_integrity_errors = true
|
137
204
|
config.ignore_processing_errors = true
|
138
205
|
config.ignore_download_errors = true
|
@@ -150,4 +217,3 @@ module CarrierWave
|
|
150
217
|
end
|
151
218
|
end
|
152
219
|
end
|
153
|
-
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
module Uploader
|
3
|
+
module ContentTypeBlacklist
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
before :cache, :check_content_type_blacklist!
|
8
|
+
end
|
9
|
+
|
10
|
+
##
|
11
|
+
# Override this method in your uploader to provide a blacklist of files content types
|
12
|
+
# which are not allowed to be uploaded.
|
13
|
+
# Not only strings but Regexp are allowed as well.
|
14
|
+
#
|
15
|
+
# === Returns
|
16
|
+
#
|
17
|
+
# [NilClass, String, Regexp, Array[String, Regexp]] a blacklist of content types which are not allowed to be uploaded
|
18
|
+
#
|
19
|
+
# === Examples
|
20
|
+
#
|
21
|
+
# def content_type_blacklist
|
22
|
+
# %w(text/json application/json)
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# Basically the same, but using a Regexp:
|
26
|
+
#
|
27
|
+
# def content_type_blacklist
|
28
|
+
# [/(text|application)\/json/]
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
def content_type_blacklist; end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def check_content_type_blacklist!(new_file)
|
36
|
+
content_type = new_file.content_type
|
37
|
+
if content_type_blacklist && blacklisted_content_type?(content_type)
|
38
|
+
raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.content_type_blacklist_error", content_type: content_type)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def blacklisted_content_type?(content_type)
|
43
|
+
Array(content_type_blacklist).any? { |item| content_type =~ /#{item}/ }
|
44
|
+
end
|
45
|
+
|
46
|
+
end # ContentTypeBlacklist
|
47
|
+
end # Uploader
|
48
|
+
end # CarrierWave
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
module Uploader
|
3
|
+
module ContentTypeWhitelist
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
before :cache, :check_content_type_whitelist!
|
8
|
+
end
|
9
|
+
|
10
|
+
##
|
11
|
+
# Override this method in your uploader to provide a whitelist of files content types
|
12
|
+
# which are allowed to be uploaded.
|
13
|
+
# Not only strings but Regexp are allowed as well.
|
14
|
+
#
|
15
|
+
# === Returns
|
16
|
+
#
|
17
|
+
# [NilClass, String, Regexp, Array[String, Regexp]] a whitelist of content types which are allowed to be uploaded
|
18
|
+
#
|
19
|
+
# === Examples
|
20
|
+
#
|
21
|
+
# def content_type_whitelist
|
22
|
+
# %w(text/json application/json)
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# Basically the same, but using a Regexp:
|
26
|
+
#
|
27
|
+
# def content_type_whitelist
|
28
|
+
# [/(text|application)\/json/]
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
def content_type_whitelist; end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def check_content_type_whitelist!(new_file)
|
36
|
+
content_type = new_file.content_type
|
37
|
+
if content_type_whitelist && !whitelisted_content_type?(content_type)
|
38
|
+
raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.content_type_whitelist_error", content_type: content_type, allowed_types: Array(content_type_whitelist).join(", "))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def whitelisted_content_type?(content_type)
|
43
|
+
Array(content_type_whitelist).any? { |item| content_type =~ /#{item}/ }
|
44
|
+
end
|
45
|
+
|
46
|
+
end # ContentTypeWhitelist
|
47
|
+
end # Uploader
|
48
|
+
end # CarrierWave
|
@@ -1,19 +1,17 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module CarrierWave
|
4
2
|
module Uploader
|
5
3
|
module DefaultUrl
|
6
4
|
|
7
5
|
def url(*args)
|
8
|
-
super || default_url
|
6
|
+
super || default_url(*args)
|
9
7
|
end
|
10
8
|
|
11
9
|
##
|
12
10
|
# Override this method in your uploader to provide a default url
|
13
11
|
# in case no file has been cached/stored yet.
|
14
12
|
#
|
15
|
-
def default_url; end
|
13
|
+
def default_url(*args); end
|
16
14
|
|
17
15
|
end # DefaultPath
|
18
16
|
end # Uploader
|
19
|
-
end # CarrierWave
|
17
|
+
end # CarrierWave
|
@@ -1,7 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'open-uri'
|
4
|
-
|
5
1
|
module CarrierWave
|
6
2
|
module Uploader
|
7
3
|
module Download
|
@@ -11,78 +7,18 @@ module CarrierWave
|
|
11
7
|
include CarrierWave::Uploader::Configuration
|
12
8
|
include CarrierWave::Uploader::Cache
|
13
9
|
|
14
|
-
class RemoteFile
|
15
|
-
def initialize(uri)
|
16
|
-
@uri = uri
|
17
|
-
end
|
18
|
-
|
19
|
-
def original_filename
|
20
|
-
if file.meta.include? 'content-disposition'
|
21
|
-
match = file.meta['content-disposition'].match(/filename=(\"?)(.+)\1/)
|
22
|
-
return match[2] unless match.nil?
|
23
|
-
end
|
24
|
-
File.basename(file.base_uri.path)
|
25
|
-
end
|
26
|
-
|
27
|
-
def respond_to?(*args)
|
28
|
-
super or file.respond_to?(*args)
|
29
|
-
end
|
30
|
-
|
31
|
-
def http?
|
32
|
-
@uri.scheme =~ /^https?$/
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def file
|
38
|
-
if @file.blank?
|
39
|
-
@file = Kernel.open(@uri.to_s)
|
40
|
-
@file = @file.is_a?(String) ? StringIO.new(@file) : @file
|
41
|
-
end
|
42
|
-
@file
|
43
|
-
|
44
|
-
rescue Exception => e
|
45
|
-
raise CarrierWave::DownloadError, "could not download file: #{e.message}"
|
46
|
-
end
|
47
|
-
|
48
|
-
def method_missing(*args, &block)
|
49
|
-
file.send(*args, &block)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
##
|
54
|
-
# Caches the file by downloading it from the given URL.
|
55
|
-
#
|
56
|
-
# === Parameters
|
57
|
-
#
|
58
|
-
# [url (String)] The URL where the remote file is stored
|
59
|
-
#
|
60
|
-
def download!(uri)
|
61
|
-
unless uri.blank?
|
62
|
-
processed_uri = process_uri(uri)
|
63
|
-
file = RemoteFile.new(processed_uri)
|
64
|
-
raise CarrierWave::DownloadError, "trying to download a file which is not served over HTTP" unless file.http?
|
65
|
-
cache!(file)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
10
|
##
|
70
|
-
#
|
11
|
+
# Caches the file by downloading it from the given URL, using downloader.
|
71
12
|
#
|
72
13
|
# === Parameters
|
73
14
|
#
|
74
15
|
# [url (String)] The URL where the remote file is stored
|
16
|
+
# [remote_headers (Hash)] Request headers
|
75
17
|
#
|
76
|
-
def
|
77
|
-
|
78
|
-
|
79
|
-
uri_parts = uri.split('?')
|
80
|
-
# regexp from Ruby's URI::Parser#regexp[:UNSAFE], with [] specifically removed
|
81
|
-
encoded_uri = URI.encode(uri_parts.shift, /[^\-_.!~*'()a-zA-Z\d;\/?:@&=+$,]/)
|
82
|
-
encoded_uri << '?' << URI.encode(uri_parts.join('?')) if uri_parts.any?
|
83
|
-
URI.parse(encoded_uri) rescue raise CarrierWave::DownloadError, "couldn't parse URL"
|
18
|
+
def download!(uri, remote_headers = {})
|
19
|
+
file = downloader.new(self).download(uri, remote_headers)
|
20
|
+
cache!(file)
|
84
21
|
end
|
85
|
-
|
86
22
|
end # Download
|
87
23
|
end # Uploader
|
88
24
|
end # CarrierWave
|
@@ -4,7 +4,7 @@ module CarrierWave
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
-
before :cache, :
|
7
|
+
before :cache, :check_extension_blacklist!
|
8
8
|
end
|
9
9
|
|
10
10
|
##
|
@@ -16,32 +16,36 @@ module CarrierWave
|
|
16
16
|
# the Regexp expression, also case insensitive.
|
17
17
|
#
|
18
18
|
# === Returns
|
19
|
-
|
20
|
-
# [NilClass, Array[String,Regexp]] a black list of extensions which are prohibited to be uploaded
|
19
|
+
|
20
|
+
# [NilClass, String, Regexp, Array[String, Regexp]] a black list of extensions which are prohibited to be uploaded
|
21
21
|
#
|
22
22
|
# === Examples
|
23
23
|
#
|
24
|
-
# def
|
24
|
+
# def extension_blacklist
|
25
25
|
# %w(swf tiff)
|
26
26
|
# end
|
27
27
|
#
|
28
28
|
# Basically the same, but using a Regexp:
|
29
29
|
#
|
30
|
-
# def
|
30
|
+
# def extension_blacklist
|
31
31
|
# [/swf/, 'tiff']
|
32
32
|
# end
|
33
33
|
#
|
34
|
-
|
35
|
-
def
|
34
|
+
|
35
|
+
def extension_blacklist; end
|
36
36
|
|
37
37
|
private
|
38
38
|
|
39
|
-
def
|
39
|
+
def check_extension_blacklist!(new_file)
|
40
40
|
extension = new_file.extension.to_s
|
41
|
-
if
|
42
|
-
raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.
|
41
|
+
if extension_blacklist && blacklisted_extension?(extension)
|
42
|
+
raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_blacklist_error", extension: new_file.extension.inspect, prohibited_types: Array(extension_blacklist).join(", "))
|
43
43
|
end
|
44
44
|
end
|
45
|
+
|
46
|
+
def blacklisted_extension?(extension)
|
47
|
+
Array(extension_blacklist).any? { |item| extension =~ /\A#{item}\z/i }
|
48
|
+
end
|
45
49
|
end
|
46
50
|
end
|
47
51
|
end
|
@@ -1,12 +1,10 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module CarrierWave
|
4
2
|
module Uploader
|
5
3
|
module ExtensionWhitelist
|
6
4
|
extend ActiveSupport::Concern
|
7
5
|
|
8
6
|
included do
|
9
|
-
before :cache, :
|
7
|
+
before :cache, :check_extension_whitelist!
|
10
8
|
end
|
11
9
|
|
12
10
|
##
|
@@ -19,31 +17,36 @@ module CarrierWave
|
|
19
17
|
#
|
20
18
|
# === Returns
|
21
19
|
#
|
22
|
-
# [NilClass, Array[String,Regexp]] a white list of extensions which are allowed to be uploaded
|
20
|
+
# [NilClass, String, Regexp, Array[String, Regexp]] a white list of extensions which are allowed to be uploaded
|
23
21
|
#
|
24
22
|
# === Examples
|
25
23
|
#
|
26
|
-
# def
|
24
|
+
# def extension_whitelist
|
27
25
|
# %w(jpg jpeg gif png)
|
28
26
|
# end
|
29
27
|
#
|
30
28
|
# Basically the same, but using a Regexp:
|
31
29
|
#
|
32
|
-
# def
|
30
|
+
# def extension_whitelist
|
33
31
|
# [/jpe?g/, 'gif', 'png']
|
34
32
|
# end
|
35
33
|
#
|
36
|
-
def
|
34
|
+
def extension_whitelist; end
|
37
35
|
|
38
36
|
private
|
39
37
|
|
40
|
-
def
|
38
|
+
def check_extension_whitelist!(new_file)
|
41
39
|
extension = new_file.extension.to_s
|
42
|
-
if
|
43
|
-
raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.
|
40
|
+
if extension_whitelist && !whitelisted_extension?(extension)
|
41
|
+
raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_whitelist_error", extension: new_file.extension.inspect, allowed_types: Array(extension_whitelist).join(", "))
|
44
42
|
end
|
45
43
|
end
|
46
44
|
|
45
|
+
def whitelisted_extension?(extension)
|
46
|
+
downcase_extension = extension.downcase
|
47
|
+
Array(extension_whitelist).any? { |item| downcase_extension =~ /\A#{item}\z/i }
|
48
|
+
end
|
49
|
+
|
47
50
|
end # ExtensionWhitelist
|
48
51
|
end # Uploader
|
49
52
|
end # CarrierWave
|