carrierwave 1.2.1 → 2.1.1
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.
Potentially problematic release.
This version of carrierwave might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/README.md +80 -26
- data/lib/carrierwave/downloader/base.rb +83 -0
- data/lib/carrierwave/downloader/remote_file.rb +65 -0
- data/lib/carrierwave/locale/en.yml +1 -1
- data/lib/carrierwave/mount.rb +25 -19
- data/lib/carrierwave/mounter.rb +71 -48
- data/lib/carrierwave/orm/activerecord.rb +14 -8
- data/lib/carrierwave/processing/mini_magick.rb +101 -114
- data/lib/carrierwave/processing/rmagick.rb +18 -4
- data/lib/carrierwave/sanitized_file.rb +37 -22
- data/lib/carrierwave/storage/file.rb +7 -3
- data/lib/carrierwave/storage/fog.rb +83 -20
- data/lib/carrierwave/storage.rb +1 -0
- data/lib/carrierwave/uploader/cache.rb +23 -15
- data/lib/carrierwave/uploader/configuration.rb +29 -14
- data/lib/carrierwave/uploader/content_type_whitelist.rb +1 -1
- data/lib/carrierwave/uploader/download.rb +2 -79
- data/lib/carrierwave/uploader/mountable.rb +6 -0
- data/lib/carrierwave/uploader/proxy.rb +2 -2
- data/lib/carrierwave/uploader/serialization.rb +1 -1
- data/lib/carrierwave/uploader/store.rb +13 -2
- data/lib/carrierwave/uploader/url.rb +2 -2
- data/lib/carrierwave/uploader/versions.rb +50 -13
- data/lib/carrierwave/validations/active_model.rb +3 -3
- data/lib/carrierwave/version.rb +1 -1
- data/lib/carrierwave.rb +24 -0
- data/lib/generators/templates/uploader.rb +0 -2
- metadata +123 -26
- data/lib/carrierwave/uploader/magic_mime_blacklist.rb +0 -94
- data/lib/carrierwave/uploader/magic_mime_whitelist.rb +0 -94
@@ -1,12 +1,7 @@
|
|
1
1
|
require 'pathname'
|
2
2
|
require 'active_support/core_ext/string/multibyte'
|
3
|
-
|
4
|
-
|
5
|
-
# Use mime/types/columnar if available, for reduced memory usage
|
6
|
-
require 'mime/types/columnar'
|
7
|
-
rescue LoadError
|
8
|
-
require 'mime/types'
|
9
|
-
end
|
3
|
+
require 'mini_mime'
|
4
|
+
require 'mimemagic'
|
10
5
|
|
11
6
|
module CarrierWave
|
12
7
|
|
@@ -20,7 +15,7 @@ module CarrierWave
|
|
20
15
|
#
|
21
16
|
class SanitizedFile
|
22
17
|
|
23
|
-
|
18
|
+
attr_reader :file
|
24
19
|
|
25
20
|
class << self
|
26
21
|
attr_writer :sanitize_regexp
|
@@ -32,6 +27,7 @@ module CarrierWave
|
|
32
27
|
|
33
28
|
def initialize(file)
|
34
29
|
self.file = file
|
30
|
+
@content = nil
|
35
31
|
end
|
36
32
|
|
37
33
|
##
|
@@ -113,12 +109,11 @@ module CarrierWave
|
|
113
109
|
# [String, nil] the path where the file is located.
|
114
110
|
#
|
115
111
|
def path
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
end
|
112
|
+
return if @file.blank?
|
113
|
+
if is_path?
|
114
|
+
File.expand_path(@file)
|
115
|
+
elsif @file.respond_to?(:path) && !@file.path.blank?
|
116
|
+
File.expand_path(@file.path)
|
122
117
|
end
|
123
118
|
end
|
124
119
|
|
@@ -264,12 +259,10 @@ module CarrierWave
|
|
264
259
|
# [String] the content type of the file
|
265
260
|
#
|
266
261
|
def content_type
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
@content_type = ::MIME::Types.type_for(path).first.to_s
|
272
|
-
end
|
262
|
+
@content_type ||=
|
263
|
+
existing_content_type ||
|
264
|
+
mime_magic_content_type ||
|
265
|
+
mini_mime_content_type
|
273
266
|
end
|
274
267
|
|
275
268
|
##
|
@@ -312,7 +305,7 @@ module CarrierWave
|
|
312
305
|
def mkdir!(path, directory_permissions)
|
313
306
|
options = {}
|
314
307
|
options[:mode] = directory_permissions if directory_permissions
|
315
|
-
FileUtils.mkdir_p(File.dirname(path), options) unless File.exist?(File.dirname(path))
|
308
|
+
FileUtils.mkdir_p(File.dirname(path), **options) unless File.exist?(File.dirname(path))
|
316
309
|
end
|
317
310
|
|
318
311
|
def chmod!(path, permissions)
|
@@ -325,10 +318,32 @@ module CarrierWave
|
|
325
318
|
name = File.basename(name)
|
326
319
|
name = name.gsub(sanitize_regexp,"_")
|
327
320
|
name = "_#{name}" if name =~ /\A\.+\z/
|
328
|
-
name = "unnamed" if name.size
|
321
|
+
name = "unnamed" if name.size.zero?
|
329
322
|
return name.mb_chars.to_s
|
330
323
|
end
|
331
324
|
|
325
|
+
def existing_content_type
|
326
|
+
if @file.respond_to?(:content_type) && @file.content_type
|
327
|
+
@file.content_type.to_s.chomp
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def mime_magic_content_type
|
332
|
+
if path
|
333
|
+
File.open(path) do |file|
|
334
|
+
MimeMagic.by_magic(file).try(:type) || 'invalid/invalid'
|
335
|
+
end
|
336
|
+
end
|
337
|
+
rescue Errno::ENOENT
|
338
|
+
nil
|
339
|
+
end
|
340
|
+
|
341
|
+
def mini_mime_content_type
|
342
|
+
return unless path
|
343
|
+
mime_type = ::MiniMime.lookup_by_filename(path)
|
344
|
+
@content_type = (mime_type && mime_type.content_type).to_s
|
345
|
+
end
|
346
|
+
|
332
347
|
def split_extension(filename)
|
333
348
|
# regular expressions to try for identifying extensions
|
334
349
|
extension_matchers = [
|
@@ -7,6 +7,10 @@ module CarrierWave
|
|
7
7
|
# pretty much it.
|
8
8
|
#
|
9
9
|
class File < Abstract
|
10
|
+
def initialize(*)
|
11
|
+
super
|
12
|
+
@cache_called = nil
|
13
|
+
end
|
10
14
|
|
11
15
|
##
|
12
16
|
# Move the file to the uploader's store path.
|
@@ -62,7 +66,7 @@ module CarrierWave
|
|
62
66
|
#
|
63
67
|
def cache!(new_file)
|
64
68
|
new_file.move_to(::File.expand_path(uploader.cache_path, uploader.root), uploader.permissions, uploader.directory_permissions, true)
|
65
|
-
rescue Errno::EMLINK => e
|
69
|
+
rescue Errno::EMLINK, Errno::ENOSPC => e
|
66
70
|
raise(e) if @cache_called
|
67
71
|
@cache_called = true
|
68
72
|
|
@@ -106,8 +110,8 @@ module CarrierWave
|
|
106
110
|
|
107
111
|
def clean_cache!(seconds)
|
108
112
|
Dir.glob(::File.expand_path(::File.join(uploader.cache_dir, '*'), CarrierWave.root)).each do |dir|
|
109
|
-
# generate_cache_id returns key formated TIMEINT-PID-COUNTER-RND
|
110
|
-
time = dir.scan(/(\d+)-\d+-\d
|
113
|
+
# generate_cache_id returns key formated TIMEINT-PID(-COUNTER)-RND
|
114
|
+
time = dir.scan(/(\d+)-\d+-\d+(?:-\d+)?/).first.map(&:to_i)
|
111
115
|
time = Time.at(*time)
|
112
116
|
if time < (Time.now.utc - seconds)
|
113
117
|
FileUtils.rm_rf(dir)
|
@@ -60,6 +60,14 @@ module CarrierWave
|
|
60
60
|
def connection_cache
|
61
61
|
@connection_cache ||= {}
|
62
62
|
end
|
63
|
+
|
64
|
+
def eager_load
|
65
|
+
# see #1198. This will hopefully no longer be necessary in future release of fog
|
66
|
+
fog_credentials = CarrierWave::Uploader::Base.fog_credentials
|
67
|
+
if fog_credentials.present?
|
68
|
+
CarrierWave::Storage::Fog.connection_cache[fog_credentials] ||= ::Fog::Storage.new(fog_credentials)
|
69
|
+
end
|
70
|
+
end
|
63
71
|
end
|
64
72
|
|
65
73
|
##
|
@@ -138,8 +146,8 @@ module CarrierWave
|
|
138
146
|
:key => uploader.fog_directory,
|
139
147
|
:public => uploader.fog_public
|
140
148
|
).files.all(:prefix => uploader.cache_dir).each do |file|
|
141
|
-
# generate_cache_id returns key formated TIMEINT-PID-COUNTER-RND
|
142
|
-
time = file.key.scan(/(\d+)-\d+-\d
|
149
|
+
# generate_cache_id returns key formated TIMEINT-PID(-COUNTER)-RND
|
150
|
+
time = file.key.scan(/(\d+)-\d+-\d+(?:-\d+)?/).first.map { |t| t.to_i }
|
143
151
|
time = Time.at(*time)
|
144
152
|
file.destroy if time < (Time.now.utc - seconds)
|
145
153
|
end
|
@@ -153,6 +161,8 @@ module CarrierWave
|
|
153
161
|
end
|
154
162
|
|
155
163
|
class File
|
164
|
+
DEFAULT_S3_REGION = 'us-east-1'
|
165
|
+
|
156
166
|
include CarrierWave::Utilities::Uri
|
157
167
|
|
158
168
|
##
|
@@ -177,7 +187,7 @@ module CarrierWave
|
|
177
187
|
|
178
188
|
##
|
179
189
|
# Return a temporary authenticated url to a private file, if available
|
180
|
-
# Only supported for AWS, Rackspace and
|
190
|
+
# Only supported for AWS, Rackspace, Google, AzureRM and Aliyun providers
|
181
191
|
#
|
182
192
|
# === Returns
|
183
193
|
#
|
@@ -186,18 +196,25 @@ module CarrierWave
|
|
186
196
|
# [NilClass] no authenticated url available
|
187
197
|
#
|
188
198
|
def authenticated_url(options = {})
|
189
|
-
if ['AWS', 'Google', 'Rackspace', 'OpenStack'].include?(@uploader.fog_credentials[:provider])
|
199
|
+
if ['AWS', 'Google', 'Rackspace', 'OpenStack', 'AzureRM', 'Aliyun', 'backblaze'].include?(@uploader.fog_credentials[:provider])
|
190
200
|
# avoid a get by using local references
|
191
201
|
local_directory = connection.directories.new(:key => @uploader.fog_directory)
|
192
202
|
local_file = local_directory.files.new(:key => path)
|
193
|
-
expire_at = ::Fog::Time.now + @uploader.fog_authenticated_url_expiration
|
203
|
+
expire_at = options[:expire_at] || ::Fog::Time.now + @uploader.fog_authenticated_url_expiration
|
194
204
|
case @uploader.fog_credentials[:provider]
|
195
|
-
when 'AWS'
|
196
|
-
|
197
|
-
|
205
|
+
when 'AWS', 'Google'
|
206
|
+
# Older versions of fog-google do not support options as a parameter
|
207
|
+
if url_options_supported?(local_file)
|
208
|
+
local_file.url(expire_at, options)
|
209
|
+
else
|
210
|
+
warn "Options hash not supported in #{local_file.class}. You may need to upgrade your Fog provider."
|
211
|
+
local_file.url(expire_at)
|
212
|
+
end
|
213
|
+
when 'Rackspace', 'OpenStack'
|
198
214
|
connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
|
199
|
-
when '
|
200
|
-
|
215
|
+
when 'Aliyun'
|
216
|
+
expire_at = expire_at - Time.now
|
217
|
+
local_file.url(expire_at)
|
201
218
|
else
|
202
219
|
local_file.url(expire_at)
|
203
220
|
end
|
@@ -212,7 +229,7 @@ module CarrierWave
|
|
212
229
|
# [String] value of content-type
|
213
230
|
#
|
214
231
|
def content_type
|
215
|
-
@content_type ||
|
232
|
+
@content_type || file.try(:content_type)
|
216
233
|
end
|
217
234
|
|
218
235
|
##
|
@@ -235,7 +252,9 @@ module CarrierWave
|
|
235
252
|
#
|
236
253
|
def delete
|
237
254
|
# avoid a get by just using local reference
|
238
|
-
directory.files.new(:key => path).destroy
|
255
|
+
directory.files.new(:key => path).destroy.tap do |result|
|
256
|
+
@file = nil if result
|
257
|
+
end
|
239
258
|
end
|
240
259
|
|
241
260
|
##
|
@@ -266,7 +285,7 @@ module CarrierWave
|
|
266
285
|
end
|
267
286
|
|
268
287
|
def initialize(uploader, base, path)
|
269
|
-
@uploader, @base, @path = uploader, base, path
|
288
|
+
@uploader, @base, @path, @content_type = uploader, base, path, nil
|
270
289
|
end
|
271
290
|
|
272
291
|
##
|
@@ -276,6 +295,16 @@ module CarrierWave
|
|
276
295
|
#
|
277
296
|
# [String] contents of file
|
278
297
|
def read
|
298
|
+
file_body = file.body
|
299
|
+
|
300
|
+
return if file_body.nil?
|
301
|
+
return file_body unless file_body.is_a?(::File)
|
302
|
+
|
303
|
+
# Fog::Storage::XXX::File#body could return the source file which was upoloaded to the remote server.
|
304
|
+
read_source_file(file_body) if ::File.exist?(file_body.path)
|
305
|
+
|
306
|
+
# If the source file doesn't exist, the remote content is read
|
307
|
+
@file = nil # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
279
308
|
file.body
|
280
309
|
end
|
281
310
|
|
@@ -313,7 +342,7 @@ module CarrierWave
|
|
313
342
|
fog_file = new_file.to_file
|
314
343
|
@content_type ||= new_file.content_type
|
315
344
|
@file = directory.files.create({
|
316
|
-
:body =>
|
345
|
+
:body => fog_file ? fog_file : new_file.read,
|
317
346
|
:content_type => @content_type,
|
318
347
|
:key => path,
|
319
348
|
:public => @uploader.fog_public
|
@@ -342,20 +371,30 @@ module CarrierWave
|
|
342
371
|
end
|
343
372
|
else
|
344
373
|
# AWS/Google optimized for speed over correctness
|
345
|
-
case
|
374
|
+
case fog_provider
|
346
375
|
when 'AWS'
|
347
376
|
# check if some endpoint is set in fog_credentials
|
348
377
|
if @uploader.fog_credentials.has_key?(:endpoint)
|
349
378
|
"#{@uploader.fog_credentials[:endpoint]}/#{@uploader.fog_directory}/#{encoded_path}"
|
350
379
|
else
|
351
380
|
protocol = @uploader.fog_use_ssl_for_aws ? "https" : "http"
|
381
|
+
|
382
|
+
subdomain_regex = /^(?:[a-z]|\d(?!\d{0,2}(?:\d{1,3}){3}$))(?:[a-z0-9\.]|(?![\-])|\-(?![\.])){1,61}[a-z0-9]$/
|
383
|
+
valid_subdomain = @uploader.fog_directory.to_s =~ subdomain_regex && !(protocol == 'https' && @uploader.fog_directory =~ /\./)
|
384
|
+
|
352
385
|
# if directory is a valid subdomain, use that style for access
|
353
|
-
if
|
386
|
+
if valid_subdomain
|
354
387
|
s3_subdomain = @uploader.fog_aws_accelerate ? "s3-accelerate" : "s3"
|
355
388
|
"#{protocol}://#{@uploader.fog_directory}.#{s3_subdomain}.amazonaws.com/#{encoded_path}"
|
356
|
-
else
|
357
|
-
|
358
|
-
|
389
|
+
else # directory is not a valid subdomain, so use path style for access
|
390
|
+
region = @uploader.fog_credentials[:region].to_s
|
391
|
+
host = case region
|
392
|
+
when DEFAULT_S3_REGION, ''
|
393
|
+
's3.amazonaws.com'
|
394
|
+
else
|
395
|
+
"s3.#{region}.amazonaws.com"
|
396
|
+
end
|
397
|
+
"#{protocol}://#{host}/#{@uploader.fog_directory}/#{encoded_path}"
|
359
398
|
end
|
360
399
|
end
|
361
400
|
when 'Google'
|
@@ -456,7 +495,31 @@ module CarrierWave
|
|
456
495
|
end
|
457
496
|
|
458
497
|
def acl_header
|
459
|
-
|
498
|
+
if fog_provider == 'AWS'
|
499
|
+
{ 'x-amz-acl' => @uploader.fog_public ? 'public-read' : 'private' }
|
500
|
+
else
|
501
|
+
{}
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
def fog_provider
|
506
|
+
@uploader.fog_credentials[:provider].to_s
|
507
|
+
end
|
508
|
+
|
509
|
+
def read_source_file(file_body)
|
510
|
+
return unless ::File.exist?(file_body.path)
|
511
|
+
|
512
|
+
begin
|
513
|
+
file_body = ::File.open(file_body.path) if file_body.closed? # Reopen if it's already closed
|
514
|
+
file_body.read
|
515
|
+
ensure
|
516
|
+
file_body.close
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
520
|
+
def url_options_supported?(local_file)
|
521
|
+
parameters = local_file.method(:url).parameters
|
522
|
+
parameters.count == 2 && parameters[1].include?(:options)
|
460
523
|
end
|
461
524
|
end
|
462
525
|
|
data/lib/carrierwave/storage.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
1
3
|
module CarrierWave
|
2
4
|
|
3
5
|
class FormNotMultipart < UploadError
|
@@ -23,9 +25,9 @@ module CarrierWave
|
|
23
25
|
#
|
24
26
|
def self.generate_cache_id
|
25
27
|
[Time.now.utc.to_i,
|
26
|
-
|
27
|
-
'%04d' % (CarrierWave::CacheCounter.increment %
|
28
|
-
'%04d' %
|
28
|
+
SecureRandom.random_number(1_000_000_000_000_000),
|
29
|
+
'%04d' % (CarrierWave::CacheCounter.increment % 10_000),
|
30
|
+
'%04d' % SecureRandom.random_number(10_000)
|
29
31
|
].map(&:to_s).join('-')
|
30
32
|
end
|
31
33
|
|
@@ -36,6 +38,16 @@ module CarrierWave
|
|
36
38
|
include CarrierWave::Uploader::Callbacks
|
37
39
|
include CarrierWave::Uploader::Configuration
|
38
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
|
+
|
39
51
|
module ClassMethods
|
40
52
|
|
41
53
|
##
|
@@ -52,7 +64,7 @@ module CarrierWave
|
|
52
64
|
# It's recommended that you keep cache files in one place only.
|
53
65
|
#
|
54
66
|
def clean_cached_files!(seconds=60*60*24)
|
55
|
-
cache_storage.new(CarrierWave::Uploader::Base.new).clean_cache!(seconds)
|
67
|
+
(cache_storage || storage).new(CarrierWave::Uploader::Base.new).clean_cache!(seconds)
|
56
68
|
end
|
57
69
|
end
|
58
70
|
|
@@ -78,14 +90,8 @@ module CarrierWave
|
|
78
90
|
end
|
79
91
|
|
80
92
|
def sanitized_file
|
81
|
-
|
82
|
-
|
83
|
-
sanitized = CarrierWave::Storage::Fog.new(self).retrieve!(File.basename(_content.path))
|
84
|
-
else
|
85
|
-
sanitized = SanitizedFile.new :tempfile => StringIO.new(_content),
|
86
|
-
:filename => File.basename(path), :content_type => file.content_type
|
87
|
-
end
|
88
|
-
sanitized
|
93
|
+
ActiveSupport::Deprecation.warn('#sanitized_file is deprecated, use #file instead.')
|
94
|
+
file
|
89
95
|
end
|
90
96
|
|
91
97
|
##
|
@@ -96,7 +102,7 @@ module CarrierWave
|
|
96
102
|
# [String] a cache name, in the format TIMEINT-PID-COUNTER-RND/filename.txt
|
97
103
|
#
|
98
104
|
def cache_name
|
99
|
-
File.join(cache_id, full_original_filename) if cache_id
|
105
|
+
File.join(cache_id, full_original_filename) if cache_id && original_filename
|
100
106
|
end
|
101
107
|
|
102
108
|
##
|
@@ -115,7 +121,7 @@ module CarrierWave
|
|
115
121
|
#
|
116
122
|
# [CarrierWave::FormNotMultipart] if the assigned parameter is a string
|
117
123
|
#
|
118
|
-
def cache!(new_file =
|
124
|
+
def cache!(new_file = file)
|
119
125
|
new_file = CarrierWave::SanitizedFile.new(new_file)
|
120
126
|
return if new_file.empty?
|
121
127
|
|
@@ -123,6 +129,7 @@ module CarrierWave
|
|
123
129
|
|
124
130
|
self.cache_id = CarrierWave.generate_cache_id unless cache_id
|
125
131
|
|
132
|
+
@staged = true
|
126
133
|
@filename = new_file.filename
|
127
134
|
self.original_filename = new_file.filename
|
128
135
|
|
@@ -156,6 +163,7 @@ module CarrierWave
|
|
156
163
|
def retrieve_from_cache!(cache_name)
|
157
164
|
with_callbacks(:retrieve_from_cache, cache_name) do
|
158
165
|
self.cache_id, self.original_filename = cache_name.to_s.split('/', 2)
|
166
|
+
@staged = true
|
159
167
|
@filename = original_filename
|
160
168
|
@file = cache_storage.retrieve_from_cache!(full_filename(original_filename))
|
161
169
|
end
|
@@ -200,7 +208,7 @@ module CarrierWave
|
|
200
208
|
end
|
201
209
|
|
202
210
|
def cache_storage
|
203
|
-
@cache_storage ||= self.class.cache_storage.new(self)
|
211
|
+
@cache_storage ||= (self.class.cache_storage || self.class.storage).new(self)
|
204
212
|
end
|
205
213
|
end # Cache
|
206
214
|
end # Uploader
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'carrierwave/downloader/base'
|
2
|
+
|
1
3
|
module CarrierWave
|
2
4
|
|
3
5
|
module Uploader
|
@@ -21,9 +23,10 @@ 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
|
26
|
-
|
29
|
+
add_deprecated_config :fog_provider
|
27
30
|
add_config :fog_attributes
|
28
31
|
add_config :fog_credentials
|
29
32
|
add_config :fog_directory
|
@@ -107,8 +110,8 @@ module CarrierWave
|
|
107
110
|
# cache_storage CarrierWave::Storage::File
|
108
111
|
# cache_storage MyCustomStorageEngine
|
109
112
|
#
|
110
|
-
def cache_storage(storage =
|
111
|
-
|
113
|
+
def cache_storage(storage = false)
|
114
|
+
unless storage == false
|
112
115
|
self._cache_storage = storage.is_a?(Symbol) ? eval(storage_engines[storage]) : storage
|
113
116
|
end
|
114
117
|
_cache_storage
|
@@ -117,16 +120,10 @@ module CarrierWave
|
|
117
120
|
|
118
121
|
def add_config(name)
|
119
122
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
120
|
-
|
121
|
-
# see #1198. This will hopefully no longer be necessary after fog 2.0
|
122
|
-
require self.fog_provider
|
123
|
-
require 'carrierwave/storage/fog'
|
124
|
-
Fog::Storage.new(fog_credentials) if fog_credentials.present?
|
125
|
-
end
|
123
|
+
@#{name} = nil
|
126
124
|
|
127
125
|
def self.#{name}(value=nil)
|
128
126
|
@#{name} = value if value
|
129
|
-
eager_load_fog(value) if value && '#{name}' == 'fog_credentials'
|
130
127
|
return @#{name} if self.object_id == #{self.object_id} || defined?(@#{name})
|
131
128
|
name = superclass.#{name}
|
132
129
|
return nil if name.nil? && !instance_variable_defined?(:@#{name})
|
@@ -134,12 +131,10 @@ module CarrierWave
|
|
134
131
|
end
|
135
132
|
|
136
133
|
def self.#{name}=(value)
|
137
|
-
eager_load_fog(value) if '#{name}' == 'fog_credentials' && value.present?
|
138
134
|
@#{name} = value
|
139
135
|
end
|
140
136
|
|
141
137
|
def #{name}=(value)
|
142
|
-
self.class.eager_load_fog(value) if '#{name}' == 'fog_credentials' && value.present?
|
143
138
|
@#{name} = value
|
144
139
|
end
|
145
140
|
|
@@ -155,6 +150,26 @@ module CarrierWave
|
|
155
150
|
RUBY
|
156
151
|
end
|
157
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
|
+
|
158
173
|
def configure
|
159
174
|
yield self
|
160
175
|
end
|
@@ -171,8 +186,7 @@ module CarrierWave
|
|
171
186
|
:fog => "CarrierWave::Storage::Fog"
|
172
187
|
}
|
173
188
|
config.storage = :file
|
174
|
-
config.cache_storage =
|
175
|
-
config.fog_provider = 'fog'
|
189
|
+
config.cache_storage = nil
|
176
190
|
config.fog_attributes = {}
|
177
191
|
config.fog_credentials = {}
|
178
192
|
config.fog_public = true
|
@@ -185,6 +199,7 @@ module CarrierWave
|
|
185
199
|
config.move_to_cache = false
|
186
200
|
config.move_to_store = false
|
187
201
|
config.remove_previously_stored_files_after_update = true
|
202
|
+
config.downloader = CarrierWave::Downloader::Base
|
188
203
|
config.ignore_integrity_errors = true
|
189
204
|
config.ignore_processing_errors = true
|
190
205
|
config.ignore_download_errors = true
|
@@ -35,7 +35,7 @@ module CarrierWave
|
|
35
35
|
def check_content_type_whitelist!(new_file)
|
36
36
|
content_type = new_file.content_type
|
37
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)
|
38
|
+
raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.content_type_whitelist_error", content_type: content_type, allowed_types: Array(content_type_whitelist).join(", "))
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'open-uri'
|
2
|
-
|
3
1
|
module CarrierWave
|
4
2
|
module Uploader
|
5
3
|
module Download
|
@@ -9,63 +7,8 @@ module CarrierWave
|
|
9
7
|
include CarrierWave::Uploader::Configuration
|
10
8
|
include CarrierWave::Uploader::Cache
|
11
9
|
|
12
|
-
class RemoteFile
|
13
|
-
def initialize(uri, remote_headers = {})
|
14
|
-
@uri = uri
|
15
|
-
@remote_headers = remote_headers
|
16
|
-
end
|
17
|
-
|
18
|
-
def original_filename
|
19
|
-
filename = filename_from_header || filename_from_uri
|
20
|
-
mime_type = MIME::Types[file.content_type].first
|
21
|
-
unless File.extname(filename).present? || mime_type.blank?
|
22
|
-
filename = "#{filename}.#{mime_type.extensions.first}"
|
23
|
-
end
|
24
|
-
filename
|
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
|
-
headers = @remote_headers.
|
40
|
-
reverse_merge('User-Agent' => "CarrierWave/#{CarrierWave::VERSION}")
|
41
|
-
|
42
|
-
@file = Kernel.open(@uri.to_s, headers)
|
43
|
-
@file = @file.is_a?(String) ? StringIO.new(@file) : @file
|
44
|
-
end
|
45
|
-
@file
|
46
|
-
|
47
|
-
rescue StandardError => e
|
48
|
-
raise CarrierWave::DownloadError, "could not download file: #{e.message}"
|
49
|
-
end
|
50
|
-
|
51
|
-
def filename_from_header
|
52
|
-
if file.meta.include? 'content-disposition'
|
53
|
-
match = file.meta['content-disposition'].match(/filename="?([^"]+)/)
|
54
|
-
return match[1] unless match.nil? || match[1].empty?
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def filename_from_uri
|
59
|
-
URI.decode(File.basename(file.base_uri.path))
|
60
|
-
end
|
61
|
-
|
62
|
-
def method_missing(*args, &block)
|
63
|
-
file.send(*args, &block)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
10
|
##
|
68
|
-
# Caches the file by downloading it from the given URL.
|
11
|
+
# Caches the file by downloading it from the given URL, using downloader.
|
69
12
|
#
|
70
13
|
# === Parameters
|
71
14
|
#
|
@@ -73,29 +16,9 @@ module CarrierWave
|
|
73
16
|
# [remote_headers (Hash)] Request headers
|
74
17
|
#
|
75
18
|
def download!(uri, remote_headers = {})
|
76
|
-
|
77
|
-
file = RemoteFile.new(processed_uri, remote_headers)
|
78
|
-
raise CarrierWave::DownloadError, "trying to download a file which is not served over HTTP" unless file.http?
|
19
|
+
file = downloader.new(self).download(uri, remote_headers)
|
79
20
|
cache!(file)
|
80
21
|
end
|
81
|
-
|
82
|
-
##
|
83
|
-
# Processes the given URL by parsing and escaping it. Public to allow overriding.
|
84
|
-
#
|
85
|
-
# === Parameters
|
86
|
-
#
|
87
|
-
# [url (String)] The URL where the remote file is stored
|
88
|
-
#
|
89
|
-
def process_uri(uri)
|
90
|
-
URI.parse(uri)
|
91
|
-
rescue URI::InvalidURIError
|
92
|
-
uri_parts = uri.split('?')
|
93
|
-
# regexp from Ruby's URI::Parser#regexp[:UNSAFE], with [] specifically removed
|
94
|
-
encoded_uri = URI.encode(uri_parts.shift, /[^\-_.!~*'()a-zA-Z\d;\/?:@&=+$,]/)
|
95
|
-
encoded_uri << '?' << URI.encode(uri_parts.join('?')) if uri_parts.any?
|
96
|
-
URI.parse(encoded_uri) rescue raise CarrierWave::DownloadError, "couldn't parse URL"
|
97
|
-
end
|
98
|
-
|
99
22
|
end # Download
|
100
23
|
end # Uploader
|
101
24
|
end # CarrierWave
|
@@ -33,6 +33,12 @@ module CarrierWave
|
|
33
33
|
@mounted_as = mounted_as
|
34
34
|
end
|
35
35
|
|
36
|
+
##
|
37
|
+
# Returns array index of given uploader within currently mounted uploaders
|
38
|
+
#
|
39
|
+
def index
|
40
|
+
model.__send__(:_mounter, mounted_as).uploaders.index(self)
|
41
|
+
end
|
36
42
|
end # Mountable
|
37
43
|
end # Uploader
|
38
44
|
end # CarrierWave
|
@@ -23,14 +23,14 @@ module CarrierWave
|
|
23
23
|
alias_method :path, :current_path
|
24
24
|
|
25
25
|
##
|
26
|
-
# Returns a string that uniquely identifies the last stored file
|
26
|
+
# Returns a string that uniquely identifies the retrieved or last stored file
|
27
27
|
#
|
28
28
|
# === Returns
|
29
29
|
#
|
30
30
|
# [String] uniquely identifies a file
|
31
31
|
#
|
32
32
|
def identifier
|
33
|
-
storage.try(:identifier)
|
33
|
+
@identifier || storage.try(:identifier)
|
34
34
|
end
|
35
35
|
|
36
36
|
##
|