carrierwave 1.3.2 → 3.0.2
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 +4 -4
 - data/README.md +235 -91
 - data/lib/carrierwave/compatibility/paperclip.rb +4 -2
 - data/lib/carrierwave/downloader/base.rb +101 -0
 - data/lib/carrierwave/downloader/remote_file.rb +68 -0
 - data/lib/carrierwave/locale/en.yml +9 -6
 - data/lib/carrierwave/mount.rb +48 -61
 - data/lib/carrierwave/mounter.rb +167 -77
 - data/lib/carrierwave/orm/activerecord.rb +15 -55
 - data/lib/carrierwave/processing/mini_magick.rb +108 -123
 - data/lib/carrierwave/processing/rmagick.rb +11 -15
 - data/lib/carrierwave/processing/vips.rb +284 -0
 - data/lib/carrierwave/processing.rb +1 -0
 - data/lib/carrierwave/sanitized_file.rb +60 -66
 - data/lib/carrierwave/storage/abstract.rb +5 -5
 - data/lib/carrierwave/storage/file.rb +6 -5
 - data/lib/carrierwave/storage/fog.rb +101 -62
 - data/lib/carrierwave/storage.rb +1 -0
 - data/lib/carrierwave/test/matchers.rb +11 -7
 - data/lib/carrierwave/uploader/cache.rb +40 -24
 - data/lib/carrierwave/uploader/callbacks.rb +1 -1
 - data/lib/carrierwave/uploader/configuration.rb +38 -19
 - data/lib/carrierwave/uploader/content_type_allowlist.rb +62 -0
 - data/lib/carrierwave/uploader/content_type_denylist.rb +62 -0
 - data/lib/carrierwave/uploader/dimension.rb +66 -0
 - data/lib/carrierwave/uploader/download.rb +2 -123
 - data/lib/carrierwave/uploader/extension_allowlist.rb +63 -0
 - data/lib/carrierwave/uploader/extension_denylist.rb +64 -0
 - data/lib/carrierwave/uploader/file_size.rb +2 -2
 - data/lib/carrierwave/uploader/mountable.rb +6 -0
 - data/lib/carrierwave/uploader/processing.rb +42 -7
 - data/lib/carrierwave/uploader/proxy.rb +17 -4
 - data/lib/carrierwave/uploader/serialization.rb +1 -1
 - data/lib/carrierwave/uploader/store.rb +47 -7
 - data/lib/carrierwave/uploader/url.rb +7 -4
 - data/lib/carrierwave/uploader/versions.rb +153 -105
 - data/lib/carrierwave/uploader.rb +10 -17
 - data/lib/carrierwave/utilities/file_name.rb +47 -0
 - data/lib/carrierwave/utilities/uri.rb +14 -11
 - data/lib/carrierwave/utilities.rb +1 -0
 - data/lib/carrierwave/validations/active_model.rb +7 -9
 - data/lib/carrierwave/version.rb +1 -1
 - data/lib/carrierwave.rb +13 -17
 - data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +2 -2
 - data/lib/generators/uploader_generator.rb +3 -3
 - metadata +100 -33
 - data/lib/carrierwave/uploader/content_type_blacklist.rb +0 -48
 - data/lib/carrierwave/uploader/content_type_whitelist.rb +0 -48
 - data/lib/carrierwave/uploader/extension_blacklist.rb +0 -51
 - data/lib/carrierwave/uploader/extension_whitelist.rb +0 -52
 
| 
         @@ -1,12 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'pathname'
         
     | 
| 
       2 
2 
     | 
    
         
             
            require 'active_support/core_ext/string/multibyte'
         
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
            begin
         
     | 
| 
       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 'marcel'
         
     | 
| 
       10 
4 
     | 
    
         | 
| 
       11 
5 
     | 
    
         
             
            module CarrierWave
         
     | 
| 
       12 
6 
     | 
    
         | 
| 
         @@ -19,6 +13,7 @@ module CarrierWave 
     | 
|
| 
       19 
13 
     | 
    
         
             
              # It's probably needlessly comprehensive and complex. Help is appreciated.
         
     | 
| 
       20 
14 
     | 
    
         
             
              #
         
     | 
| 
       21 
15 
     | 
    
         
             
              class SanitizedFile
         
     | 
| 
      
 16 
     | 
    
         
            +
                include CarrierWave::Utilities::FileName
         
     | 
| 
       22 
17 
     | 
    
         | 
| 
       23 
18 
     | 
    
         
             
                attr_reader :file
         
     | 
| 
       24 
19 
     | 
    
         | 
| 
         @@ -32,7 +27,7 @@ module CarrierWave 
     | 
|
| 
       32 
27 
     | 
    
         | 
| 
       33 
28 
     | 
    
         
             
                def initialize(file)
         
     | 
| 
       34 
29 
     | 
    
         
             
                  self.file = file
         
     | 
| 
       35 
     | 
    
         
            -
                  @content = nil
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @content = @content_type = nil
         
     | 
| 
       36 
31 
     | 
    
         
             
                end
         
     | 
| 
       37 
32 
     | 
    
         | 
| 
       38 
33 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -44,7 +39,7 @@ module CarrierWave 
     | 
|
| 
       44 
39 
     | 
    
         
             
                #
         
     | 
| 
       45 
40 
     | 
    
         
             
                def original_filename
         
     | 
| 
       46 
41 
     | 
    
         
             
                  return @original_filename if @original_filename
         
     | 
| 
       47 
     | 
    
         
            -
                  if @file  
     | 
| 
      
 42 
     | 
    
         
            +
                  if @file && @file.respond_to?(:original_filename)
         
     | 
| 
       48 
43 
     | 
    
         
             
                    @file.original_filename
         
     | 
| 
       49 
44 
     | 
    
         
             
                  elsif path
         
     | 
| 
       50 
45 
     | 
    
         
             
                    File.basename(path)
         
     | 
| 
         @@ -64,29 +59,6 @@ module CarrierWave 
     | 
|
| 
       64 
59 
     | 
    
         | 
| 
       65 
60 
     | 
    
         
             
                alias_method :identifier, :filename
         
     | 
| 
       66 
61 
     | 
    
         | 
| 
       67 
     | 
    
         
            -
                ##
         
     | 
| 
       68 
     | 
    
         
            -
                # Returns the part of the filename before the extension. So if a file is called 'test.jpeg'
         
     | 
| 
       69 
     | 
    
         
            -
                # this would return 'test'
         
     | 
| 
       70 
     | 
    
         
            -
                #
         
     | 
| 
       71 
     | 
    
         
            -
                # === Returns
         
     | 
| 
       72 
     | 
    
         
            -
                #
         
     | 
| 
       73 
     | 
    
         
            -
                # [String] the first part of the filename
         
     | 
| 
       74 
     | 
    
         
            -
                #
         
     | 
| 
       75 
     | 
    
         
            -
                def basename
         
     | 
| 
       76 
     | 
    
         
            -
                  split_extension(filename)[0] if filename
         
     | 
| 
       77 
     | 
    
         
            -
                end
         
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
     | 
    
         
            -
                ##
         
     | 
| 
       80 
     | 
    
         
            -
                # Returns the file extension
         
     | 
| 
       81 
     | 
    
         
            -
                #
         
     | 
| 
       82 
     | 
    
         
            -
                # === Returns
         
     | 
| 
       83 
     | 
    
         
            -
                #
         
     | 
| 
       84 
     | 
    
         
            -
                # [String] the extension
         
     | 
| 
       85 
     | 
    
         
            -
                #
         
     | 
| 
       86 
     | 
    
         
            -
                def extension
         
     | 
| 
       87 
     | 
    
         
            -
                  split_extension(filename)[1] if filename
         
     | 
| 
       88 
     | 
    
         
            -
                end
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
62 
     | 
    
         
             
                ##
         
     | 
| 
       91 
63 
     | 
    
         
             
                # Returns the file's size.
         
     | 
| 
       92 
64 
     | 
    
         
             
                #
         
     | 
| 
         @@ -137,7 +109,7 @@ module CarrierWave 
     | 
|
| 
       137 
109 
     | 
    
         
             
                # [Boolean] whether the file is valid and has a non-zero size
         
     | 
| 
       138 
110 
     | 
    
         
             
                #
         
     | 
| 
       139 
111 
     | 
    
         
             
                def empty?
         
     | 
| 
       140 
     | 
    
         
            -
                  @file.nil? || self.size.nil? || (self.size.zero? && ! 
     | 
| 
      
 112 
     | 
    
         
            +
                  @file.nil? || self.size.nil? || (self.size.zero? && !self.exists?)
         
     | 
| 
       141 
113 
     | 
    
         
             
                end
         
     | 
| 
       142 
114 
     | 
    
         | 
| 
       143 
115 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -156,15 +128,21 @@ module CarrierWave 
     | 
|
| 
       156 
128 
     | 
    
         
             
                #
         
     | 
| 
       157 
129 
     | 
    
         
             
                # [String] contents of the file
         
     | 
| 
       158 
130 
     | 
    
         
             
                #
         
     | 
| 
       159 
     | 
    
         
            -
                def read
         
     | 
| 
      
 131 
     | 
    
         
            +
                def read(*args)
         
     | 
| 
       160 
132 
     | 
    
         
             
                  if @content
         
     | 
| 
       161 
     | 
    
         
            -
                     
     | 
| 
      
 133 
     | 
    
         
            +
                    if args.empty?
         
     | 
| 
      
 134 
     | 
    
         
            +
                      @content
         
     | 
| 
      
 135 
     | 
    
         
            +
                    else
         
     | 
| 
      
 136 
     | 
    
         
            +
                      length, outbuf = args
         
     | 
| 
      
 137 
     | 
    
         
            +
                      raise ArgumentError, "outbuf argument not supported since the content is already loaded" if outbuf
         
     | 
| 
      
 138 
     | 
    
         
            +
                      @content[0, length]
         
     | 
| 
      
 139 
     | 
    
         
            +
                    end
         
     | 
| 
       162 
140 
     | 
    
         
             
                  elsif is_path?
         
     | 
| 
       163 
     | 
    
         
            -
                    File.open(@file, "rb") {|file| file.read}
         
     | 
| 
      
 141 
     | 
    
         
            +
                    File.open(@file, "rb") {|file| file.read(*args)}
         
     | 
| 
       164 
142 
     | 
    
         
             
                  else
         
     | 
| 
       165 
143 
     | 
    
         
             
                    @file.try(:rewind)
         
     | 
| 
       166 
     | 
    
         
            -
                    @content = @file.read
         
     | 
| 
       167 
     | 
    
         
            -
                    @file.try(:close) unless @file.try(:closed?)
         
     | 
| 
      
 144 
     | 
    
         
            +
                    @content = @file.read(*args)
         
     | 
| 
      
 145 
     | 
    
         
            +
                    @file.try(:close) unless @file.class.ancestors.include?(::StringIO) || @file.try(:closed?)
         
     | 
| 
       168 
146 
     | 
    
         
             
                    @content
         
     | 
| 
       169 
147 
     | 
    
         
             
                  end
         
     | 
| 
       170 
148 
     | 
    
         
             
                end
         
     | 
| 
         @@ -185,13 +163,10 @@ module CarrierWave 
     | 
|
| 
       185 
163 
     | 
    
         
             
                  mkdir!(new_path, directory_permissions)
         
     | 
| 
       186 
164 
     | 
    
         
             
                  move!(new_path)
         
     | 
| 
       187 
165 
     | 
    
         
             
                  chmod!(new_path, permissions)
         
     | 
| 
       188 
     | 
    
         
            -
                   
     | 
| 
       189 
     | 
    
         
            -
                    self.file = {:tempfile => new_path, :filename => original_filename, :content_type => content_type}
         
     | 
| 
       190 
     | 
    
         
            -
                  else
         
     | 
| 
       191 
     | 
    
         
            -
                    self.file = {:tempfile => new_path, :content_type => content_type}
         
     | 
| 
       192 
     | 
    
         
            -
                  end
         
     | 
| 
      
 166 
     | 
    
         
            +
                  self.file = {tempfile: new_path, filename: keep_filename ? original_filename : nil, content_type: declared_content_type}
         
     | 
| 
       193 
167 
     | 
    
         
             
                  self
         
     | 
| 
       194 
168 
     | 
    
         
             
                end
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
       195 
170 
     | 
    
         
             
                ##
         
     | 
| 
       196 
171 
     | 
    
         
             
                # Helper to move file to new path.
         
     | 
| 
       197 
172 
     | 
    
         
             
                #
         
     | 
| 
         @@ -223,7 +198,7 @@ module CarrierWave 
     | 
|
| 
       223 
198 
     | 
    
         
             
                  mkdir!(new_path, directory_permissions)
         
     | 
| 
       224 
199 
     | 
    
         
             
                  copy!(new_path)
         
     | 
| 
       225 
200 
     | 
    
         
             
                  chmod!(new_path, permissions)
         
     | 
| 
       226 
     | 
    
         
            -
                  self.class.new({: 
     | 
| 
      
 201 
     | 
    
         
            +
                  self.class.new({tempfile: new_path, content_type: declared_content_type})
         
     | 
| 
       227 
202 
     | 
    
         
             
                end
         
     | 
| 
       228 
203 
     | 
    
         | 
| 
       229 
204 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -264,12 +239,11 @@ module CarrierWave 
     | 
|
| 
       264 
239 
     | 
    
         
             
                # [String] the content type of the file
         
     | 
| 
       265 
240 
     | 
    
         
             
                #
         
     | 
| 
       266 
241 
     | 
    
         
             
                def content_type
         
     | 
| 
       267 
     | 
    
         
            -
                   
     | 
| 
       268 
     | 
    
         
            -
             
     | 
| 
       269 
     | 
    
         
            -
                     
     | 
| 
       270 
     | 
    
         
            -
             
     | 
| 
       271 
     | 
    
         
            -
                     
     | 
| 
       272 
     | 
    
         
            -
                  end
         
     | 
| 
      
 242 
     | 
    
         
            +
                  @content_type ||=
         
     | 
| 
      
 243 
     | 
    
         
            +
                    identified_content_type ||
         
     | 
| 
      
 244 
     | 
    
         
            +
                    declared_content_type ||
         
     | 
| 
      
 245 
     | 
    
         
            +
                    guessed_safe_content_type ||
         
     | 
| 
      
 246 
     | 
    
         
            +
                    Marcel::MimeType::BINARY
         
     | 
| 
       273 
247 
     | 
    
         
             
                end
         
     | 
| 
       274 
248 
     | 
    
         | 
| 
       275 
249 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -300,11 +274,11 @@ module CarrierWave 
     | 
|
| 
       300 
274 
     | 
    
         
             
                  if file.is_a?(Hash)
         
     | 
| 
       301 
275 
     | 
    
         
             
                    @file = file["tempfile"] || file[:tempfile]
         
     | 
| 
       302 
276 
     | 
    
         
             
                    @original_filename = file["filename"] || file[:filename]
         
     | 
| 
       303 
     | 
    
         
            -
                    @ 
     | 
| 
      
 277 
     | 
    
         
            +
                    @declared_content_type = file["content_type"] || file[:content_type] || file["type"] || file[:type]
         
     | 
| 
       304 
278 
     | 
    
         
             
                  else
         
     | 
| 
       305 
279 
     | 
    
         
             
                    @file = file
         
     | 
| 
       306 
280 
     | 
    
         
             
                    @original_filename = nil
         
     | 
| 
       307 
     | 
    
         
            -
                    @ 
     | 
| 
      
 281 
     | 
    
         
            +
                    @declared_content_type = nil
         
     | 
| 
       308 
282 
     | 
    
         
             
                  end
         
     | 
| 
       309 
283 
     | 
    
         
             
                end
         
     | 
| 
       310 
284 
     | 
    
         | 
| 
         @@ -321,28 +295,48 @@ module CarrierWave 
     | 
|
| 
       321 
295 
     | 
    
         | 
| 
       322 
296 
     | 
    
         
             
                # Sanitize the filename, to prevent hacking
         
     | 
| 
       323 
297 
     | 
    
         
             
                def sanitize(name)
         
     | 
| 
      
 298 
     | 
    
         
            +
                  name = name.scrub
         
     | 
| 
       324 
299 
     | 
    
         
             
                  name = name.tr("\\", "/") # work-around for IE
         
     | 
| 
       325 
300 
     | 
    
         
             
                  name = File.basename(name)
         
     | 
| 
       326 
     | 
    
         
            -
                  name = name.gsub(sanitize_regexp,"_")
         
     | 
| 
      
 301 
     | 
    
         
            +
                  name = name.gsub(sanitize_regexp, "_")
         
     | 
| 
       327 
302 
     | 
    
         
             
                  name = "_#{name}" if name =~ /\A\.+\z/
         
     | 
| 
       328 
     | 
    
         
            -
                  name = "unnamed" if name.size 
     | 
| 
       329 
     | 
    
         
            -
                   
     | 
| 
      
 303 
     | 
    
         
            +
                  name = "unnamed" if name.size.zero?
         
     | 
| 
      
 304 
     | 
    
         
            +
                  name.mb_chars.to_s
         
     | 
| 
       330 
305 
     | 
    
         
             
                end
         
     | 
| 
       331 
306 
     | 
    
         | 
| 
       332 
     | 
    
         
            -
                def  
     | 
| 
       333 
     | 
    
         
            -
                   
     | 
| 
       334 
     | 
    
         
            -
             
     | 
| 
       335 
     | 
    
         
            -
             
     | 
| 
       336 
     | 
    
         
            -
                    /\A(.+)\.([^\.]+)\z/ # matches "something.jpg"
         
     | 
| 
       337 
     | 
    
         
            -
                  ]
         
     | 
| 
       338 
     | 
    
         
            -
             
     | 
| 
       339 
     | 
    
         
            -
                  extension_matchers.each do |regexp|
         
     | 
| 
       340 
     | 
    
         
            -
                    if filename =~ regexp
         
     | 
| 
       341 
     | 
    
         
            -
                      return $1, $2
         
     | 
| 
      
 307 
     | 
    
         
            +
                def declared_content_type
         
     | 
| 
      
 308 
     | 
    
         
            +
                  @declared_content_type ||
         
     | 
| 
      
 309 
     | 
    
         
            +
                    if @file.respond_to?(:content_type) && @file.content_type
         
     | 
| 
      
 310 
     | 
    
         
            +
                      @file.content_type.to_s.chomp
         
     | 
| 
       342 
311 
     | 
    
         
             
                    end
         
     | 
| 
      
 312 
     | 
    
         
            +
                end
         
     | 
| 
      
 313 
     | 
    
         
            +
             
     | 
| 
      
 314 
     | 
    
         
            +
                # Guess content type from its file extension. Limit what to be returned to prevent spoofing.
         
     | 
| 
      
 315 
     | 
    
         
            +
                def guessed_safe_content_type
         
     | 
| 
      
 316 
     | 
    
         
            +
                  return unless path
         
     | 
| 
      
 317 
     | 
    
         
            +
             
     | 
| 
      
 318 
     | 
    
         
            +
                  type = Marcel::Magic.by_path(original_filename).to_s
         
     | 
| 
      
 319 
     | 
    
         
            +
                  type if type.start_with?('text/') || type.start_with?('application/json')
         
     | 
| 
      
 320 
     | 
    
         
            +
                end
         
     | 
| 
      
 321 
     | 
    
         
            +
             
     | 
| 
      
 322 
     | 
    
         
            +
                def identified_content_type
         
     | 
| 
      
 323 
     | 
    
         
            +
                  with_io do |io|
         
     | 
| 
      
 324 
     | 
    
         
            +
                    Marcel::Magic.by_magic(io).try(:type)
         
     | 
| 
       343 
325 
     | 
    
         
             
                  end
         
     | 
| 
       344 
     | 
    
         
            -
             
     | 
| 
      
 326 
     | 
    
         
            +
                rescue Errno::ENOENT
         
     | 
| 
      
 327 
     | 
    
         
            +
                  nil
         
     | 
| 
       345 
328 
     | 
    
         
             
                end
         
     | 
| 
       346 
329 
     | 
    
         | 
| 
      
 330 
     | 
    
         
            +
                def with_io(&block)
         
     | 
| 
      
 331 
     | 
    
         
            +
                  if file.is_a?(IO)
         
     | 
| 
      
 332 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 333 
     | 
    
         
            +
                      yield file
         
     | 
| 
      
 334 
     | 
    
         
            +
                    ensure
         
     | 
| 
      
 335 
     | 
    
         
            +
                      file.try(:rewind)
         
     | 
| 
      
 336 
     | 
    
         
            +
                    end
         
     | 
| 
      
 337 
     | 
    
         
            +
                  elsif path
         
     | 
| 
      
 338 
     | 
    
         
            +
                    File.open(path, &block)
         
     | 
| 
      
 339 
     | 
    
         
            +
                  end
         
     | 
| 
      
 340 
     | 
    
         
            +
                end
         
     | 
| 
       347 
341 
     | 
    
         
             
              end # SanitizedFile
         
     | 
| 
       348 
342 
     | 
    
         
             
            end # CarrierWave
         
     | 
| 
         @@ -14,7 +14,7 @@ module CarrierWave 
     | 
|
| 
       14 
14 
     | 
    
         
             
                  end
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
16 
     | 
    
         
             
                  def identifier
         
     | 
| 
       17 
     | 
    
         
            -
                    uploader. 
     | 
| 
      
 17 
     | 
    
         
            +
                    uploader.deduplicated_filename
         
     | 
| 
       18 
18 
     | 
    
         
             
                  end
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
       20 
20 
     | 
    
         
             
                  def store!(file)
         
     | 
| 
         @@ -24,19 +24,19 @@ module CarrierWave 
     | 
|
| 
       24 
24 
     | 
    
         
             
                  end
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
                  def cache!(new_file)
         
     | 
| 
       27 
     | 
    
         
            -
                    raise NotImplementedError 
     | 
| 
      
 27 
     | 
    
         
            +
                    raise NotImplementedError, "Need to implement #cache! if you want to use #{self.class.name} as a cache storage."
         
     | 
| 
       28 
28 
     | 
    
         
             
                  end
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
                  def retrieve_from_cache!(identifier)
         
     | 
| 
       31 
     | 
    
         
            -
                    raise NotImplementedError 
     | 
| 
      
 31 
     | 
    
         
            +
                    raise NotImplementedError, "Need to implement #retrieve_from_cache! if you want to use #{self.class.name} as a cache storage."
         
     | 
| 
       32 
32 
     | 
    
         
             
                  end
         
     | 
| 
       33 
33 
     | 
    
         | 
| 
       34 
34 
     | 
    
         
             
                  def delete_dir!(path)
         
     | 
| 
       35 
     | 
    
         
            -
                    raise NotImplementedError 
     | 
| 
      
 35 
     | 
    
         
            +
                    raise NotImplementedError, "Need to implement #delete_dir! if you want to use #{self.class.name} as a cache storage."
         
     | 
| 
       36 
36 
     | 
    
         
             
                  end
         
     | 
| 
       37 
37 
     | 
    
         | 
| 
       38 
38 
     | 
    
         
             
                  def clean_cache!(seconds)
         
     | 
| 
       39 
     | 
    
         
            -
                    raise NotImplementedError 
     | 
| 
      
 39 
     | 
    
         
            +
                    raise NotImplementedError, "Need to implement #clean_cache! if you want to use #{self.class.name} as a cache storage."
         
     | 
| 
       40 
40 
     | 
    
         
             
                  end
         
     | 
| 
       41 
41 
     | 
    
         
             
                end # Abstract
         
     | 
| 
       42 
42 
     | 
    
         
             
              end # Storage
         
     | 
| 
         @@ -17,7 +17,7 @@ module CarrierWave 
     | 
|
| 
       17 
17 
     | 
    
         
             
                  #
         
     | 
| 
       18 
18 
     | 
    
         
             
                  # By default, store!() uses copy_to(), which operates by copying the file
         
     | 
| 
       19 
19 
     | 
    
         
             
                  # from the cache to the store, then deleting the file from the cache.
         
     | 
| 
       20 
     | 
    
         
            -
                  # If move_to_store() is  
     | 
| 
      
 20 
     | 
    
         
            +
                  # If move_to_store() is overridden to return true, then store!() uses move_to(),
         
     | 
| 
       21 
21 
     | 
    
         
             
                  # which simply moves the file from cache to store.  Useful for large files.
         
     | 
| 
       22 
22 
     | 
    
         
             
                  #
         
     | 
| 
       23 
23 
     | 
    
         
             
                  # === Parameters
         
     | 
| 
         @@ -109,10 +109,11 @@ module CarrierWave 
     | 
|
| 
       109 
109 
     | 
    
         
             
                  end
         
     | 
| 
       110 
110 
     | 
    
         | 
| 
       111 
111 
     | 
    
         
             
                  def clean_cache!(seconds)
         
     | 
| 
       112 
     | 
    
         
            -
                    Dir.glob(::File.expand_path(::File.join(uploader.cache_dir, '*'),  
     | 
| 
       113 
     | 
    
         
            -
                      # generate_cache_id returns key  
     | 
| 
       114 
     | 
    
         
            -
                       
     | 
| 
       115 
     | 
    
         
            -
                       
     | 
| 
      
 112 
     | 
    
         
            +
                    Dir.glob(::File.expand_path(::File.join(uploader.cache_dir, '*'), uploader.root)).each do |dir|
         
     | 
| 
      
 113 
     | 
    
         
            +
                      # generate_cache_id returns key formatted TIMEINT-PID(-COUNTER)-RND
         
     | 
| 
      
 114 
     | 
    
         
            +
                      matched = dir.scan(/(\d+)-\d+-\d+(?:-\d+)?/).first
         
     | 
| 
      
 115 
     | 
    
         
            +
                      next unless matched
         
     | 
| 
      
 116 
     | 
    
         
            +
                      time = Time.at(matched[0].to_i)
         
     | 
| 
       116 
117 
     | 
    
         
             
                      if time < (Time.now.utc - seconds)
         
     | 
| 
       117 
118 
     | 
    
         
             
                        FileUtils.rm_rf(dir)
         
     | 
| 
       118 
119 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -30,7 +30,7 @@ module CarrierWave 
     | 
|
| 
       30 
30 
     | 
    
         
             
                #
         
     | 
| 
       31 
31 
     | 
    
         
             
                # Google credentials contain the following keys:
         
     | 
| 
       32 
32 
     | 
    
         
             
                # [:google_storage_access_key_id]
         
     | 
| 
       33 
     | 
    
         
            -
                # [: 
     | 
| 
      
 33 
     | 
    
         
            +
                # [:google_storage_secret_access_key]
         
     | 
| 
       34 
34 
     | 
    
         
             
                #
         
     | 
| 
       35 
35 
     | 
    
         
             
                #
         
     | 
| 
       36 
36 
     | 
    
         
             
                # Local credentials contain the following keys:
         
     | 
| 
         @@ -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,9 +146,10 @@ 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  
     | 
| 
       142 
     | 
    
         
            -
                       
     | 
| 
       143 
     | 
    
         
            -
                       
     | 
| 
      
 149 
     | 
    
         
            +
                      # generate_cache_id returns key formatted TIMEINT-PID(-COUNTER)-RND
         
     | 
| 
      
 150 
     | 
    
         
            +
                      matched = file.key.match(/(\d+)-\d+-\d+(?:-\d+)?/)
         
     | 
| 
      
 151 
     | 
    
         
            +
                      next unless matched
         
     | 
| 
      
 152 
     | 
    
         
            +
                      time = Time.at(matched[1].to_i)
         
     | 
| 
       144 
153 
     | 
    
         
             
                      file.destroy if time < (Time.now.utc - seconds)
         
     | 
| 
       145 
154 
     | 
    
         
             
                    end
         
     | 
| 
       146 
155 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -153,7 +162,10 @@ module CarrierWave 
     | 
|
| 
       153 
162 
     | 
    
         
             
                  end
         
     | 
| 
       154 
163 
     | 
    
         | 
| 
       155 
164 
     | 
    
         
             
                  class File
         
     | 
| 
      
 165 
     | 
    
         
            +
                    DEFAULT_S3_REGION = 'us-east-1'.freeze
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
       156 
167 
     | 
    
         
             
                    include CarrierWave::Utilities::Uri
         
     | 
| 
      
 168 
     | 
    
         
            +
                    include CarrierWave::Utilities::FileName
         
     | 
| 
       157 
169 
     | 
    
         | 
| 
       158 
170 
     | 
    
         
             
                    ##
         
     | 
| 
       159 
171 
     | 
    
         
             
                    # Current local path to file
         
     | 
| 
         @@ -177,7 +189,7 @@ module CarrierWave 
     | 
|
| 
       177 
189 
     | 
    
         | 
| 
       178 
190 
     | 
    
         
             
                    ##
         
     | 
| 
       179 
191 
     | 
    
         
             
                    # Return a temporary authenticated url to a private file, if available
         
     | 
| 
       180 
     | 
    
         
            -
                    # Only supported for AWS, Rackspace, Google and  
     | 
| 
      
 192 
     | 
    
         
            +
                    # Only supported for AWS, Rackspace, Google, AzureRM and Aliyun providers
         
     | 
| 
       181 
193 
     | 
    
         
             
                    #
         
     | 
| 
       182 
194 
     | 
    
         
             
                    # === Returns
         
     | 
| 
       183 
195 
     | 
    
         
             
                    #
         
     | 
| 
         @@ -186,24 +198,27 @@ module CarrierWave 
     | 
|
| 
       186 
198 
     | 
    
         
             
                    # [NilClass] no authenticated url available
         
     | 
| 
       187 
199 
     | 
    
         
             
                    #
         
     | 
| 
       188 
200 
     | 
    
         
             
                    def authenticated_url(options = {})
         
     | 
| 
       189 
     | 
    
         
            -
                      if ['AWS', 'Google', 'Rackspace', 'OpenStack', 'AzureRM'].include?( 
     | 
| 
      
 201 
     | 
    
         
            +
                      if ['AWS', 'Google', 'Rackspace', 'OpenStack', 'AzureRM', 'Aliyun', 'backblaze'].include?(fog_provider)
         
     | 
| 
       190 
202 
     | 
    
         
             
                        # avoid a get by using local references
         
     | 
| 
       191 
203 
     | 
    
         
             
                        local_directory = connection.directories.new(:key => @uploader.fog_directory)
         
     | 
| 
       192 
204 
     | 
    
         
             
                        local_file = local_directory.files.new(:key => path)
         
     | 
| 
       193 
     | 
    
         
            -
                        expire_at = ::Fog::Time.now 
     | 
| 
       194 
     | 
    
         
            -
                        case  
     | 
| 
       195 
     | 
    
         
            -
             
     | 
| 
       196 
     | 
    
         
            -
             
     | 
| 
       197 
     | 
    
         
            -
             
     | 
| 
       198 
     | 
    
         
            -
             
     | 
| 
       199 
     | 
    
         
            -
                            else
         
     | 
| 
       200 
     | 
    
         
            -
                              warn "Options hash not supported in #{local_file.class}. You may need to upgrade your Fog provider."
         
     | 
| 
       201 
     | 
    
         
            -
                              local_file.url(expire_at)
         
     | 
| 
       202 
     | 
    
         
            -
                            end
         
     | 
| 
       203 
     | 
    
         
            -
                          when 'Rackspace', 'OpenStack'
         
     | 
| 
       204 
     | 
    
         
            -
                            connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
         
     | 
| 
      
 205 
     | 
    
         
            +
                        expire_at = options[:expire_at] || ::Fog::Time.now.since(@uploader.fog_authenticated_url_expiration.to_i)
         
     | 
| 
      
 206 
     | 
    
         
            +
                        case fog_provider
         
     | 
| 
      
 207 
     | 
    
         
            +
                        when 'AWS', 'Google'
         
     | 
| 
      
 208 
     | 
    
         
            +
                          # Older versions of fog-google do not support options as a parameter
         
     | 
| 
      
 209 
     | 
    
         
            +
                          if url_options_supported?(local_file)
         
     | 
| 
      
 210 
     | 
    
         
            +
                            local_file.url(expire_at, options)
         
     | 
| 
       205 
211 
     | 
    
         
             
                          else
         
     | 
| 
      
 212 
     | 
    
         
            +
                            warn "Options hash not supported in #{local_file.class}. You may need to upgrade your Fog provider."
         
     | 
| 
       206 
213 
     | 
    
         
             
                            local_file.url(expire_at)
         
     | 
| 
      
 214 
     | 
    
         
            +
                          end
         
     | 
| 
      
 215 
     | 
    
         
            +
                        when 'Rackspace', 'OpenStack'
         
     | 
| 
      
 216 
     | 
    
         
            +
                          connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
         
     | 
| 
      
 217 
     | 
    
         
            +
                        when 'Aliyun'
         
     | 
| 
      
 218 
     | 
    
         
            +
                          expire_at -= Time.now
         
     | 
| 
      
 219 
     | 
    
         
            +
                          local_file.url(expire_at)
         
     | 
| 
      
 220 
     | 
    
         
            +
                        else
         
     | 
| 
      
 221 
     | 
    
         
            +
                          local_file.url(expire_at)
         
     | 
| 
       207 
222 
     | 
    
         
             
                        end
         
     | 
| 
       208 
223 
     | 
    
         
             
                      end
         
     | 
| 
       209 
224 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -216,7 +231,7 @@ module CarrierWave 
     | 
|
| 
       216 
231 
     | 
    
         
             
                    # [String] value of content-type
         
     | 
| 
       217 
232 
     | 
    
         
             
                    #
         
     | 
| 
       218 
233 
     | 
    
         
             
                    def content_type
         
     | 
| 
       219 
     | 
    
         
            -
                      @content_type ||  
     | 
| 
      
 234 
     | 
    
         
            +
                      @content_type || file.try(:content_type)
         
     | 
| 
       220 
235 
     | 
    
         
             
                    end
         
     | 
| 
       221 
236 
     | 
    
         | 
| 
       222 
237 
     | 
    
         
             
                    ##
         
     | 
| 
         @@ -239,19 +254,9 @@ module CarrierWave 
     | 
|
| 
       239 
254 
     | 
    
         
             
                    #
         
     | 
| 
       240 
255 
     | 
    
         
             
                    def delete
         
     | 
| 
       241 
256 
     | 
    
         
             
                      # avoid a get by just using local reference
         
     | 
| 
       242 
     | 
    
         
            -
                      directory.files.new(:key => path).destroy
         
     | 
| 
       243 
     | 
    
         
            -
             
     | 
| 
       244 
     | 
    
         
            -
             
     | 
| 
       245 
     | 
    
         
            -
                    ##
         
     | 
| 
       246 
     | 
    
         
            -
                    # Return extension of file
         
     | 
| 
       247 
     | 
    
         
            -
                    #
         
     | 
| 
       248 
     | 
    
         
            -
                    # === Returns
         
     | 
| 
       249 
     | 
    
         
            -
                    #
         
     | 
| 
       250 
     | 
    
         
            -
                    # [String] extension of file or nil if the file has no extension
         
     | 
| 
       251 
     | 
    
         
            -
                    #
         
     | 
| 
       252 
     | 
    
         
            -
                    def extension
         
     | 
| 
       253 
     | 
    
         
            -
                      path_elements = path.split('.')
         
     | 
| 
       254 
     | 
    
         
            -
                      path_elements.last if path_elements.size > 1
         
     | 
| 
      
 257 
     | 
    
         
            +
                      directory.files.new(:key => path).destroy.tap do |result|
         
     | 
| 
      
 258 
     | 
    
         
            +
                        @file = nil if result
         
     | 
| 
      
 259 
     | 
    
         
            +
                      end
         
     | 
| 
       255 
260 
     | 
    
         
             
                    end
         
     | 
| 
       256 
261 
     | 
    
         | 
| 
       257 
262 
     | 
    
         
             
                    ##
         
     | 
| 
         @@ -280,16 +285,16 @@ module CarrierWave 
     | 
|
| 
       280 
285 
     | 
    
         
             
                    #
         
     | 
| 
       281 
286 
     | 
    
         
             
                    # [String] contents of file
         
     | 
| 
       282 
287 
     | 
    
         
             
                    def read
         
     | 
| 
       283 
     | 
    
         
            -
                      file_body = file 
     | 
| 
      
 288 
     | 
    
         
            +
                      file_body = file&.body
         
     | 
| 
       284 
289 
     | 
    
         | 
| 
       285 
290 
     | 
    
         
             
                      return if file_body.nil?
         
     | 
| 
       286 
291 
     | 
    
         
             
                      return file_body unless file_body.is_a?(::File)
         
     | 
| 
       287 
292 
     | 
    
         | 
| 
       288 
     | 
    
         
            -
                      # Fog::Storage::XXX::File#body could return the source file which was  
     | 
| 
       289 
     | 
    
         
            -
                      read_source_file 
     | 
| 
      
 293 
     | 
    
         
            +
                      # Fog::Storage::XXX::File#body could return the source file which was uploaded to the remote server.
         
     | 
| 
      
 294 
     | 
    
         
            +
                      return read_source_file if ::File.exist?(file_body.path)
         
     | 
| 
       290 
295 
     | 
    
         | 
| 
       291 
296 
     | 
    
         
             
                      # If the source file doesn't exist, the remote content is read
         
     | 
| 
       292 
     | 
    
         
            -
                      @file = nil 
     | 
| 
      
 297 
     | 
    
         
            +
                      @file = nil
         
     | 
| 
       293 
298 
     | 
    
         
             
                      file.body
         
     | 
| 
       294 
299 
     | 
    
         
             
                    end
         
     | 
| 
       295 
300 
     | 
    
         | 
| 
         @@ -327,7 +332,7 @@ module CarrierWave 
     | 
|
| 
       327 
332 
     | 
    
         
             
                        fog_file = new_file.to_file
         
     | 
| 
       328 
333 
     | 
    
         
             
                        @content_type ||= new_file.content_type
         
     | 
| 
       329 
334 
     | 
    
         
             
                        @file = directory.files.create({
         
     | 
| 
       330 
     | 
    
         
            -
                          :body         => fog_file  
     | 
| 
      
 335 
     | 
    
         
            +
                          :body         => fog_file || new_file.read,
         
     | 
| 
       331 
336 
     | 
    
         
             
                          :content_type => @content_type,
         
     | 
| 
       332 
337 
     | 
    
         
             
                          :key          => path,
         
     | 
| 
       333 
338 
     | 
    
         
             
                          :public       => @uploader.fog_public
         
     | 
| 
         @@ -348,7 +353,7 @@ module CarrierWave 
     | 
|
| 
       348 
353 
     | 
    
         
             
                    #
         
     | 
| 
       349 
354 
     | 
    
         
             
                    def public_url
         
     | 
| 
       350 
355 
     | 
    
         
             
                      encoded_path = encode_path(path)
         
     | 
| 
       351 
     | 
    
         
            -
                      if host = @uploader.asset_host
         
     | 
| 
      
 356 
     | 
    
         
            +
                      if (host = @uploader.asset_host)
         
     | 
| 
       352 
357 
     | 
    
         
             
                        if host.respond_to? :call
         
     | 
| 
       353 
358 
     | 
    
         
             
                          "#{host.call(self)}/#{encoded_path}"
         
     | 
| 
       354 
359 
     | 
    
         
             
                        else
         
     | 
| 
         @@ -365,15 +370,22 @@ module CarrierWave 
     | 
|
| 
       365 
370 
     | 
    
         
             
                            protocol = @uploader.fog_use_ssl_for_aws ? "https" : "http"
         
     | 
| 
       366 
371 
     | 
    
         | 
| 
       367 
372 
     | 
    
         
             
                            subdomain_regex = /^(?:[a-z]|\d(?!\d{0,2}(?:\d{1,3}){3}$))(?:[a-z0-9\.]|(?![\-])|\-(?![\.])){1,61}[a-z0-9]$/
         
     | 
| 
       368 
     | 
    
         
            -
                             
     | 
| 
       369 
     | 
    
         
            -
             
     | 
| 
       370 
     | 
    
         
            -
             
     | 
| 
       371 
     | 
    
         
            -
                             
     | 
| 
       372 
     | 
    
         
            -
             
     | 
| 
       373 
     | 
    
         
            -
             
     | 
| 
       374 
     | 
    
         
            -
             
     | 
| 
       375 
     | 
    
         
            -
             
     | 
| 
       376 
     | 
    
         
            -
             
     | 
| 
      
 373 
     | 
    
         
            +
                            # To use the virtual-hosted style, the bucket name needs to be representable as a subdomain
         
     | 
| 
      
 374 
     | 
    
         
            +
                            use_virtual_hosted_style = @uploader.fog_directory.to_s =~ subdomain_regex && !(protocol == 'https' && @uploader.fog_directory =~ /\./)
         
     | 
| 
      
 375 
     | 
    
         
            +
             
     | 
| 
      
 376 
     | 
    
         
            +
                            region = @uploader.fog_credentials[:region].to_s
         
     | 
| 
      
 377 
     | 
    
         
            +
                            regional_host = case region
         
     | 
| 
      
 378 
     | 
    
         
            +
                                            when DEFAULT_S3_REGION, ''
         
     | 
| 
      
 379 
     | 
    
         
            +
                                              's3.amazonaws.com'
         
     | 
| 
      
 380 
     | 
    
         
            +
                                            else
         
     | 
| 
      
 381 
     | 
    
         
            +
                                              "s3.#{region}.amazonaws.com"
         
     | 
| 
      
 382 
     | 
    
         
            +
                                            end
         
     | 
| 
      
 383 
     | 
    
         
            +
             
     | 
| 
      
 384 
     | 
    
         
            +
                            if use_virtual_hosted_style
         
     | 
| 
      
 385 
     | 
    
         
            +
                              regional_host = 's3-accelerate.amazonaws.com' if @uploader.fog_aws_accelerate
         
     | 
| 
      
 386 
     | 
    
         
            +
                              "#{protocol}://#{@uploader.fog_directory}.#{regional_host}/#{encoded_path}"
         
     | 
| 
      
 387 
     | 
    
         
            +
                            else # directory is not a valid subdomain, so use path style for access
         
     | 
| 
      
 388 
     | 
    
         
            +
                              "#{protocol}://#{regional_host}/#{@uploader.fog_directory}/#{encoded_path}"
         
     | 
| 
       377 
389 
     | 
    
         
             
                            end
         
     | 
| 
       378 
390 
     | 
    
         
             
                          end
         
     | 
| 
       379 
391 
     | 
    
         
             
                        when 'Google'
         
     | 
| 
         @@ -387,7 +399,7 @@ module CarrierWave 
     | 
|
| 
       387 
399 
     | 
    
         
             
                    end
         
     | 
| 
       388 
400 
     | 
    
         | 
| 
       389 
401 
     | 
    
         
             
                    ##
         
     | 
| 
       390 
     | 
    
         
            -
                    # Return url to file, if  
     | 
| 
      
 402 
     | 
    
         
            +
                    # Return url to file, if available
         
     | 
| 
       391 
403 
     | 
    
         
             
                    #
         
     | 
| 
       392 
404 
     | 
    
         
             
                    # === Returns
         
     | 
| 
       393 
405 
     | 
    
         
             
                    #
         
     | 
| 
         @@ -413,7 +425,7 @@ module CarrierWave 
     | 
|
| 
       413 
425 
     | 
    
         
             
                    # [NilClass] no file name available
         
     | 
| 
       414 
426 
     | 
    
         
             
                    #
         
     | 
| 
       415 
427 
     | 
    
         
             
                    def filename(options = {})
         
     | 
| 
       416 
     | 
    
         
            -
                      return unless file_url = url(options)
         
     | 
| 
      
 428 
     | 
    
         
            +
                      return unless (file_url = url(options))
         
     | 
| 
       417 
429 
     | 
    
         
             
                      CGI.unescape(file_url.split('?').first).gsub(/.*\/(.*?$)/, '\1')
         
     | 
| 
       418 
430 
     | 
    
         
             
                    end
         
     | 
| 
       419 
431 
     | 
    
         | 
| 
         @@ -429,10 +441,29 @@ module CarrierWave 
     | 
|
| 
       429 
441 
     | 
    
         
             
                    # @return [CarrierWave::Storage::Fog::File] the location where the file will be stored.
         
     | 
| 
       430 
442 
     | 
    
         
             
                    #
         
     | 
| 
       431 
443 
     | 
    
         
             
                    def copy_to(new_path)
         
     | 
| 
       432 
     | 
    
         
            -
                       
     | 
| 
      
 444 
     | 
    
         
            +
                      file.copy(@uploader.fog_directory, new_path, copy_options)
         
     | 
| 
       433 
445 
     | 
    
         
             
                      CarrierWave::Storage::Fog::File.new(@uploader, @base, new_path)
         
     | 
| 
       434 
446 
     | 
    
         
             
                    end
         
     | 
| 
       435 
447 
     | 
    
         | 
| 
      
 448 
     | 
    
         
            +
                    ##
         
     | 
| 
      
 449 
     | 
    
         
            +
                    # Return the local file
         
     | 
| 
      
 450 
     | 
    
         
            +
                    #
         
     | 
| 
      
 451 
     | 
    
         
            +
                    # === Returns
         
     | 
| 
      
 452 
     | 
    
         
            +
                    #
         
     | 
| 
      
 453 
     | 
    
         
            +
                    # [File] The local file as Ruby's File class
         
     | 
| 
      
 454 
     | 
    
         
            +
                    #   or
         
     | 
| 
      
 455 
     | 
    
         
            +
                    # [NilClass] When there's no file, or the file is remotely stored
         
     | 
| 
      
 456 
     | 
    
         
            +
                    #
         
     | 
| 
      
 457 
     | 
    
         
            +
                    def to_file
         
     | 
| 
      
 458 
     | 
    
         
            +
                      return nil unless file.body.is_a? ::File
         
     | 
| 
      
 459 
     | 
    
         
            +
             
     | 
| 
      
 460 
     | 
    
         
            +
                      if file.body.closed?
         
     | 
| 
      
 461 
     | 
    
         
            +
                        ::File.open(file.body.path) # Reopen if it's already closed
         
     | 
| 
      
 462 
     | 
    
         
            +
                      else
         
     | 
| 
      
 463 
     | 
    
         
            +
                        file.body
         
     | 
| 
      
 464 
     | 
    
         
            +
                      end
         
     | 
| 
      
 465 
     | 
    
         
            +
                    end
         
     | 
| 
      
 466 
     | 
    
         
            +
             
     | 
| 
       436 
467 
     | 
    
         
             
                  private
         
     | 
| 
       437 
468 
     | 
    
         | 
| 
       438 
469 
     | 
    
         
             
                    ##
         
     | 
| 
         @@ -454,12 +485,10 @@ module CarrierWave 
     | 
|
| 
       454 
485 
     | 
    
         
             
                    # [Fog::#{provider}::Directory] containing directory
         
     | 
| 
       455 
486 
     | 
    
         
             
                    #
         
     | 
| 
       456 
487 
     | 
    
         
             
                    def directory
         
     | 
| 
       457 
     | 
    
         
            -
                      @directory ||=  
     | 
| 
       458 
     | 
    
         
            -
                         
     | 
| 
       459 
     | 
    
         
            -
             
     | 
| 
       460 
     | 
    
         
            -
             
     | 
| 
       461 
     | 
    
         
            -
                        )
         
     | 
| 
       462 
     | 
    
         
            -
                      end
         
     | 
| 
      
 488 
     | 
    
         
            +
                      @directory ||= connection.directories.new(
         
     | 
| 
      
 489 
     | 
    
         
            +
                        :key    => @uploader.fog_directory,
         
     | 
| 
      
 490 
     | 
    
         
            +
                        :public => @uploader.fog_public
         
     | 
| 
      
 491 
     | 
    
         
            +
                      )
         
     | 
| 
       463 
492 
     | 
    
         
             
                    end
         
     | 
| 
       464 
493 
     | 
    
         | 
| 
       465 
494 
     | 
    
         
             
                    ##
         
     | 
| 
         @@ -473,9 +502,19 @@ module CarrierWave 
     | 
|
| 
       473 
502 
     | 
    
         
             
                      @file ||= directory.files.head(path)
         
     | 
| 
       474 
503 
     | 
    
         
             
                    end
         
     | 
| 
       475 
504 
     | 
    
         | 
| 
      
 505 
     | 
    
         
            +
                    def copy_options
         
     | 
| 
      
 506 
     | 
    
         
            +
                      options = {}
         
     | 
| 
      
 507 
     | 
    
         
            +
                      options.merge!(acl_header) if acl_header.present?
         
     | 
| 
      
 508 
     | 
    
         
            +
                      options[fog_provider == "Google" ? :content_type : 'Content-Type'] ||= content_type if content_type
         
     | 
| 
      
 509 
     | 
    
         
            +
                      options.merge(@uploader.fog_attributes)
         
     | 
| 
      
 510 
     | 
    
         
            +
                    end
         
     | 
| 
      
 511 
     | 
    
         
            +
             
     | 
| 
       476 
512 
     | 
    
         
             
                    def acl_header
         
     | 
| 
       477 
     | 
    
         
            -
                       
     | 
| 
      
 513 
     | 
    
         
            +
                      case fog_provider
         
     | 
| 
      
 514 
     | 
    
         
            +
                      when 'AWS'
         
     | 
| 
       478 
515 
     | 
    
         
             
                        { 'x-amz-acl' => @uploader.fog_public ? 'public-read' : 'private' }
         
     | 
| 
      
 516 
     | 
    
         
            +
                      when "Google"
         
     | 
| 
      
 517 
     | 
    
         
            +
                        @uploader.fog_public ? { destination_predefined_acl: "publicRead" } : {}
         
     | 
| 
       479 
518 
     | 
    
         
             
                      else
         
     | 
| 
       480 
519 
     | 
    
         
             
                        {}
         
     | 
| 
       481 
520 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -485,14 +524,14 @@ module CarrierWave 
     | 
|
| 
       485 
524 
     | 
    
         
             
                      @uploader.fog_credentials[:provider].to_s
         
     | 
| 
       486 
525 
     | 
    
         
             
                    end
         
     | 
| 
       487 
526 
     | 
    
         | 
| 
       488 
     | 
    
         
            -
                    def read_source_file 
     | 
| 
       489 
     | 
    
         
            -
                       
     | 
| 
      
 527 
     | 
    
         
            +
                    def read_source_file
         
     | 
| 
      
 528 
     | 
    
         
            +
                      source_file = to_file
         
     | 
| 
      
 529 
     | 
    
         
            +
                      return unless source_file
         
     | 
| 
       490 
530 
     | 
    
         | 
| 
       491 
531 
     | 
    
         
             
                      begin
         
     | 
| 
       492 
     | 
    
         
            -
                         
     | 
| 
       493 
     | 
    
         
            -
                        file_body.read
         
     | 
| 
      
 532 
     | 
    
         
            +
                        source_file.read
         
     | 
| 
       494 
533 
     | 
    
         
             
                      ensure
         
     | 
| 
       495 
     | 
    
         
            -
                         
     | 
| 
      
 534 
     | 
    
         
            +
                        source_file.close
         
     | 
| 
       496 
535 
     | 
    
         
             
                      end
         
     | 
| 
       497 
536 
     | 
    
         
             
                    end
         
     | 
| 
       498 
537 
     | 
    
         | 
    
        data/lib/carrierwave/storage.rb
    CHANGED
    
    
| 
         @@ -45,11 +45,11 @@ module CarrierWave 
     | 
|
| 
       45 
45 
     | 
    
         
             
                    def matches?(actual)
         
     | 
| 
       46 
46 
     | 
    
         
             
                      @actual = actual
         
     | 
| 
       47 
47 
     | 
    
         
             
                      # Satisfy expectation here. Return false or raise an error if it's not met.
         
     | 
| 
       48 
     | 
    
         
            -
                      (File.stat(@actual.path).mode &  
     | 
| 
      
 48 
     | 
    
         
            +
                      (File.stat(@actual.path).mode & 0o777) == @expected
         
     | 
| 
       49 
49 
     | 
    
         
             
                    end
         
     | 
| 
       50 
50 
     | 
    
         | 
| 
       51 
51 
     | 
    
         
             
                    def failure_message
         
     | 
| 
       52 
     | 
    
         
            -
                      "expected #{@actual.current_path.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode &  
     | 
| 
      
 52 
     | 
    
         
            +
                      "expected #{@actual.current_path.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode & 0o777).to_s(8)}"
         
     | 
| 
       53 
53 
     | 
    
         
             
                    end
         
     | 
| 
       54 
54 
     | 
    
         | 
| 
       55 
55 
     | 
    
         
             
                    def failure_message_when_negated
         
     | 
| 
         @@ -76,11 +76,11 @@ module CarrierWave 
     | 
|
| 
       76 
76 
     | 
    
         
             
                    def matches?(actual)
         
     | 
| 
       77 
77 
     | 
    
         
             
                      @actual = actual
         
     | 
| 
       78 
78 
     | 
    
         
             
                      # Satisfy expectation here. Return false or raise an error if it's not met.
         
     | 
| 
       79 
     | 
    
         
            -
                      (File.stat(File.dirname 
     | 
| 
      
 79 
     | 
    
         
            +
                      (File.stat(File.dirname(@actual.path)).mode & 0o777) == @expected
         
     | 
| 
       80 
80 
     | 
    
         
             
                    end
         
     | 
| 
       81 
81 
     | 
    
         | 
| 
       82 
82 
     | 
    
         
             
                    def failure_message
         
     | 
| 
       83 
     | 
    
         
            -
                      "expected #{File.dirname @actual.current_path.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode &  
     | 
| 
      
 83 
     | 
    
         
            +
                      "expected #{File.dirname @actual.current_path.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode & 0o777).to_s(8)}"
         
     | 
| 
       84 
84 
     | 
    
         
             
                    end
         
     | 
| 
       85 
85 
     | 
    
         | 
| 
       86 
86 
     | 
    
         
             
                    def failure_message_when_negated
         
     | 
| 
         @@ -341,9 +341,11 @@ module CarrierWave 
     | 
|
| 
       341 
341 
     | 
    
         
             
                          begin
         
     | 
| 
       342 
342 
     | 
    
         
             
                            require 'rmagick'
         
     | 
| 
       343 
343 
     | 
    
         
             
                          rescue LoadError
         
     | 
| 
       344 
     | 
    
         
            -
                             
     | 
| 
       345 
     | 
    
         
            -
             
     | 
| 
       346 
     | 
    
         
            -
                             
     | 
| 
      
 344 
     | 
    
         
            +
                            begin
         
     | 
| 
      
 345 
     | 
    
         
            +
                              require 'RMagick'
         
     | 
| 
      
 346 
     | 
    
         
            +
                            rescue LoadError
         
     | 
| 
      
 347 
     | 
    
         
            +
                              puts "WARNING: Failed to require rmagick, image processing may fail!"
         
     | 
| 
      
 348 
     | 
    
         
            +
                            end
         
     | 
| 
       347 
349 
     | 
    
         
             
                          end
         
     | 
| 
       348 
350 
     | 
    
         
             
                        end
         
     | 
| 
       349 
351 
     | 
    
         
             
                        MagickWrapper.new(filename)
         
     | 
| 
         @@ -353,6 +355,7 @@ module CarrierWave 
     | 
|
| 
       353 
355 
     | 
    
         | 
| 
       354 
356 
     | 
    
         
             
                  class MagickWrapper # :nodoc:
         
     | 
| 
       355 
357 
     | 
    
         
             
                    attr_reader :image
         
     | 
| 
      
 358 
     | 
    
         
            +
             
     | 
| 
       356 
359 
     | 
    
         
             
                    def width
         
     | 
| 
       357 
360 
     | 
    
         
             
                      image.columns
         
     | 
| 
       358 
361 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -372,6 +375,7 @@ module CarrierWave 
     | 
|
| 
       372 
375 
     | 
    
         | 
| 
       373 
376 
     | 
    
         
             
                  class MiniMagickWrapper # :nodoc:
         
     | 
| 
       374 
377 
     | 
    
         
             
                    attr_reader :image
         
     | 
| 
      
 378 
     | 
    
         
            +
             
     | 
| 
       375 
379 
     | 
    
         
             
                    def width
         
     | 
| 
       376 
380 
     | 
    
         
             
                      image[:width]
         
     | 
| 
       377 
381 
     | 
    
         
             
                    end
         
     |