carrierwave 0.10.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 +5 -5
- data/README.md +307 -121
- data/lib/carrierwave/compatibility/paperclip.rb +0 -2
- 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 +229 -180
- data/lib/carrierwave/mounter.rb +188 -0
- data/lib/carrierwave/orm/activerecord.rb +59 -24
- data/lib/carrierwave/processing/mini_magick.rb +137 -83
- data/lib/carrierwave/processing/rmagick.rb +65 -8
- data/lib/carrierwave/processing.rb +0 -1
- data/lib/carrierwave/sanitized_file.rb +67 -32
- data/lib/carrierwave/storage/abstract.rb +15 -2
- data/lib/carrierwave/storage/file.rb +69 -2
- data/lib/carrierwave/storage/fog.rb +177 -39
- 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 +71 -13
- 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 +4 -74
- 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 +10 -10
- data/lib/carrierwave/uploader/proxy.rb +6 -8
- data/lib/carrierwave/uploader/remove.rb +0 -2
- data/lib/carrierwave/uploader/serialization.rb +2 -4
- data/lib/carrierwave/uploader/store.rb +17 -24
- data/lib/carrierwave/uploader/url.rb +3 -5
- data/lib/carrierwave/uploader/versions.rb +123 -93
- data/lib/carrierwave/uploader.rb +6 -2
- data/lib/carrierwave/utilities/uri.rb +5 -6
- data/lib/carrierwave/utilities.rb +0 -3
- data/lib/carrierwave/validations/active_model.rb +3 -5
- data/lib/carrierwave/version.rb +1 -1
- data/lib/carrierwave.rb +34 -8
- data/lib/generators/templates/uploader.rb +4 -8
- metadata +130 -57
- data/lib/carrierwave/locale/cs.yml +0 -11
- data/lib/carrierwave/locale/de.yml +0 -11
- data/lib/carrierwave/locale/el.yml +0 -11
- data/lib/carrierwave/locale/es.yml +0 -11
- data/lib/carrierwave/locale/fr.yml +0 -11
- data/lib/carrierwave/locale/ja.yml +0 -11
- data/lib/carrierwave/locale/nb.yml +0 -11
- data/lib/carrierwave/locale/nl.yml +0 -11
- data/lib/carrierwave/locale/pl.yml +0 -11
- data/lib/carrierwave/locale/pt-BR.yml +0 -11
- data/lib/carrierwave/locale/pt-PT.yml +0 -11
- data/lib/carrierwave/locale/ru.yml +0 -11
- data/lib/carrierwave/locale/sk.yml +0 -11
- data/lib/carrierwave/locale/tr.yml +0 -11
- data/lib/carrierwave/processing/mime_types.rb +0 -74
- data/lib/carrierwave/utilities/deprecation.rb +0 -18
@@ -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,36 +75,66 @@ 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
|
81
|
-
|
82
|
-
# see #1198. This will hopefully no longer be necessary after fog 2.0
|
83
|
-
Fog::Storage.new(fog_credentials) if fog_credentials.present?
|
84
|
-
end
|
123
|
+
@#{name} = nil
|
85
124
|
|
86
125
|
def self.#{name}(value=nil)
|
87
126
|
@#{name} = value if value
|
88
|
-
eager_load_fog(value) if value && '#{name}' == 'fog_credentials'
|
89
127
|
return @#{name} if self.object_id == #{self.object_id} || defined?(@#{name})
|
90
128
|
name = superclass.#{name}
|
91
|
-
return nil if name.nil? && !instance_variable_defined?(
|
129
|
+
return nil if name.nil? && !instance_variable_defined?(:@#{name})
|
92
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
|
93
131
|
end
|
94
132
|
|
95
133
|
def self.#{name}=(value)
|
96
|
-
eager_load_fog(value) if '#{name}' == 'fog_credentials'
|
97
134
|
@#{name} = value
|
98
135
|
end
|
99
136
|
|
100
137
|
def #{name}=(value)
|
101
|
-
self.class.eager_load_fog(value) if '#{name}' == 'fog_credentials'
|
102
138
|
@#{name} = value
|
103
139
|
end
|
104
140
|
|
@@ -107,13 +143,33 @@ module CarrierWave
|
|
107
143
|
value = self.class.#{name} unless instance_variable_defined?(:@#{name})
|
108
144
|
if value.instance_of?(Proc)
|
109
145
|
value.arity >= 1 ? value.call(self) : value.call
|
110
|
-
else
|
146
|
+
else
|
111
147
|
value
|
112
148
|
end
|
113
149
|
end
|
114
150
|
RUBY
|
115
151
|
end
|
116
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
|
+
|
117
173
|
def configure
|
118
174
|
yield self
|
119
175
|
end
|
@@ -130,17 +186,20 @@ module CarrierWave
|
|
130
186
|
:fog => "CarrierWave::Storage::Fog"
|
131
187
|
}
|
132
188
|
config.storage = :file
|
189
|
+
config.cache_storage = nil
|
133
190
|
config.fog_attributes = {}
|
134
191
|
config.fog_credentials = {}
|
135
192
|
config.fog_public = true
|
136
193
|
config.fog_authenticated_url_expiration = 600
|
137
194
|
config.fog_use_ssl_for_aws = true
|
195
|
+
config.fog_aws_accelerate = false
|
138
196
|
config.store_dir = 'uploads'
|
139
197
|
config.cache_dir = 'uploads/tmp'
|
140
198
|
config.delete_tmp_file_after_storage = true
|
141
199
|
config.move_to_cache = false
|
142
200
|
config.move_to_store = false
|
143
201
|
config.remove_previously_stored_files_after_update = true
|
202
|
+
config.downloader = CarrierWave::Downloader::Base
|
144
203
|
config.ignore_integrity_errors = true
|
145
204
|
config.ignore_processing_errors = true
|
146
205
|
config.ignore_download_errors = true
|
@@ -158,4 +217,3 @@ module CarrierWave
|
|
158
217
|
end
|
159
218
|
end
|
160
219
|
end
|
161
|
-
|
@@ -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,84 +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
|
-
filename = filename_from_header || File.basename(file.base_uri.path)
|
21
|
-
mime_type = MIME::Types[file.content_type].first
|
22
|
-
unless File.extname(filename).present? || mime_type.blank?
|
23
|
-
filename = "#{filename}.#{mime_type.extensions.first}"
|
24
|
-
end
|
25
|
-
filename
|
26
|
-
end
|
27
|
-
|
28
|
-
def respond_to?(*args)
|
29
|
-
super or file.respond_to?(*args)
|
30
|
-
end
|
31
|
-
|
32
|
-
def http?
|
33
|
-
@uri.scheme =~ /^https?$/
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def file
|
39
|
-
if @file.blank?
|
40
|
-
@file = Kernel.open(@uri.to_s)
|
41
|
-
@file = @file.is_a?(String) ? StringIO.new(@file) : @file
|
42
|
-
end
|
43
|
-
@file
|
44
|
-
|
45
|
-
rescue Exception => e
|
46
|
-
raise CarrierWave::DownloadError, "could not download file: #{e.message}"
|
47
|
-
end
|
48
|
-
|
49
|
-
def filename_from_header
|
50
|
-
if file.meta.include? 'content-disposition'
|
51
|
-
match = file.meta['content-disposition'].match(/filename="?([^"]+)/)
|
52
|
-
return match[1] unless match.nil? || match[1].empty?
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def method_missing(*args, &block)
|
57
|
-
file.send(*args, &block)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
10
|
##
|
62
|
-
# Caches the file by downloading it from the given URL.
|
11
|
+
# Caches the file by downloading it from the given URL, using downloader.
|
63
12
|
#
|
64
13
|
# === Parameters
|
65
14
|
#
|
66
15
|
# [url (String)] The URL where the remote file is stored
|
16
|
+
# [remote_headers (Hash)] Request headers
|
67
17
|
#
|
68
|
-
def download!(uri)
|
69
|
-
|
70
|
-
file = RemoteFile.new(processed_uri)
|
71
|
-
raise CarrierWave::DownloadError, "trying to download a file which is not served over HTTP" unless file.http?
|
18
|
+
def download!(uri, remote_headers = {})
|
19
|
+
file = downloader.new(self).download(uri, remote_headers)
|
72
20
|
cache!(file)
|
73
21
|
end
|
74
|
-
|
75
|
-
##
|
76
|
-
# Processes the given URL by parsing and escaping it. Public to allow overriding.
|
77
|
-
#
|
78
|
-
# === Parameters
|
79
|
-
#
|
80
|
-
# [url (String)] The URL where the remote file is stored
|
81
|
-
#
|
82
|
-
def process_uri(uri)
|
83
|
-
URI.parse(uri)
|
84
|
-
rescue URI::InvalidURIError
|
85
|
-
uri_parts = uri.split('?')
|
86
|
-
# regexp from Ruby's URI::Parser#regexp[:UNSAFE], with [] specifically removed
|
87
|
-
encoded_uri = URI.encode(uri_parts.shift, /[^\-_.!~*'()a-zA-Z\d;\/?:@&=+$,]/)
|
88
|
-
encoded_uri << '?' << URI.encode(uri_parts.join('?')) if uri_parts.any?
|
89
|
-
URI.parse(encoded_uri) rescue raise CarrierWave::DownloadError, "couldn't parse URL"
|
90
|
-
end
|
91
|
-
|
92
22
|
end # Download
|
93
23
|
end # Uploader
|
94
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
|