rack_resize 0.1.1 → 0.1.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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/README.md +1 -1
- data/lib/rack_resize/configuration.rb +31 -6
- data/lib/rack_resize/input_parsers/cloudflare.rb +20 -2
- data/lib/rack_resize/processing.rb +11 -11
- data/lib/rack_resize/processors/imlib2.rb +0 -1
- data/lib/rack_resize/processors/mini_magick.rb +0 -6
- data/lib/rack_resize/processors/sips.rb +30 -26
- data/lib/rack_resize/processors/vips.rb +0 -2
- data/lib/rack_resize/rack_app.rb +27 -24
- data/lib/rack_resize/rails_autoload.rb +1 -1
- data/lib/rack_resize.rb +5 -1
- data/rack_resize.gemspec +2 -2
- metadata +4 -10
- data/samples/image_1.jpeg +0 -0
- data/samples/image_2.jpeg +0 -0
- data/samples/image_3.jpeg +0 -0
- data/samples/image_4.jpeg +0 -0
- data/samples/index.html +0 -34
- data/test/rack_app_test.rb +0 -146
- data/test/test_helper.rb +0 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 48043ad5846a54c36958ce1d2b4648de14b01c30db46ec8dcdb2b601628118f2
|
|
4
|
+
data.tar.gz: 2ccd0c5703c104cb952bd4e299fc6e1be49ef2e08849f2a9637d661adca13a22
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9fa7b2853a0701bf476f9730d1aae31ffc9edb28f53d032e8d51acb3c7e82fdd07e64e2225d4195507bfde69956b44bc48152d9d4b1c4e2fa840fe140d592518
|
|
7
|
+
data.tar.gz: e0b76b4d16323c0a87bae2d8c61fa2d44d0a72d1d27c6d8872bd091084ab2a5f9055216a48af9724af5ccff8dba6cf782acf8f7a38ca0216039318a87268c479
|
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
4.0.5
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -32,7 +32,7 @@ Fastly and bunny.net: (tbd)
|
|
|
32
32
|
|
|
33
33
|
```ruby
|
|
34
34
|
RackResize.configure do |config|
|
|
35
|
-
config.
|
|
35
|
+
config.assets_folders = { "assets" => Rails.root.join('app', 'assets', 'images') }
|
|
36
36
|
config.processor = :sips / :vips / :mini_magick / :imlib2
|
|
37
37
|
config.default_quality = 95
|
|
38
38
|
config.save_resized = false
|
|
@@ -3,8 +3,8 @@ require 'pathname'
|
|
|
3
3
|
class RackResize::Configuration
|
|
4
4
|
PROCESSORS = %i[sips vips mini_magick imlib2].freeze
|
|
5
5
|
|
|
6
|
-
attr_reader :processor
|
|
7
|
-
attr_accessor :save_resized, :default_quality, :cache_folder, :
|
|
6
|
+
attr_reader :processor, :assets_folders
|
|
7
|
+
attr_accessor :save_resized, :default_quality, :cache_folder, :http_cache_max_age, :max_dimension, :logger
|
|
8
8
|
|
|
9
9
|
alias_method :save_resized?, :save_resized
|
|
10
10
|
|
|
@@ -13,12 +13,20 @@ class RackResize::Configuration
|
|
|
13
13
|
@save_resized = options.key?(:save_resized) ? options[:save_resized] : false
|
|
14
14
|
@default_quality = options[:default_quality] || 95
|
|
15
15
|
@cache_folder = options[:cache_folder]
|
|
16
|
-
@assets_folder = options[:assets_folder] ? Pathname.new(options[:assets_folder]) : nil
|
|
17
16
|
@http_cache_max_age = options[:http_cache_max_age] || 86400 # 1 day
|
|
17
|
+
@max_dimension = options[:max_dimension] || 4000
|
|
18
|
+
@logger = options[:logger]
|
|
18
19
|
|
|
19
|
-
if
|
|
20
|
+
self.assets_folders = options[:assets_folders] if options[:assets_folders]
|
|
21
|
+
|
|
22
|
+
if defined?(Rails) && Rails.respond_to?(:root) && Rails.root
|
|
20
23
|
@cache_folder ||= Rails.root.join('tmp', 'rack_resize_cache')
|
|
21
|
-
|
|
24
|
+
unless options.key?(:assets_folders)
|
|
25
|
+
self.assets_folders = {
|
|
26
|
+
"assets" => Rails.root.join("app/assets/images"),
|
|
27
|
+
"uploads" => Rails.root.join("public/uploads"),
|
|
28
|
+
}
|
|
29
|
+
end
|
|
22
30
|
unless options.key?(:save_resized)
|
|
23
31
|
@save_resized = true
|
|
24
32
|
end
|
|
@@ -29,6 +37,17 @@ class RackResize::Configuration
|
|
|
29
37
|
end
|
|
30
38
|
end
|
|
31
39
|
|
|
40
|
+
def assets_folders=(values)
|
|
41
|
+
if values.is_a?(Array)
|
|
42
|
+
@assets_folders = values.map { |v| [format_asset_path(v), Pathname.new(v)] }.to_h
|
|
43
|
+
elsif values.is_a?(Hash)
|
|
44
|
+
@assets_folders = values.transform_values { |v| v.is_a?(Pathname) ? v : Pathname.new(v) }
|
|
45
|
+
.transform_keys {|k| format_asset_path(k) }
|
|
46
|
+
else
|
|
47
|
+
raise ArgumentError, "RackResize::Configuration.assets_folders can be either hash or array, received #{values.class}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
32
51
|
def processor=(value)
|
|
33
52
|
value = value.to_sym
|
|
34
53
|
unless PROCESSORS.include?(value)
|
|
@@ -40,7 +59,7 @@ class RackResize::Configuration
|
|
|
40
59
|
|
|
41
60
|
def processor_instance
|
|
42
61
|
@processor_instance ||= case @processor
|
|
43
|
-
when :mini_magick then RackResize::MiniMagick.new
|
|
62
|
+
when :mini_magick then RackResize::Processors::MiniMagick.new
|
|
44
63
|
when :vips then RackResize::Processors::Vips.new
|
|
45
64
|
when :sips then RackResize::Processors::Sips.new
|
|
46
65
|
when :imlib2 then RackResize::Processors::Imlib2.new
|
|
@@ -48,4 +67,10 @@ class RackResize::Configuration
|
|
|
48
67
|
raise "RackResize - Unknow image processor #{@processor.inspect}"
|
|
49
68
|
end
|
|
50
69
|
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def format_asset_path(path)
|
|
74
|
+
path.start_with?('/') ? path.to_s : "/#{path}"
|
|
75
|
+
end
|
|
51
76
|
end
|
|
@@ -1,4 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
module RackResize::InputParsers::Cloudflare
|
|
2
|
+
extend self
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
# process string like this
|
|
5
|
+
# /cdn-cgi/image/width=426,format=auto/assets/templates/vancouver-27c47f55.jpg
|
|
6
|
+
|
|
7
|
+
def parse_input(fullpath, cf_path_prefix:)
|
|
8
|
+
unless fullpath.start_with?(cf_path_prefix)
|
|
9
|
+
return { route_matched: false, req_params: nil, asset_path: nil }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
fullpath = fullpath.delete_prefix("/cdn-cgi").delete_prefix("/image").delete_prefix("/")
|
|
13
|
+
file_path_match = fullpath.match(%r{(?<params>[^\/]+)(?<file>\/.+?)(-[\da-f]{8})?(?<ext>\.\w{2,})$})
|
|
14
|
+
|
|
15
|
+
return { route_matched: true, req_params: nil, asset_path: nil } unless file_path_match
|
|
16
|
+
|
|
17
|
+
req_params = file_path_match[:params].split(",").map {|s| s.split("=") }.to_h.transform_keys(&:to_sym)
|
|
18
|
+
asset_path = "#{file_path_match[:file]}#{file_path_match[:ext]}"
|
|
19
|
+
|
|
20
|
+
{ route_matched: true, req_params:, asset_path: }
|
|
21
|
+
end
|
|
4
22
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'digest'
|
|
2
|
+
|
|
1
3
|
class RackResize::Processing
|
|
2
4
|
attr_reader :config
|
|
3
5
|
|
|
@@ -24,8 +26,11 @@ class RackResize::Processing
|
|
|
24
26
|
|
|
25
27
|
def process_file(source_file:, req_params:, target_file: nil)
|
|
26
28
|
dpr = req_params[:dpr]&.to_f || 1.0
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
dpr = [[dpr, 0.1].max, 10.0].min
|
|
30
|
+
|
|
31
|
+
max = config.max_dimension.to_f
|
|
32
|
+
target_width = (req_params[:w]&.to_i || req_params[:width]&.to_i)&.*(dpr)&.clamp(1, max)
|
|
33
|
+
target_height = (req_params[:h]&.to_i || req_params[:height]&.to_i)&.*(dpr)&.clamp(1, max)
|
|
29
34
|
|
|
30
35
|
start_time = Time.now
|
|
31
36
|
begin
|
|
@@ -37,13 +42,8 @@ class RackResize::Processing
|
|
|
37
42
|
end
|
|
38
43
|
|
|
39
44
|
def logger
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
else
|
|
44
|
-
require 'logger'
|
|
45
|
-
Logger.new(STDOUT)
|
|
46
|
-
end
|
|
47
|
-
end
|
|
45
|
+
config.logger ||
|
|
46
|
+
(defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger) ||
|
|
47
|
+
(require('logger') && Logger.new(STDOUT))
|
|
48
48
|
end
|
|
49
|
-
end
|
|
49
|
+
end
|
|
@@ -11,7 +11,6 @@ class RackResize::Processors::Imlib2
|
|
|
11
11
|
image.resize!(target_width || :auto, target_height || :auto) if target_width || target_height
|
|
12
12
|
|
|
13
13
|
if target_file
|
|
14
|
-
image.call(destination: target_file)
|
|
15
14
|
image.save(target_file)
|
|
16
15
|
else
|
|
17
16
|
image.save_data(format: source_file.to_s =~ /\.png$/ ? :png : :jpeg)
|
|
@@ -45,9 +45,3 @@ class RackResize::Processors::MiniMagick
|
|
|
45
45
|
image&.destroy!
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
|
-
|
|
49
|
-
# magick /Users/pavel/Work/resume-io/app/assets/images/templates/vancouver.jpg -auto-orient -resize 426.0x> -quality 95 /Users/pavel/Work/resume-io/tmp/cdn_cgi_cache/60f2727cce350874040b321219f05766.jpg
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
# magick mogrify -resize 426.0x> /var/folders/n9/b__lxh7j1_xcwg4k_8j2_39m0000gp/T/mini_magick20260709-58478-qowydk.jpg
|
|
53
|
-
# magick mogrify -quality 95 /var/folders/n9/b__lxh7j1_xcwg4k_8j2_39m0000gp/T/mini_magick20260709-58478-qowydk.jpg
|
|
@@ -1,37 +1,41 @@
|
|
|
1
|
-
require "
|
|
1
|
+
require "open3"
|
|
2
2
|
|
|
3
3
|
class RackResize::Processors::Sips
|
|
4
4
|
|
|
5
5
|
def resize(source_file:, target_width:, target_height:, target_file: nil)
|
|
6
|
-
|
|
7
|
-
args
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
args = %w[sips --deleteColorManagementProperties]
|
|
7
|
+
args += ["-s", "formatOptions", RackResize.config.default_quality.to_s]
|
|
8
|
+
|
|
9
|
+
if target_width && target_height
|
|
10
|
+
info, status = Open3.capture2("sips", "-g", "pixelWidth", "-g", "pixelHeight", source_file.to_s)
|
|
11
|
+
raise "sips failed to read dimensions for #{source_file}" unless status.success?
|
|
12
|
+
src_w = info[/pixelWidth: (\d+)/, 1]&.to_f
|
|
13
|
+
src_h = info[/pixelHeight: (\d+)/, 1]&.to_f
|
|
14
|
+
if src_w && src_h && (target_width.to_f / src_w) <= (target_height.to_f / src_h)
|
|
15
|
+
args += ["--resampleWidth", target_width.to_i.to_s]
|
|
16
|
+
else
|
|
17
|
+
args += ["--resampleHeight", target_height.to_i.to_s]
|
|
18
|
+
end
|
|
14
19
|
else
|
|
15
|
-
|
|
16
|
-
args
|
|
20
|
+
args += ["--resampleWidth", target_width.to_i.to_s] if target_width
|
|
21
|
+
args += ["--resampleHeight", target_height.to_i.to_s] if target_height
|
|
17
22
|
end
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
result = `#{args.join(" ")}`
|
|
24
|
-
|
|
25
|
-
puts "sips command result: #{result}"
|
|
26
|
-
|
|
27
|
-
unless target_file
|
|
28
|
-
begin
|
|
29
|
-
return File.open(tmp_file.path, 'rb', &:read)
|
|
30
|
-
ensure
|
|
31
|
-
tmp_file.unlink
|
|
32
|
-
end
|
|
24
|
+
if target_file
|
|
25
|
+
_, status = Open3.capture2(*args, "-o", target_file.to_s, source_file.to_s)
|
|
26
|
+
raise "sips failed (exit #{status.exitstatus}) for #{source_file}" unless status.success?
|
|
27
|
+
return nil
|
|
33
28
|
end
|
|
34
29
|
|
|
35
|
-
|
|
30
|
+
tmp = Tempfile.new(["result", File.extname(source_file)])
|
|
31
|
+
tmp_path = tmp.path || raise("tempfile has no path")
|
|
32
|
+
begin
|
|
33
|
+
_, status = Open3.capture2(*args, "-o", tmp_path, source_file.to_s)
|
|
34
|
+
raise "sips failed (exit #{status.exitstatus}) for #{source_file}" unless status.success?
|
|
35
|
+
File.binread(tmp_path)
|
|
36
|
+
ensure
|
|
37
|
+
tmp.close
|
|
38
|
+
tmp.unlink
|
|
39
|
+
end
|
|
36
40
|
end
|
|
37
41
|
end
|
|
@@ -11,8 +11,6 @@ class RackResize::Processors::Vips
|
|
|
11
11
|
image = image.resize_to_limit(target_width, target_height) if target_width || target_height
|
|
12
12
|
image = image.saver(quality: RackResize.config.default_quality)
|
|
13
13
|
|
|
14
|
-
# image.call(destination: target_file)
|
|
15
|
-
|
|
16
14
|
if target_file
|
|
17
15
|
image.call(destination: target_file)
|
|
18
16
|
else
|
data/lib/rack_resize/rack_app.rb
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
1
|
require 'rack'
|
|
4
2
|
|
|
5
3
|
class RackResize::RackApp
|
|
@@ -20,33 +18,38 @@ class RackResize::RackApp
|
|
|
20
18
|
request = Rack::Request.new(env)
|
|
21
19
|
fullpath = request.path_info
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# process string like this
|
|
28
|
-
# /cdn-cgi/image/width=426,format=auto/assets/templates/vancouver-27c47f55.jpg
|
|
21
|
+
RackResize::InputParsers::Cloudflare.parse_input(fullpath, cf_path_prefix: @cf_path_prefix) =>
|
|
22
|
+
{route_matched:, req_params:, asset_path:}
|
|
29
23
|
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
return @app.call(env) unless route_matched
|
|
25
|
+
return error_resp("can't parse file path") unless asset_path
|
|
32
26
|
|
|
33
|
-
return error_resp("
|
|
27
|
+
return error_resp("no assets folders configured") if config.assets_folders.nil? || config.assets_folders.empty?
|
|
34
28
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
29
|
+
has_matched = false
|
|
30
|
+
asset_file = nil
|
|
31
|
+
config.assets_folders.each do |prefix, folder|
|
|
32
|
+
if asset_path.start_with?(prefix)
|
|
33
|
+
asset_file = folder.join(asset_path.delete_prefix(prefix + (prefix.end_with?("/") ? "" : "/")))
|
|
34
|
+
if asset_file.expand_path.to_s.start_with?(folder.to_s)
|
|
35
|
+
has_matched = true
|
|
36
|
+
end
|
|
37
|
+
break
|
|
38
|
+
end
|
|
42
39
|
end
|
|
43
40
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
if asset_path.include?("..")
|
|
42
|
+
@processing.logger.info("RackResize::RackApp - File path has invalid byte sequence #{asset_path}")
|
|
43
|
+
return error_resp(".. is not allowed in image path")
|
|
44
|
+
end
|
|
45
|
+
unless has_matched
|
|
46
|
+
@processing.logger.info("RackResize::RackApp - requested file #{asset_path} not match any of configured assets folder #{config.assets_folders.keys}")
|
|
47
|
+
return error_resp("invalid file path")
|
|
48
|
+
end
|
|
49
|
+
unless asset_file.exist?
|
|
50
|
+
@processing.logger.info("RackResize::RackApp - File path fond #{asset_path} => #{asset_file}")
|
|
51
|
+
return error_resp("file not exists on a server")
|
|
52
|
+
end
|
|
50
53
|
|
|
51
54
|
file_content = @processing.process!(source_file: asset_file, req_params:)
|
|
52
55
|
return send_file(asset_file:, file_content:)
|
data/lib/rack_resize.rb
CHANGED
|
@@ -7,10 +7,14 @@ module RackResize
|
|
|
7
7
|
module Processors
|
|
8
8
|
autoload :Sips, "#{__dir__}/rack_resize/processors/sips"
|
|
9
9
|
autoload :Vips, "#{__dir__}/rack_resize/processors/vips"
|
|
10
|
-
autoload :
|
|
10
|
+
autoload :MiniMagick, "#{__dir__}/rack_resize/processors/mini_magick"
|
|
11
11
|
autoload :Imlib2, "#{__dir__}/rack_resize/processors/imlib2"
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
module InputParsers
|
|
15
|
+
autoload :Cloudflare, "#{__dir__}/rack_resize/input_parsers/cloudflare"
|
|
16
|
+
end
|
|
17
|
+
|
|
14
18
|
class << self
|
|
15
19
|
def configuration
|
|
16
20
|
@configuration ||= Configuration.new
|
data/rack_resize.gemspec
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Gem::Specification.new do |s|
|
|
2
2
|
s.name = "rack_resize"
|
|
3
|
-
s.version = "0.1.
|
|
3
|
+
s.version = "0.1.2"
|
|
4
4
|
s.author = ["Pavel Evstigneev"]
|
|
5
5
|
s.email = ["pavel.evst@gmail.com"]
|
|
6
6
|
s.homepage = "https://github.com/paxa/rack_resize"
|
|
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
|
8
8
|
s.license = 'MIT'
|
|
9
9
|
s.required_ruby_version = ['>= 3.0']
|
|
10
10
|
|
|
11
|
-
s.files = `git ls-files`.split("\n")
|
|
11
|
+
s.files = `git ls-files`.split("\n").delete_if{|f| f.start_with?('samples', 'test') }
|
|
12
12
|
s.test_files = []
|
|
13
13
|
|
|
14
14
|
s.require_paths = ["lib"]
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rack_resize
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Pavel Evstigneev
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: rack
|
|
@@ -37,6 +37,7 @@ extra_rdoc_files: []
|
|
|
37
37
|
files:
|
|
38
38
|
- ".github/workflows/test.yml"
|
|
39
39
|
- ".gitignore"
|
|
40
|
+
- ".ruby-version"
|
|
40
41
|
- Gemfile
|
|
41
42
|
- README.md
|
|
42
43
|
- Rakefile
|
|
@@ -52,13 +53,6 @@ files:
|
|
|
52
53
|
- lib/rack_resize/rack_app.rb
|
|
53
54
|
- lib/rack_resize/rails_autoload.rb
|
|
54
55
|
- rack_resize.gemspec
|
|
55
|
-
- samples/image_1.jpeg
|
|
56
|
-
- samples/image_2.jpeg
|
|
57
|
-
- samples/image_3.jpeg
|
|
58
|
-
- samples/image_4.jpeg
|
|
59
|
-
- samples/index.html
|
|
60
|
-
- test/rack_app_test.rb
|
|
61
|
-
- test/test_helper.rb
|
|
62
56
|
homepage: https://github.com/paxa/rack_resize
|
|
63
57
|
licenses:
|
|
64
58
|
- MIT
|
|
@@ -77,7 +71,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
77
71
|
- !ruby/object:Gem::Version
|
|
78
72
|
version: '0'
|
|
79
73
|
requirements: []
|
|
80
|
-
rubygems_version:
|
|
74
|
+
rubygems_version: 4.0.10
|
|
81
75
|
specification_version: 4
|
|
82
76
|
summary: Image resizing on a fly
|
|
83
77
|
test_files: []
|
data/samples/image_1.jpeg
DELETED
|
Binary file
|
data/samples/image_2.jpeg
DELETED
|
Binary file
|
data/samples/image_3.jpeg
DELETED
|
Binary file
|
data/samples/image_4.jpeg
DELETED
|
Binary file
|
data/samples/index.html
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
|
|
3
|
-
<p>
|
|
4
|
-
height 150: <br>
|
|
5
|
-
<img src="/cdn-cgi/image/height=150/samples/image_1.jpeg"/>
|
|
6
|
-
<img src="/cdn-cgi/image/height=150/samples/image_2.jpeg"/>
|
|
7
|
-
<img src="/cdn-cgi/image/height=150/samples/image_3.jpeg"/>
|
|
8
|
-
<img src="/cdn-cgi/image/height=150/samples/image_4.jpeg"/>
|
|
9
|
-
</p>
|
|
10
|
-
|
|
11
|
-
<p>
|
|
12
|
-
width 150: <br>
|
|
13
|
-
<img src="/cdn-cgi/image/width=150/samples/image_1.jpeg"/>
|
|
14
|
-
<img src="/cdn-cgi/image/width=150/samples/image_2.jpeg"/>
|
|
15
|
-
<img src="/cdn-cgi/image/width=150/samples/image_3.jpeg"/>
|
|
16
|
-
<img src="/cdn-cgi/image/width=150/samples/image_4.jpeg"/>
|
|
17
|
-
</p>
|
|
18
|
-
|
|
19
|
-
<p>
|
|
20
|
-
width 50: <br>
|
|
21
|
-
<img src="/cdn-cgi/image/width=50/samples/image_1.jpeg"/>
|
|
22
|
-
<img src="/cdn-cgi/image/width=50/samples/image_2.jpeg"/>
|
|
23
|
-
<img src="/cdn-cgi/image/width=50/samples/image_3.jpeg"/>
|
|
24
|
-
<img src="/cdn-cgi/image/width=50/samples/image_4.jpeg"/>
|
|
25
|
-
</p>
|
|
26
|
-
|
|
27
|
-
<p>
|
|
28
|
-
originals: <br>
|
|
29
|
-
<img src="image_1.jpeg"/>
|
|
30
|
-
<img src="image_2.jpeg"/>
|
|
31
|
-
<img src="image_3.jpeg"/>
|
|
32
|
-
<img src="image_4.jpeg"/>
|
|
33
|
-
</p>
|
|
34
|
-
|
data/test/rack_app_test.rb
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'test_helper'
|
|
4
|
-
|
|
5
|
-
class RackAppTest < Minitest::Test
|
|
6
|
-
UPSTREAM = ->(env) { [200, { 'content-type' => 'text/plain' }, ['upstream']] }
|
|
7
|
-
|
|
8
|
-
def setup
|
|
9
|
-
@tmpdir = Dir.mktmpdir('rack_resize_test')
|
|
10
|
-
File.write(File.join(@tmpdir, 'photo.jpg'), 'fake jpeg content')
|
|
11
|
-
|
|
12
|
-
@app = RackResize::RackApp.new(
|
|
13
|
-
UPSTREAM,
|
|
14
|
-
assets_folder: @tmpdir,
|
|
15
|
-
processor: :sips,
|
|
16
|
-
save_resized: false
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
fake_processing = Object.new
|
|
20
|
-
def fake_processing.process!(**) = StringIO.new('processed image data')
|
|
21
|
-
@app.instance_variable_set(:@processing, fake_processing)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def teardown
|
|
25
|
-
FileUtils.rm_rf(@tmpdir)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# --- error_resp ---
|
|
29
|
-
|
|
30
|
-
def test_error_resp_default_status
|
|
31
|
-
status, headers, body = @app.error_resp('oops')
|
|
32
|
-
assert_equal 404, status
|
|
33
|
-
assert_equal({}, headers)
|
|
34
|
-
assert_equal ['oops'], body
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def test_error_resp_custom_status
|
|
38
|
-
status, _, body = @app.error_resp('bad input', http_code: 422)
|
|
39
|
-
assert_equal 422, status
|
|
40
|
-
assert_equal ['bad input'], body
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# --- send_file ---
|
|
44
|
-
|
|
45
|
-
def test_send_file_returns_200_with_headers
|
|
46
|
-
asset_file = Pathname.new(File.join(@tmpdir, 'photo.jpg'))
|
|
47
|
-
content = StringIO.new('hello')
|
|
48
|
-
status, headers, _ = @app.send_file(asset_file:, file_content: content)
|
|
49
|
-
|
|
50
|
-
assert_equal 200, status
|
|
51
|
-
assert_equal 'image/jpeg', headers['content-type']
|
|
52
|
-
assert_equal '5', headers['content-length']
|
|
53
|
-
assert_equal 'inline', headers['content-disposition']
|
|
54
|
-
assert_match(/\d+/, headers['cache-control'])
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# --- pass-through for non-cdn-cgi paths ---
|
|
58
|
-
|
|
59
|
-
def test_passes_through_unrelated_paths
|
|
60
|
-
env = Rack::MockRequest.env_for('/foo/bar.jpg')
|
|
61
|
-
status, _, body = @app.call(env)
|
|
62
|
-
assert_equal 200, status
|
|
63
|
-
assert_equal ['upstream'], body
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def test_passes_through_root_path
|
|
67
|
-
env = Rack::MockRequest.env_for('/')
|
|
68
|
-
_, _, body = @app.call(env)
|
|
69
|
-
assert_equal ['upstream'], body
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# --- path parsing errors ---
|
|
73
|
-
|
|
74
|
-
def test_returns_404_for_unparseable_path
|
|
75
|
-
env = Rack::MockRequest.env_for('/cdn-cgi/image/bad-path-no-extension')
|
|
76
|
-
status, _, body = @app.call(env)
|
|
77
|
-
assert_equal 404, status
|
|
78
|
-
assert_equal ["can't parse file path"], body
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def test_returns_404_for_path_traversal
|
|
82
|
-
env = Rack::MockRequest.env_for('/cdn-cgi/image/width=100/assets/../etc/photo.jpg')
|
|
83
|
-
status, _, body = @app.call(env)
|
|
84
|
-
assert_equal 404, status
|
|
85
|
-
assert_equal ['.. is not allowed in image path'], body
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def test_returns_404_for_missing_file
|
|
89
|
-
env = Rack::MockRequest.env_for('/cdn-cgi/image/width=100/assets/missing.jpg')
|
|
90
|
-
status, _, body = @app.call(env)
|
|
91
|
-
assert_equal 404, status
|
|
92
|
-
assert_equal ['file not exists on a server'], body
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
# --- successful processing ---
|
|
96
|
-
|
|
97
|
-
def test_returns_200_for_valid_request
|
|
98
|
-
env = Rack::MockRequest.env_for('/cdn-cgi/image/width=100/assets/photo.jpg')
|
|
99
|
-
status, headers, _ = @app.call(env)
|
|
100
|
-
assert_equal 200, status
|
|
101
|
-
assert_equal 'image/jpeg', headers['content-type']
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def test_valid_request_with_multiple_params
|
|
105
|
-
env = Rack::MockRequest.env_for('/cdn-cgi/image/width=200,format=auto,quality=80/assets/photo.jpg')
|
|
106
|
-
status, = @app.call(env)
|
|
107
|
-
assert_equal 200, status
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def test_response_body_is_processed_content
|
|
111
|
-
env = Rack::MockRequest.env_for('/cdn-cgi/image/width=100/assets/photo.jpg')
|
|
112
|
-
_, headers, body = @app.call(env)
|
|
113
|
-
assert_equal 'processed image data'.bytesize.to_s, headers['content-length']
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
# --- fingerprinted filenames (Rails asset digest) ---
|
|
117
|
-
|
|
118
|
-
def test_strips_digest_fingerprint_from_filename
|
|
119
|
-
File.write(File.join(@tmpdir, 'photo.jpg'), 'fake jpeg content')
|
|
120
|
-
env = Rack::MockRequest.env_for('/cdn-cgi/image/width=100/assets/photo-1a2b3c4d.jpg')
|
|
121
|
-
status, _, _ = @app.call(env)
|
|
122
|
-
assert_equal 200, status
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
# --- custom cf_path_prefix ---
|
|
126
|
-
|
|
127
|
-
def test_custom_cf_path_prefix_does_not_intercept_default_prefix
|
|
128
|
-
app = RackResize::RackApp.new(
|
|
129
|
-
UPSTREAM,
|
|
130
|
-
assets_folder: @tmpdir,
|
|
131
|
-
processor: :sips,
|
|
132
|
-
save_resized: false,
|
|
133
|
-
cf_path_prefix: '/img'
|
|
134
|
-
)
|
|
135
|
-
env = Rack::MockRequest.env_for('/cdn-cgi/image/width=100/assets/photo.jpg')
|
|
136
|
-
_, _, body = app.call(env)
|
|
137
|
-
assert_equal ['upstream'], body
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
# --- without upstream app ---
|
|
141
|
-
|
|
142
|
-
def test_initializes_without_upstream_app
|
|
143
|
-
app = RackResize::RackApp.new(assets_folder: @tmpdir, processor: :sips, save_resized: false)
|
|
144
|
-
assert_nil app.instance_variable_get(:@app)
|
|
145
|
-
end
|
|
146
|
-
end
|