carrierwave 2.2.2 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +180 -62
  3. data/lib/carrierwave/compatibility/paperclip.rb +4 -2
  4. data/lib/carrierwave/downloader/base.rb +28 -14
  5. data/lib/carrierwave/downloader/remote_file.rb +13 -10
  6. data/lib/carrierwave/locale/en.yml +5 -3
  7. data/lib/carrierwave/mount.rb +36 -50
  8. data/lib/carrierwave/mounter.rb +118 -50
  9. data/lib/carrierwave/orm/activerecord.rb +21 -62
  10. data/lib/carrierwave/processing/mini_magick.rb +45 -14
  11. data/lib/carrierwave/processing/rmagick.rb +47 -20
  12. data/lib/carrierwave/processing/vips.rb +43 -12
  13. data/lib/carrierwave/sanitized_file.rb +58 -77
  14. data/lib/carrierwave/storage/abstract.rb +5 -5
  15. data/lib/carrierwave/storage/file.rb +6 -5
  16. data/lib/carrierwave/storage/fog.rb +86 -65
  17. data/lib/carrierwave/test/matchers.rb +11 -7
  18. data/lib/carrierwave/uploader/cache.rb +19 -11
  19. data/lib/carrierwave/uploader/callbacks.rb +1 -1
  20. data/lib/carrierwave/uploader/configuration.rb +18 -8
  21. data/lib/carrierwave/uploader/{content_type_whitelist.rb → content_type_allowlist.rb} +18 -16
  22. data/lib/carrierwave/uploader/{content_type_blacklist.rb → content_type_denylist.rb} +20 -15
  23. data/lib/carrierwave/uploader/dimension.rb +66 -0
  24. data/lib/carrierwave/uploader/{extension_whitelist.rb → extension_allowlist.rb} +17 -15
  25. data/lib/carrierwave/uploader/{extension_blacklist.rb → extension_denylist.rb} +19 -14
  26. data/lib/carrierwave/uploader/file_size.rb +2 -2
  27. data/lib/carrierwave/uploader/processing.rb +45 -7
  28. data/lib/carrierwave/uploader/proxy.rb +16 -3
  29. data/lib/carrierwave/uploader/store.rb +70 -6
  30. data/lib/carrierwave/uploader/url.rb +1 -1
  31. data/lib/carrierwave/uploader/versions.rb +158 -138
  32. data/lib/carrierwave/uploader.rb +10 -8
  33. data/lib/carrierwave/utilities/file_name.rb +47 -0
  34. data/lib/carrierwave/utilities/uri.rb +14 -11
  35. data/lib/carrierwave/utilities.rb +1 -0
  36. data/lib/carrierwave/validations/active_model.rb +4 -6
  37. data/lib/carrierwave/version.rb +1 -1
  38. data/lib/carrierwave.rb +18 -17
  39. data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +1 -1
  40. data/lib/generators/uploader_generator.rb +3 -3
  41. metadata +37 -63
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b815c0a48b4df1ed7a3c3ea6f0d3cf4748b9197d5507b7b99ba262bcf703f8de
4
- data.tar.gz: b162ccab7c487c367702310819a3e14a05f014abed916a79112520550877a477
3
+ metadata.gz: 418e6b0903adc403510724ba7a5764e8edaa5b4bc96d5313e8f01572bf26ceac
4
+ data.tar.gz: 0bbac560a7928ce059afccb2280a1f77d17c9bca418a3f471097a3e3375fc6d0
5
5
  SHA512:
6
- metadata.gz: a6341493e822abeaa770f1c202e3ca62c43b54a2dcf1768e7d485208f825a546354d66b9c45d1169c2636d32a39b36312a8029729009504b87ab2ff6b8500187
7
- data.tar.gz: 9a8f6b9f5c2ba84f500a051f1ad9f7da603af42a746422f5a727fe79c02eb1cd9063c5b082fd7a051f263b52918d76a1abeb16ee4bb2dd8ecaea73d4a9f732fe
6
+ metadata.gz: 253d7d3f2e78fd169e347042c6eae2d5ab70f1383dc159988387215cb669ca905232817484f168816c21bcfb6733221a69c6ae02d7a463df920446ee53ae8efd
7
+ data.tar.gz: 7640c8c67f2bb11025a42c9b05752a167a3da4d3452dc3359ffc51e5cb5ea8460fd23be401446734daa573e77f9a0639b7f2cf053288d8c5360e63907a80f08c
data/README.md CHANGED
@@ -10,7 +10,7 @@ It works well with Rack based web applications, such as Ruby on Rails.
10
10
 
11
11
  ## Information
12
12
 
13
- * RDoc documentation [available on RubyDoc.info](http://rubydoc.info/gems/carrierwave/frames)
13
+ * RDoc documentation [available on RubyDoc.info](https://rubydoc.info/gems/carrierwave)
14
14
  * Source code [available on GitHub](http://github.com/carrierwaveuploader/carrierwave)
15
15
  * More information, known limitations, and how-tos [available on the wiki](https://github.com/carrierwaveuploader/carrierwave/wiki)
16
16
 
@@ -30,13 +30,19 @@ $ gem install carrierwave
30
30
  In Rails, add it to your Gemfile:
31
31
 
32
32
  ```ruby
33
- gem 'carrierwave', '~> 2.0'
33
+ gem 'carrierwave', '~> 3.0'
34
34
  ```
35
35
 
36
36
  Finally, restart the server to apply the changes.
37
37
 
38
- As of version 2.0, CarrierWave requires Rails 5.0 or higher and Ruby 2.2
39
- or higher. If you're on Rails 4, you should use 1.x.
38
+ ## Upgrading from 2.x or earlier
39
+
40
+ CarrierWave 3.0 comes with a change in the way of handling the file extension on conversion. This results in following issues if you use `process convert: :format` to change the file format:
41
+
42
+ - If you have it on the uploader itself (not within a version), the file extension of the cached file will change. That means if you serve both CarrierWave 2.x and 3.x simultaneously on the same workload (e.g. using blue-green deployment), a cache file stored by 2.x can't be retrieved by 3.x and vice versa.
43
+ - If you have it within a version, the file extension of the stored file will change. You need to perform `#recreate_versions!` to make it usable again.
44
+
45
+ To preserve the 2.x behavior, you can set `force_extension false` right after calling `process convert: :format`. See [#2659](https://github.com/carrierwaveuploader/carrierwave/pull/2659) for the detail.
40
46
 
41
47
  ## Getting Started
42
48
 
@@ -227,6 +233,20 @@ class MyUploader < CarrierWave::Uploader::Base
227
233
  end
228
234
  ```
229
235
 
236
+ ## Changing the filename
237
+
238
+ To change the filename of uploaded files, you can override `#filename` method in the uploader.
239
+
240
+ ```ruby
241
+ class MyUploader < CarrierWave::Uploader::Base
242
+ def filename
243
+ "image.#{file.extension}" # If you upload 'file.jpg', you'll get 'image.jpg'
244
+ end
245
+ end
246
+ ```
247
+
248
+ Some old documentations (like [this](https://stackoverflow.com/a/5865117)) may instruct you to safeguard the filename value with `if original_filename`, but it's no longer necessary with CarrierWave 3.0 or later.
249
+
230
250
  ## Securing uploads
231
251
 
232
252
  Certain files might be dangerous if uploaded to the wrong location, such as PHP
@@ -305,17 +325,8 @@ You no longer need to do this manually.
305
325
 
306
326
  ## Adding versions
307
327
 
308
- Often you'll want to add different versions of the same file. The classic example is image thumbnails. There is built in support for this*:
309
-
310
- *Note:* You must have Imagemagick installed to do image resizing.
311
-
312
- Some documentation refers to RMagick instead of MiniMagick but MiniMagick is recommended.
313
-
314
- To install Imagemagick on OSX with homebrew type the following:
315
-
316
- ```
317
- $ brew install imagemagick
318
- ```
328
+ Often you'll want to add different versions of the same file. The classic example is generating image thumbnails while preserving the original file to be used for high-quality representation.
329
+ In this section we'll explore how CarrierWave supports working with multiple versions. The image manipulation itself is covered in [another section](#manipulating-images).
319
330
 
320
331
  ```ruby
321
332
  class MyUploader < CarrierWave::Uploader::Base
@@ -351,17 +362,7 @@ uploader.thumb.url # => '/url/to/thumb_my_file.png' # size: 200x200
351
362
  One important thing to remember is that process is called *before* versions are
352
363
  created. This can cut down on processing cost.
353
364
 
354
- ### Processing Methods: mini_magick
355
-
356
- - `convert` - Changes the image encoding format to the given format, eg. jpg
357
- - `resize_to_limit` - Resize the image to fit within the specified dimensions while retaining the original aspect ratio. Will only resize the image if it is larger than the specified dimensions. The resulting image may be shorter or narrower than specified in the smaller dimension but will not be larger than the specified values.
358
- - `resize_to_fit` - Resize the image to fit within the specified dimensions while retaining the original aspect ratio. The image may be shorter or narrower than specified in the smaller dimension but will not be larger than the specified values.
359
- - `resize_to_fill` - Resize the image to fit within the specified dimensions while retaining the aspect ratio of the original image. If necessary, crop the image in the larger dimension. Optionally, a "gravity" may be specified, for example "Center", or "NorthEast".
360
- - `resize_and_pad` - Resize the image to fit within the specified dimensions while retaining the original aspect ratio. If necessary, will pad the remaining area with the given color, which defaults to transparent (for gif and png, white for jpeg). Optionally, a "gravity" may be specified, as above.
361
-
362
- See `carrierwave/processing/mini_magick.rb` for details.
363
-
364
- ### conditional process
365
+ ### Conditional processing
365
366
 
366
367
  If you want to use conditional process, you can only use `if` statement.
367
368
 
@@ -445,8 +446,27 @@ class MyUploader < CarrierWave::Uploader::Base
445
446
  end
446
447
  ```
447
448
 
448
- The option `:from_version` uses the file cached in the `:thumb` version instead
449
- of the original version, potentially resulting in faster processing.
449
+ ### Customizing version filenames
450
+
451
+ CarrierWave supports [customization of filename](#changing-the-filename) by overriding an uploader's
452
+ #filename method, but this doesn't work for versions because of the limitation on how CarrierWave
453
+ re-constructs the filename on retrieval of the stored file.
454
+ Instead, you can override `#full_filename` with providing a version-aware name.
455
+
456
+ ```ruby
457
+ class MyUploader < CarrierWave::Uploader::Base
458
+ version :thumb do
459
+ def full_filename(for_file)
460
+ 'thumb.png'
461
+ end
462
+ process convert: 'png'
463
+ end
464
+ end
465
+ ```
466
+
467
+ Please note that `#full_filename` mustn't be constructed based on a dynamic value
468
+ that can change from the time of store and time of retrieval, since it will result in
469
+ being unable to retrieve a file previously stored.
450
470
 
451
471
  ## Making uploads work across form redisplays
452
472
 
@@ -531,6 +551,17 @@ failures automatically with attribute validation errors. If you aren't, or you
531
551
  disable CarrierWave's `validate_download` option, you'll need to handle those
532
552
  errors yourself.
533
553
 
554
+ ### Retry option for download from remote location
555
+ If you want to retry the download from the Remote URL, enable the download_retry_count option, an error occurs during download, it will try to execute the specified number of times.
556
+ This option is effective when the remote destination is unstable.
557
+
558
+ ```rb
559
+ CarrierWave.configure do |config|
560
+ config.download_retry_count = 3 # Default 0
561
+ config.download_retry_wait_time = 3 # Default 5
562
+ end
563
+ ```
564
+
534
565
  ## Providing a default URL
535
566
 
536
567
  In many cases, especially when working with images, it might be a good idea to
@@ -628,14 +659,17 @@ end
628
659
  ## Testing with CarrierWave
629
660
 
630
661
  It's a good idea to test your uploaders in isolation. In order to speed up your
631
- tests, it's recommended to switch off processing in your tests, and to use the
632
- file storage. In Rails you could do that by adding an initializer with:
662
+ tests, it's recommended to switch off processing in your tests, and to use the file storage.
663
+ Also, you can disable SSRF protection at your own risk using the `skip_ssrf_protection` configuration.
664
+
665
+ In Rails you could do that by adding an initializer with:
633
666
 
634
667
  ```ruby
635
668
  if Rails.env.test? or Rails.env.cucumber?
636
669
  CarrierWave.configure do |config|
637
670
  config.storage = :file
638
671
  config.enable_processing = false
672
+ config.skip_ssrf_protection = true
639
673
  end
640
674
  end
641
675
  ```
@@ -733,6 +767,10 @@ CarrierWave.configure do |config|
733
767
  config.fog_directory = 'name_of_bucket' # required
734
768
  config.fog_public = false # optional, defaults to true
735
769
  config.fog_attributes = { cache_control: "public, max-age=#{365.days.to_i}" } # optional, defaults to {}
770
+ # Use this if you have AWS S3 ACLs disabled.
771
+ # config.fog_attributes = { 'x-amz-acl' => 'bucket-owner-full-control' }
772
+ # Use this if you have Google Cloud Storage uniform bucket-level access enabled.
773
+ # config.fog_attributes = { uniform: true }
736
774
  # For an application which utilizes multiple servers but does not need caches persisted across requests,
737
775
  # uncomment the line :file instead of the default :storage. Otherwise, it will use AWS as the temp cache store.
738
776
  # config.cache_storage = :file
@@ -766,7 +804,7 @@ gem "fog"
766
804
  ```
767
805
 
768
806
  You'll need to configure a directory (also known as a container), username and API key in the initializer.
769
- For the sake of performance it is assumed that the directory already exists, so please create it if need be.
807
+ For the sake of performance it is assumed that the directory already exists, so please create it if needs to be.
770
808
 
771
809
  Using a US-based account:
772
810
 
@@ -825,14 +863,13 @@ gem "fog-google"
825
863
  ```
826
864
 
827
865
  You'll need to configure a directory (also known as a bucket) and the credentials in the initializer.
828
- For the sake of performance it is assumed that the directory already exists, so please create it if need be.
866
+ For the sake of performance it is assumed that the directory already exists, so please create it if needs to be.
829
867
 
830
868
  Please read the [fog-google README](https://github.com/fog/fog-google/blob/master/README.md) on how to get credentials.
831
869
 
832
870
  For Google Storage JSON API (recommended):
833
871
  ```ruby
834
872
  CarrierWave.configure do |config|
835
- config.fog_provider = 'fog/google'
836
873
  config.fog_credentials = {
837
874
  provider: 'Google',
838
875
  google_project: 'my-project',
@@ -846,7 +883,6 @@ end
846
883
  For Google Storage XML API:
847
884
  ```ruby
848
885
  CarrierWave.configure do |config|
849
- config.fog_provider = 'fog/google'
850
886
  config.fog_credentials = {
851
887
  provider: 'Google',
852
888
  google_storage_access_key_id: 'xxxxxx',
@@ -905,12 +941,48 @@ CarrierWave.configure do |config|
905
941
  end
906
942
  ```
907
943
 
908
- ## Using RMagick
944
+ ## Manipulating images
909
945
 
910
946
  If you're uploading images, you'll probably want to manipulate them in some way,
911
- you might want to create thumbnail images for example. CarrierWave comes with a
912
- small library to make manipulating images with RMagick easier, you'll need to
913
- include it in your Uploader:
947
+ you might want to create thumbnail images for example.
948
+
949
+ ### Using MiniMagick
950
+
951
+ MiniMagick performs all the operations using the 'convert' CLI which is part of the standard ImageMagick kit.
952
+ This allows you to have the power of ImageMagick without having to worry about installing
953
+ all the RMagick libraries, it often results in higher memory footprint.
954
+
955
+ See the MiniMagick site for more details:
956
+
957
+ https://github.com/minimagick/minimagick
958
+
959
+ To install Imagemagick on OSX with homebrew type the following:
960
+
961
+ ```
962
+ $ brew install imagemagick
963
+ ```
964
+
965
+ And the ImageMagick command line options for more for what's on offer:
966
+
967
+ http://www.imagemagick.org/script/command-line-options.php
968
+
969
+ Currently, the MiniMagick carrierwave processor provides exactly the same methods as
970
+ for the RMagick processor.
971
+
972
+ ```ruby
973
+ class AvatarUploader < CarrierWave::Uploader::Base
974
+ include CarrierWave::MiniMagick
975
+
976
+ process resize_to_fill: [200, 200]
977
+ end
978
+ ```
979
+
980
+ See `carrierwave/processing/mini_magick.rb` for details.
981
+
982
+ ### Using RMagick
983
+
984
+ CarrierWave also comes with support for RMagick, a well-known image processing library.
985
+ To use it, you'll need to include this in your Uploader:
914
986
 
915
987
  ```ruby
916
988
  class AvatarUploader < CarrierWave::Uploader::Base
@@ -923,7 +995,6 @@ The RMagick module gives you a few methods, like
923
995
  way. You can set a `process` callback, which will call that method any time a
924
996
  file is uploaded.
925
997
  There is a demonstration of convert here.
926
- Convert will only work if the file has the same file extension, thus the use of the filename method.
927
998
 
928
999
  ```ruby
929
1000
  class AvatarUploader < CarrierWave::Uploader::Base
@@ -931,40 +1002,59 @@ class AvatarUploader < CarrierWave::Uploader::Base
931
1002
 
932
1003
  process resize_to_fill: [200, 200]
933
1004
  process convert: 'png'
934
-
935
- def filename
936
- super.chomp(File.extname(super)) + '.png' if original_filename.present?
937
- end
938
1005
  end
939
1006
  ```
940
1007
 
941
1008
  Check out the manipulate! method, which makes it easy for you to write your own
942
1009
  manipulation methods.
943
1010
 
944
- ## Using MiniMagick
1011
+ ### Using Vips
945
1012
 
946
- MiniMagick is similar to RMagick but performs all the operations using the 'convert'
947
- CLI which is part of the standard ImageMagick kit. This allows you to have the power
948
- of ImageMagick without having to worry about installing all the RMagick libraries.
1013
+ CarrierWave version 2.2.0 added support for the `libvips` image processing library, through [ImageProcessing::Vips](https://github.com/janko/image_processing/blob/master/doc/vips.md). Its functionality matches that of the RMagick and MiniMagick processors, but it uses less memory and offers [faster processing](https://github.com/libvips/libvips/wiki/Speed-and-memory-use). To use the Vips processing module you must first install `libvips`, for example:
949
1014
 
950
- See the MiniMagick site for more details:
1015
+ ````bash
1016
+ $ sudo apt install libvips
1017
+ ````
951
1018
 
952
- https://github.com/minimagick/minimagick
1019
+ You also need to tell your uploader to use Vips:
953
1020
 
954
- And the ImageMagick command line options for more for whats on offer:
1021
+ ````ruby
1022
+ class ImageFileUploader < CarrierWave::Uploader::Base
1023
+ include CarrierWave::Vips
1024
+ end
1025
+ ````
955
1026
 
956
- http://www.imagemagick.org/script/command-line-options.php
1027
+ ### List of available processing methods:
957
1028
 
958
- Currently, the MiniMagick carrierwave processor provides exactly the same methods as
959
- for the RMagick processor.
1029
+ > [!NOTE]
1030
+ > While the intention is to provide uniform interfaces to all three processing libraries the availability and implementation of processing methods can <a href="supported-processing-methods">vary slightly between them</a>.
960
1031
 
961
- ```ruby
962
- class AvatarUploader < CarrierWave::Uploader::Base
963
- include CarrierWave::MiniMagick
1032
+ - `convert` - Changes the image encoding format to the given format (eg. jpg). This operation is treated specially to trigger the change of the file extension, so it matches with the format of the resulting file.
1033
+ - `resize_to_limit` - Resize the image to fit within the specified dimensions while retaining the original aspect ratio. Will only resize the image if it is larger than the specified dimensions. The resulting image may be shorter or narrower than specified in the smaller dimension but will not be larger than the specified values.
1034
+ - `resize_to_fit` - Resize the image to fit within the specified dimensions while retaining the original aspect ratio. The image may be shorter or narrower than specified in the smaller dimension but will not be larger than the specified values.
1035
+ - `resize_to_fill` - Resize the image to fit within the specified dimensions while retaining the aspect ratio of the original image. If necessary, crop the image in the larger dimension. Optionally, a "gravity" may be specified, for example "Center", or "NorthEast".
1036
+ - `resize_and_pad` - Resize the image to fit within the specified dimensions while retaining the original aspect ratio. If necessary, will pad the remaining area with the given color, which defaults to transparent (for gif and png, white for jpeg). Optionally, a "gravity" may be specified, as above.
1037
+ - `crop` - Crop the image to the contents of a box with the specified height and width, positioned a given number of pixels from the top and left. The original image edge will be retained should the bottom and/or right edge of the box fall outside the image bounds.
964
1038
 
965
- process resize_to_fill: [200, 200]
966
- end
967
- ```
1039
+ #### Supported processing methods
1040
+
1041
+ The following table shows which processing methods are supported by each processing library, and which parameters they accept:
1042
+
1043
+ Method|RMagick|MiniMagick|Vips
1044
+ ------|-----------------|-----------------|-----------------|
1045
+ `convert`|`format`|`format`, `page`<sup>1</sup>|`format`, `page`<sup>1</sup>
1046
+ `resize_to_limit`|`width`, `height`|`width`, `height`|`width`, `height`
1047
+ `resize_to_fit`|`width`, `height`|`width`, `height`|`width`, `height`
1048
+ `resize_to_fill`|`width`, `height`, `gravity`<sup>2</sup>|`width`, `height`, `gravity`<sup>2</sup>|`width`, `height`
1049
+ `resize_and_pad`|`width`, `height`, `background`, `gravity`<sup>2</sup>|`width`, `height`, `background`, `gravity`<sup>2</sup>|`width`, `height`, `background`, `gravity`<sup>2</sup>
1050
+ `resize_to_geometry_string`|`geometry_string`<sup>3</sup>|*not implemented*|*not implemented*
1051
+ `crop`|`left`, `top`, `width`, `height`|`left`, `top`, `width`, `height`|`left`, `top`, `width`, `height`
1052
+
1053
+ <sup>1</sup>`page` refers to the page number when converting from PDF, frame number when converting from GIF, and layer number when converting from PSD.
1054
+
1055
+ <sup>2</sup>`gravity` refers to an image position given as one of `Center`, `North`, `NorthWest`, `West`, `SouthWest`, `South`, `SouthEast`, `East`, or `NorthEast`.
1056
+
1057
+ <sup>3</sup>`geometry_string` is an [ImageMagick geometry string](https://rmagick.github.io/imusage.html#geometry).
968
1058
 
969
1059
  ## Migrating from Paperclip
970
1060
 
@@ -1000,10 +1090,13 @@ errors:
1000
1090
  extension_denylist_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
1001
1091
  content_type_allowlist_error: "You are not allowed to upload %{content_type} files, allowed types: %{allowed_types}"
1002
1092
  content_type_denylist_error: "You are not allowed to upload %{content_type} files"
1003
- rmagick_processing_error: "Failed to manipulate with rmagick, maybe it is not an image?"
1004
- mini_magick_processing_error: "Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}"
1093
+ processing_error: "Failed to manipulate, maybe it is not an image?"
1005
1094
  min_size_error: "File size should be greater than %{min_size}"
1006
1095
  max_size_error: "File size should be less than %{max_size}"
1096
+ min_width_error: "Image width should be greater than %{min_width}px"
1097
+ max_width_error: "Image width should be less than %{max_width}px"
1098
+ min_height_error: "Image height should be greater than %{min_height}px"
1099
+ max_height_error: "Image height should be less than %{max_height}px"
1007
1100
  ```
1008
1101
 
1009
1102
  The [`carrierwave-i18n`](https://github.com/carrierwaveuploader/carrierwave-i18n)
@@ -1066,6 +1159,31 @@ class User
1066
1159
  end
1067
1160
  ```
1068
1161
 
1162
+ ## Uploader Callbacks
1163
+
1164
+ In addition to the ActiveRecord callbacks described above, uploaders also have callbacks.
1165
+
1166
+ ```ruby
1167
+ class MyUploader < ::CarrierWave::Uploader::Base
1168
+ before :remove, :log_removal
1169
+ private
1170
+ def log_removal
1171
+ ::Rails.logger.info(format('Deleting file on S3: %s', @file))
1172
+ end
1173
+ end
1174
+ ```
1175
+
1176
+ Uploader callbacks can be `before` or `after` the following events:
1177
+
1178
+ ```
1179
+ cache
1180
+ process
1181
+ remove
1182
+ retrieve_from_cache
1183
+ retrieve_from_store
1184
+ store
1185
+ ```
1186
+
1069
1187
  ## Contributing to CarrierWave
1070
1188
 
1071
1189
  See [CONTRIBUTING.md](https://github.com/carrierwaveuploader/carrierwave/blob/master/CONTRIBUTING.md)
@@ -1074,7 +1192,7 @@ See [CONTRIBUTING.md](https://github.com/carrierwaveuploader/carrierwave/blob/ma
1074
1192
 
1075
1193
  The MIT License (MIT)
1076
1194
 
1077
- Copyright (c) 2008-2015 Jonas Nicklas
1195
+ Copyright (c) 2008 Jonas Nicklas
1078
1196
 
1079
1197
  Permission is hereby granted, free of charge, to any person obtaining
1080
1198
  a copy of this software and associated documentation files (the
@@ -56,10 +56,11 @@ module CarrierWave
56
56
  :basename => lambda{|u, f| u.filename.gsub(/#{File.extname(u.filename)}$/, "") },
57
57
  :extension => lambda{|u, d| File.extname(u.filename).gsub(/^\.+/, "")},
58
58
  :class => lambda{|u, f| u.model.class.name.underscore.pluralize}
59
- }
59
+ }.freeze
60
60
 
61
61
  included do
62
62
  attr_accessor :filename
63
+
63
64
  class_attribute :mappings
64
65
  self.mappings ||= DEFAULT_MAPPINGS.dup
65
66
  end
@@ -92,7 +93,8 @@ module CarrierWave
92
93
  end
93
94
  end
94
95
 
95
- private
96
+ private
97
+
96
98
  def interpolate_paperclip_path(path)
97
99
  mappings.each_pair.inject(path) do |agg, pair|
98
100
  agg.gsub(":#{pair[0]}") { pair[1].call(self, self.paperclip_style).to_s }
@@ -6,6 +6,8 @@ require 'carrierwave/downloader/remote_file'
6
6
  module CarrierWave
7
7
  module Downloader
8
8
  class Base
9
+ include CarrierWave::Utilities::Uri
10
+
9
11
  attr_reader :uploader
10
12
 
11
13
  def initialize(uploader)
@@ -21,6 +23,7 @@ module CarrierWave
21
23
  # [remote_headers (Hash)] Request headers
22
24
  #
23
25
  def download(url, remote_headers = {})
26
+ @current_download_retry_count = 0
24
27
  headers = remote_headers.
25
28
  reverse_merge('User-Agent' => "CarrierWave/#{CarrierWave::VERSION}")
26
29
  uri = process_uri(url.to_s)
@@ -29,14 +32,26 @@ module CarrierWave
29
32
  response = OpenURI.open_uri(process_uri(url.to_s), headers)
30
33
  else
31
34
  request = nil
32
- response = SsrfFilter.get(uri, headers: headers) do |req|
33
- request = req
35
+ if ::SsrfFilter::VERSION.to_f < 1.1
36
+ response = SsrfFilter.get(uri, headers: headers) do |req|
37
+ request = req
38
+ end
39
+ else
40
+ response = SsrfFilter.get(uri, headers: headers, request_proc: ->(req) { request = req }) do |res|
41
+ res.body # ensure to read body
42
+ end
34
43
  end
35
44
  response.uri = request.uri
36
45
  response.value
37
46
  end
38
47
  rescue StandardError => e
39
- raise CarrierWave::DownloadError, "could not download file: #{e.message}"
48
+ if @current_download_retry_count < @uploader.download_retry_count
49
+ @current_download_retry_count += 1
50
+ sleep @uploader.download_retry_wait_time
51
+ retry
52
+ else
53
+ raise CarrierWave::DownloadError, "could not download file: #{e.message}"
54
+ end
40
55
  end
41
56
  CarrierWave::Downloader::RemoteFile.new(response)
42
57
  end
@@ -48,17 +63,16 @@ module CarrierWave
48
63
  #
49
64
  # [url (String)] The URL where the remote file is stored
50
65
  #
51
- def process_uri(uri)
52
- uri_parts = uri.split('?')
53
- encoded_uri = Addressable::URI.parse(uri_parts.shift).normalize.to_s
54
- query = uri_parts.any? ? "?#{uri_parts.join('?')}" : ''
55
- begin
56
- URI.parse("#{encoded_uri}#{query}")
57
- rescue URI::InvalidURIError
58
- URI.parse("#{encoded_uri}#{URI::DEFAULT_PARSER.escape(query)}")
59
- end
66
+ def process_uri(source)
67
+ uri = Addressable::URI.parse(source)
68
+ uri.host = uri.normalized_host
69
+ # Perform decode first, as the path is likely to be already encoded
70
+ uri.path = encode_path(decode_uri(uri.path)) if uri.path =~ CarrierWave::Utilities::Uri::PATH_UNSAFE
71
+ uri.query = encode_non_ascii(uri.query) if uri.query
72
+ uri.fragment = encode_non_ascii(uri.fragment) if uri.fragment
73
+ URI.parse(uri.to_s)
60
74
  rescue URI::InvalidURIError, Addressable::URI::InvalidURIError
61
- raise CarrierWave::DownloadError, "couldn't parse URL: #{uri}"
75
+ raise CarrierWave::DownloadError, "couldn't parse URL: #{source}"
62
76
  end
63
77
 
64
78
  ##
@@ -80,7 +94,7 @@ module CarrierWave
80
94
  # my_uploader.downloader = CarrierWave::Downloader::CustomDownloader
81
95
  #
82
96
  def skip_ssrf_protection?(uri)
83
- false
97
+ @uploader.skip_ssrf_protection
84
98
  end
85
99
  end
86
100
  end
@@ -8,7 +8,10 @@ module CarrierWave
8
8
  when String
9
9
  @file = StringIO.new(file)
10
10
  when Net::HTTPResponse
11
- @file = StringIO.new(file.body)
11
+ body = file.body
12
+ raise CarrierWave::DownloadError, 'could not download file: No Content' if body.nil?
13
+
14
+ @file = StringIO.new(body)
12
15
  @content_type = file.content_type
13
16
  @headers = file
14
17
  @uri = file.uri
@@ -30,18 +33,15 @@ module CarrierWave
30
33
 
31
34
  def original_filename
32
35
  filename = filename_from_header || filename_from_uri
33
- mime_type = MiniMime.lookup_by_content_type(content_type)
34
- unless File.extname(filename).present? || mime_type.blank?
35
- filename = "#{filename}.#{mime_type.extension}"
36
+ extensions = Marcel::Magic.new(content_type).extensions
37
+ unless File.extname(filename).present? || extensions.blank?
38
+ extension = extensions.first
39
+ filename = "#{filename}.#{extension}"
36
40
  end
37
41
  filename
38
42
  end
39
43
 
40
- def respond_to?(*args)
41
- super || file.respond_to?(*args)
42
- end
43
-
44
- private
44
+ private
45
45
 
46
46
  def filename_from_header
47
47
  return nil unless headers['content-disposition']
@@ -59,7 +59,10 @@ module CarrierWave
59
59
  def method_missing(*args, &block)
60
60
  file.send(*args, &block)
61
61
  end
62
+
63
+ def respond_to_missing?(*args)
64
+ super || file.respond_to?(*args)
65
+ end
62
66
  end
63
67
  end
64
68
  end
65
-
@@ -8,8 +8,10 @@ en:
8
8
  extension_denylist_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
9
9
  content_type_allowlist_error: "You are not allowed to upload %{content_type} files, allowed types: %{allowed_types}"
10
10
  content_type_denylist_error: "You are not allowed to upload %{content_type} files"
11
- rmagick_processing_error: "Failed to manipulate with rmagick, maybe it is not an image?"
12
- mini_magick_processing_error: "Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}"
13
- vips_processing_error: "Failed to manipulate with vips, maybe it is not an image? Original Error: %{e}"
11
+ processing_error: "Failed to manipulate, maybe it is not an image?"
14
12
  min_size_error: "File size should be greater than %{min_size}"
15
13
  max_size_error: "File size should be less than %{max_size}"
14
+ min_width_error: "Image width should be greater than %{min_width}px"
15
+ max_width_error: "Image width should be less than %{max_width}px"
16
+ min_height_error: "Image height should be greater than %{min_height}px"
17
+ max_height_error: "Image height should be less than %{max_height}px"