httpimagestore 1.6.0 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -3
- data/Gemfile.lock +12 -16
- data/README.md +73 -0
- data/VERSION +1 -1
- data/bin/httpimagestore +7 -7
- data/features/data-uri.feature +55 -0
- data/features/error-reporting.feature +21 -3
- data/features/source-failover.feature +71 -0
- data/features/step_definitions/httpimagestore_steps.rb +27 -12
- data/features/storage.feature +26 -25
- data/features/support/tiny.png +0 -0
- data/features/xid-forwarding.feature +49 -0
- data/httpimagestore.gemspec +19 -23
- data/lib/httpimagestore/configuration/file.rb +6 -0
- data/lib/httpimagestore/configuration/handler.rb +4 -1
- data/lib/httpimagestore/configuration/identify.rb +2 -2
- data/lib/httpimagestore/configuration/output.rb +20 -1
- data/lib/httpimagestore/configuration/s3.rb +15 -9
- data/lib/httpimagestore/configuration/source_failover.rb +51 -0
- data/lib/httpimagestore/configuration/thumbnailer.rb +7 -7
- data/lib/httpimagestore/error_reporter.rb +9 -1
- data/lib/httpimagestore/ruby_string_template.rb +12 -7
- data/load_test/load_test.jmx +50 -77
- data/load_test/thumbnail_specs_v2.csv +10 -0
- data/spec/configuration_file_spec.rb +27 -2
- data/spec/configuration_identify_spec.rb +25 -2
- data/spec/configuration_s3_spec.rb +29 -3
- data/spec/configuration_source_failover_spec.rb +101 -0
- data/spec/configuration_thumbnailer_spec.rb +63 -8
- data/spec/ruby_string_template_spec.rb +4 -0
- data/spec/support/full.cfg +167 -33
- metadata +19 -23
- data/.idea/.name +0 -1
- data/.idea/.rakeTasks +0 -7
- data/.idea/codeStyleSettings.xml +0 -13
- data/.idea/dictionaries/wcc.xml +0 -8
- data/.idea/encodings.xml +0 -5
- data/.idea/httpimagestore.iml +0 -69
- data/.idea/jenkinsSettings.xml +0 -9
- data/.idea/misc.xml +0 -5
- data/.idea/modules.xml +0 -9
- data/.idea/scopes/scope_settings.xml +0 -5
- data/.idea/vcs.xml +0 -7
data/httpimagestore.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "httpimagestore"
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.7.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jakub Pastuszek"]
|
12
|
-
s.date = "
|
12
|
+
s.date = "2014-07-28"
|
13
13
|
s.description = "Thumbnails images using httpthumbnailer and stored data on HTTP server (S3)"
|
14
14
|
s.email = "jpastuszek@gmail.com"
|
15
15
|
s.executables = ["httpimagestore"]
|
@@ -19,17 +19,6 @@ Gem::Specification.new do |s|
|
|
19
19
|
]
|
20
20
|
s.files = [
|
21
21
|
".document",
|
22
|
-
".idea/.name",
|
23
|
-
".idea/.rakeTasks",
|
24
|
-
".idea/codeStyleSettings.xml",
|
25
|
-
".idea/dictionaries/wcc.xml",
|
26
|
-
".idea/encodings.xml",
|
27
|
-
".idea/httpimagestore.iml",
|
28
|
-
".idea/jenkinsSettings.xml",
|
29
|
-
".idea/misc.xml",
|
30
|
-
".idea/modules.xml",
|
31
|
-
".idea/scopes/scope_settings.xml",
|
32
|
-
".idea/vcs.xml",
|
33
22
|
".rspec",
|
34
23
|
"Gemfile",
|
35
24
|
"Gemfile.lock",
|
@@ -40,11 +29,13 @@ Gem::Specification.new do |s|
|
|
40
29
|
"bin/httpimagestore",
|
41
30
|
"features/cache-control.feature",
|
42
31
|
"features/compatibility.feature",
|
32
|
+
"features/data-uri.feature",
|
43
33
|
"features/error-reporting.feature",
|
44
34
|
"features/flexi.feature",
|
45
35
|
"features/health-check.feature",
|
46
36
|
"features/request-matching.feature",
|
47
37
|
"features/s3-store-and-thumbnail.feature",
|
38
|
+
"features/source-failover.feature",
|
48
39
|
"features/step_definitions/httpimagestore_steps.rb",
|
49
40
|
"features/storage.feature",
|
50
41
|
"features/support/env.rb",
|
@@ -53,6 +44,8 @@ Gem::Specification.new do |s|
|
|
53
44
|
"features/support/test.jpg",
|
54
45
|
"features/support/test.png",
|
55
46
|
"features/support/test.txt",
|
47
|
+
"features/support/tiny.png",
|
48
|
+
"features/xid-forwarding.feature",
|
56
49
|
"httpimagestore.gemspec",
|
57
50
|
"lib/httpimagestore/aws_sdk_regions_hack.rb",
|
58
51
|
"lib/httpimagestore/configuration.rb",
|
@@ -62,6 +55,7 @@ Gem::Specification.new do |s|
|
|
62
55
|
"lib/httpimagestore/configuration/output.rb",
|
63
56
|
"lib/httpimagestore/configuration/path.rb",
|
64
57
|
"lib/httpimagestore/configuration/s3.rb",
|
58
|
+
"lib/httpimagestore/configuration/source_failover.rb",
|
65
59
|
"lib/httpimagestore/configuration/thumbnailer.rb",
|
66
60
|
"lib/httpimagestore/error_reporter.rb",
|
67
61
|
"lib/httpimagestore/ruby_string_template.rb",
|
@@ -69,12 +63,14 @@ Gem::Specification.new do |s|
|
|
69
63
|
"load_test/load_test.1k.ec9bde794.m1.small.csv",
|
70
64
|
"load_test/load_test.jmx",
|
71
65
|
"load_test/thumbnail_specs.csv",
|
66
|
+
"load_test/thumbnail_specs_v2.csv",
|
72
67
|
"spec/configuration_file_spec.rb",
|
73
68
|
"spec/configuration_handler_spec.rb",
|
74
69
|
"spec/configuration_identify_spec.rb",
|
75
70
|
"spec/configuration_output_spec.rb",
|
76
71
|
"spec/configuration_path_spec.rb",
|
77
72
|
"spec/configuration_s3_spec.rb",
|
73
|
+
"spec/configuration_source_failover_spec.rb",
|
78
74
|
"spec/configuration_spec.rb",
|
79
75
|
"spec/configuration_thumbnailer_spec.rb",
|
80
76
|
"spec/ruby_string_template_spec.rb",
|
@@ -86,15 +82,15 @@ Gem::Specification.new do |s|
|
|
86
82
|
s.homepage = "http://github.com/jpastuszek/httpimagestore"
|
87
83
|
s.licenses = ["MIT"]
|
88
84
|
s.require_paths = ["lib"]
|
89
|
-
s.rubygems_version = "1.8.
|
85
|
+
s.rubygems_version = "1.8.23"
|
90
86
|
s.summary = "HTTP based image storage and thumbnailer"
|
91
87
|
|
92
88
|
if s.respond_to? :specification_version then
|
93
89
|
s.specification_version = 3
|
94
90
|
|
95
91
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
96
|
-
s.add_runtime_dependency(%q<unicorn-cuba-base>, ["~> 1.
|
97
|
-
s.add_runtime_dependency(%q<httpthumbnailer-client>, ["~> 1.
|
92
|
+
s.add_runtime_dependency(%q<unicorn-cuba-base>, ["~> 1.2.0"])
|
93
|
+
s.add_runtime_dependency(%q<httpthumbnailer-client>, ["~> 1.2.0"])
|
98
94
|
s.add_runtime_dependency(%q<aws-sdk>, ["~> 1.10"])
|
99
95
|
s.add_runtime_dependency(%q<mime-types>, ["~> 1.17"])
|
100
96
|
s.add_runtime_dependency(%q<sdl4r>, ["~> 0.9"])
|
@@ -106,10 +102,10 @@ Gem::Specification.new do |s|
|
|
106
102
|
s.add_development_dependency(%q<rdoc>, ["~> 3.9"])
|
107
103
|
s.add_development_dependency(%q<daemon>, ["~> 1"])
|
108
104
|
s.add_development_dependency(%q<prawn>, ["= 0.8.4"])
|
109
|
-
s.add_development_dependency(%q<httpthumbnailer>, ["
|
105
|
+
s.add_development_dependency(%q<httpthumbnailer>, ["~> 1.2.0"])
|
110
106
|
else
|
111
|
-
s.add_dependency(%q<unicorn-cuba-base>, ["~> 1.
|
112
|
-
s.add_dependency(%q<httpthumbnailer-client>, ["~> 1.
|
107
|
+
s.add_dependency(%q<unicorn-cuba-base>, ["~> 1.2.0"])
|
108
|
+
s.add_dependency(%q<httpthumbnailer-client>, ["~> 1.2.0"])
|
113
109
|
s.add_dependency(%q<aws-sdk>, ["~> 1.10"])
|
114
110
|
s.add_dependency(%q<mime-types>, ["~> 1.17"])
|
115
111
|
s.add_dependency(%q<sdl4r>, ["~> 0.9"])
|
@@ -121,11 +117,11 @@ Gem::Specification.new do |s|
|
|
121
117
|
s.add_dependency(%q<rdoc>, ["~> 3.9"])
|
122
118
|
s.add_dependency(%q<daemon>, ["~> 1"])
|
123
119
|
s.add_dependency(%q<prawn>, ["= 0.8.4"])
|
124
|
-
s.add_dependency(%q<httpthumbnailer>, ["
|
120
|
+
s.add_dependency(%q<httpthumbnailer>, ["~> 1.2.0"])
|
125
121
|
end
|
126
122
|
else
|
127
|
-
s.add_dependency(%q<unicorn-cuba-base>, ["~> 1.
|
128
|
-
s.add_dependency(%q<httpthumbnailer-client>, ["~> 1.
|
123
|
+
s.add_dependency(%q<unicorn-cuba-base>, ["~> 1.2.0"])
|
124
|
+
s.add_dependency(%q<httpthumbnailer-client>, ["~> 1.2.0"])
|
129
125
|
s.add_dependency(%q<aws-sdk>, ["~> 1.10"])
|
130
126
|
s.add_dependency(%q<mime-types>, ["~> 1.17"])
|
131
127
|
s.add_dependency(%q<sdl4r>, ["~> 0.9"])
|
@@ -137,7 +133,7 @@ Gem::Specification.new do |s|
|
|
137
133
|
s.add_dependency(%q<rdoc>, ["~> 3.9"])
|
138
134
|
s.add_dependency(%q<daemon>, ["~> 1"])
|
139
135
|
s.add_dependency(%q<prawn>, ["= 0.8.4"])
|
140
|
-
s.add_dependency(%q<httpthumbnailer>, ["
|
136
|
+
s.add_dependency(%q<httpthumbnailer>, ["~> 1.2.0"])
|
141
137
|
end
|
142
138
|
end
|
143
139
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'httpimagestore/configuration/path'
|
2
2
|
require 'httpimagestore/configuration/handler'
|
3
|
+
require 'httpimagestore/configuration/source_failover'
|
3
4
|
require 'pathname'
|
4
5
|
require 'uri'
|
5
6
|
|
@@ -54,6 +55,10 @@ module Configuration
|
|
54
55
|
|
55
56
|
storage_path
|
56
57
|
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
"FileSource[image_name: '#{@image_name}' root_dir: '#{@root_dir}' path_spec: '#{@path_spec}']"
|
61
|
+
end
|
57
62
|
end
|
58
63
|
|
59
64
|
class FileSource < FileSourceStoreBase
|
@@ -90,6 +95,7 @@ module Configuration
|
|
90
95
|
end
|
91
96
|
end
|
92
97
|
Handler::register_node_parser FileSource
|
98
|
+
SourceFailover::register_node_parser FileSource
|
93
99
|
|
94
100
|
class FileStore < FileSourceStoreBase
|
95
101
|
include ClassLogging
|
@@ -60,7 +60,7 @@ module Configuration
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
-
def initialize(body = '', matches = {}, path = '', query_string = {}, memory_limit = MemoryLimit.new)
|
63
|
+
def initialize(body = '', matches = {}, path = '', query_string = {}, memory_limit = MemoryLimit.new, headers = {})
|
64
64
|
super() do |request_state, name|
|
65
65
|
# note that request_state may be different object when useing with_locals that creates duplicate
|
66
66
|
request_state[name] = request_state.generate_meta_variable(name) or raise VariableNotDefinedError.new(name)
|
@@ -76,11 +76,14 @@ module Configuration
|
|
76
76
|
@images = Images.new(memory_limit)
|
77
77
|
@memory_limit = memory_limit
|
78
78
|
@output_callback = nil
|
79
|
+
|
80
|
+
@headers = headers
|
79
81
|
end
|
80
82
|
|
81
83
|
attr_reader :body
|
82
84
|
attr_reader :images
|
83
85
|
attr_reader :memory_limit
|
86
|
+
attr_reader :headers
|
84
87
|
|
85
88
|
def with_locals(locals)
|
86
89
|
log.debug "using additional local variables: #{locals}"
|
@@ -8,7 +8,7 @@ module Configuration
|
|
8
8
|
|
9
9
|
extend Stats
|
10
10
|
def_stats(
|
11
|
-
:total_identify_requests,
|
11
|
+
:total_identify_requests,
|
12
12
|
:total_identify_requests_bytes
|
13
13
|
)
|
14
14
|
|
@@ -42,7 +42,7 @@ module Configuration
|
|
42
42
|
Identify.stats.incr_total_identify_requests
|
43
43
|
Identify.stats.incr_total_identify_requests_bytes image.data.bytesize
|
44
44
|
|
45
|
-
id = client.identify(image.data)
|
45
|
+
id = client.with_headers(request_state.headers).identify(image.data)
|
46
46
|
|
47
47
|
image.mime_type = id.mime_type if id.mime_type
|
48
48
|
image.width = id.width if id.width
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'httpimagestore/configuration/handler'
|
2
2
|
require 'httpimagestore/ruby_string_template'
|
3
3
|
require 'uri'
|
4
|
+
require 'base64'
|
4
5
|
|
5
6
|
module Configuration
|
6
7
|
class StorePathNotSetForImage < ConfigurationError
|
@@ -131,7 +132,7 @@ module Configuration
|
|
131
132
|
configuration.output and raise StatementCollisionError.new(node, 'output')
|
132
133
|
image_name = node.grab_values('image name').first
|
133
134
|
cache_control = node.grab_attributes('cache-control').first
|
134
|
-
configuration.output =
|
135
|
+
configuration.output = self.new(image_name, cache_control)
|
135
136
|
end
|
136
137
|
|
137
138
|
def initialize(name, cache_control)
|
@@ -158,6 +159,24 @@ module Configuration
|
|
158
159
|
end
|
159
160
|
Handler::register_node_parser OutputImage
|
160
161
|
|
162
|
+
class OutputDataURIImage < OutputImage
|
163
|
+
def self.match(node)
|
164
|
+
node.name == 'output_data_uri_image'
|
165
|
+
end
|
166
|
+
|
167
|
+
def realize(request_state)
|
168
|
+
image = request_state.images[@name]
|
169
|
+
fail "image '#{@name}' needs to be identified first to be used in data URI output" unless image.mime_type
|
170
|
+
|
171
|
+
cache_control = @cache_control
|
172
|
+
request_state.output do
|
173
|
+
res['Cache-Control'] = cache_control if cache_control
|
174
|
+
write 200, 'text/uri-list', "data:#{image.mime_type};base64,#{Base64.strict_encode64(image.data)}"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
Handler::register_node_parser OutputDataURIImage
|
179
|
+
|
161
180
|
class OutputStorePath < OutputMultiBase
|
162
181
|
def self.match(node)
|
163
182
|
node.name == 'output_store_path'
|
@@ -4,6 +4,7 @@ require 'msgpack'
|
|
4
4
|
require 'httpimagestore/aws_sdk_regions_hack'
|
5
5
|
require 'httpimagestore/configuration/path'
|
6
6
|
require 'httpimagestore/configuration/handler'
|
7
|
+
require 'httpimagestore/configuration/source_failover'
|
7
8
|
|
8
9
|
module Configuration
|
9
10
|
class S3NotConfiguredError < ConfigurationError
|
@@ -43,7 +44,7 @@ module Configuration
|
|
43
44
|
node.grab_values
|
44
45
|
node.required_attributes('key', 'secret')
|
45
46
|
node.valid_attribute_values('ssl', true, false, nil)
|
46
|
-
|
47
|
+
|
47
48
|
key, secret, ssl = node.grab_attributes('key', 'secret', 'ssl')
|
48
49
|
ssl = true if ssl.nil?
|
49
50
|
|
@@ -191,7 +192,7 @@ module Configuration
|
|
191
192
|
class CacheObject < S3Object
|
192
193
|
extend Stats
|
193
194
|
def_stats(
|
194
|
-
:total_s3_cache_hits,
|
195
|
+
:total_s3_cache_hits,
|
195
196
|
:total_s3_cache_misses,
|
196
197
|
:total_s3_cache_errors,
|
197
198
|
)
|
@@ -274,7 +275,7 @@ module Configuration
|
|
274
275
|
|
275
276
|
extend Stats
|
276
277
|
def_stats(
|
277
|
-
:total_s3_store,
|
278
|
+
:total_s3_store,
|
278
279
|
:total_s3_store_bytes,
|
279
280
|
:total_s3_source,
|
280
281
|
:total_s3_source_bytes
|
@@ -286,18 +287,18 @@ module Configuration
|
|
286
287
|
node.required_attributes('bucket', 'path')
|
287
288
|
node.valid_attribute_values('public_access', true, false, nil)
|
288
289
|
|
289
|
-
bucket, path_spec, public_access, cache_control, prefix, cache_root, if_image_name_on =
|
290
|
+
bucket, path_spec, public_access, cache_control, prefix, cache_root, if_image_name_on =
|
290
291
|
*node.grab_attributes('bucket', 'path', 'public', 'cache-control', 'prefix', 'cache-root', 'if-image-name-on')
|
291
292
|
public_access = false if public_access.nil?
|
292
293
|
prefix = '' if prefix.nil?
|
293
294
|
|
294
295
|
self.new(
|
295
|
-
configuration.global,
|
296
|
-
image_name,
|
296
|
+
configuration.global,
|
297
|
+
image_name,
|
297
298
|
InclusionMatcher.new(image_name, if_image_name_on),
|
298
|
-
bucket,
|
299
|
-
path_spec,
|
300
|
-
public_access,
|
299
|
+
bucket,
|
300
|
+
path_spec,
|
301
|
+
public_access,
|
301
302
|
cache_control,
|
302
303
|
prefix,
|
303
304
|
cache_root
|
@@ -395,8 +396,13 @@ module Configuration
|
|
395
396
|
end
|
396
397
|
end
|
397
398
|
end
|
399
|
+
|
400
|
+
def to_s
|
401
|
+
"S3Source[image_name: '#{@image_name}' bucket: '#{@bucket}' prefix: '#{@prefix}' path_spec: '#{@path_spec}']"
|
402
|
+
end
|
398
403
|
end
|
399
404
|
Handler::register_node_parser S3Source
|
405
|
+
SourceFailover::register_node_parser S3Source
|
400
406
|
|
401
407
|
class S3Store < S3SourceStoreBase
|
402
408
|
def self.match(node)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'httpimagestore/configuration/handler'
|
2
|
+
|
3
|
+
module Configuration
|
4
|
+
class SourceFailoverAllFailedError < ConfigurationError
|
5
|
+
attr_reader :sources, :errors
|
6
|
+
|
7
|
+
def initialize(sources, errors)
|
8
|
+
@sources = sources
|
9
|
+
@errors = errors
|
10
|
+
super "all sources failed: #{sources.zip(errors).map{|s, e| "#{s}(#{e.class.name}: #{e.message})"}.join(', ')}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class SourceFailover < Scope
|
15
|
+
include ClassLogging
|
16
|
+
|
17
|
+
def self.match(node)
|
18
|
+
node.name == 'source_failover'
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.parse(configuration, node)
|
22
|
+
# support only sources
|
23
|
+
handler_configuration = Struct.new(
|
24
|
+
:global,
|
25
|
+
:sources
|
26
|
+
).new
|
27
|
+
handler_configuration.global = configuration.global
|
28
|
+
handler_configuration.sources = []
|
29
|
+
|
30
|
+
failover = self.new(handler_configuration)
|
31
|
+
configuration.sources << failover
|
32
|
+
failover.parse(node)
|
33
|
+
end
|
34
|
+
|
35
|
+
def realize(request_state)
|
36
|
+
errors = []
|
37
|
+
@configuration.sources.each do |source|
|
38
|
+
begin
|
39
|
+
log.debug "trying source: #{source}"
|
40
|
+
return source.realize(request_state) unless source.respond_to? :excluded? and source.excluded?(request_state)
|
41
|
+
rescue => error
|
42
|
+
errors << error
|
43
|
+
log.warn "source #{source} failed; trying next source", error
|
44
|
+
end
|
45
|
+
end
|
46
|
+
log.error "all sources: #{@configuration.sources.map(&:to_s).join(', ')} failed; giving up"
|
47
|
+
raise SourceFailoverAllFailedError.new(@configuration.sources.to_a, errors)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
Handler::register_node_parser SourceFailover
|
51
|
+
end
|
@@ -36,7 +36,7 @@ module Configuration
|
|
36
36
|
|
37
37
|
extend Stats
|
38
38
|
def_stats(
|
39
|
-
:total_thumbnail_requests,
|
39
|
+
:total_thumbnail_requests,
|
40
40
|
:total_thumbnail_requests_bytes,
|
41
41
|
:total_thumbnail_thumbnails,
|
42
42
|
:total_thumbnail_thumbnails_bytes
|
@@ -134,9 +134,9 @@ module Configuration
|
|
134
134
|
matcher = InclusionMatcher.new(source_image_name, node.grab_attributes('if-image-name-on').first) if use_multipart_api
|
135
135
|
|
136
136
|
configuration.processors << self.new(
|
137
|
-
configuration.global,
|
138
|
-
source_image_name,
|
139
|
-
specs,
|
137
|
+
configuration.global,
|
138
|
+
source_image_name,
|
139
|
+
specs,
|
140
140
|
use_multipart_api,
|
141
141
|
matcher
|
142
142
|
)
|
@@ -177,7 +177,7 @@ module Configuration
|
|
177
177
|
logger = log
|
178
178
|
|
179
179
|
begin
|
180
|
-
thumbnails = client.thumbnail(source_image.data) do
|
180
|
+
thumbnails = client.with_headers(request_state.headers).thumbnail(source_image.data) do
|
181
181
|
rendered_specs.each_pair do |name, spec|
|
182
182
|
begin
|
183
183
|
thumbnail(*spec)
|
@@ -202,7 +202,7 @@ module Configuration
|
|
202
202
|
if thumbnail.kind_of? HTTPThumbnailerClient::HTTPThumbnailerClientError
|
203
203
|
error = thumbnail
|
204
204
|
log.warn 'got single thumbnail error', error
|
205
|
-
raise ThumbnailingError.new(@source_image_name, name, error)
|
205
|
+
raise ThumbnailingError.new(@source_image_name, name, error)
|
206
206
|
end
|
207
207
|
end
|
208
208
|
|
@@ -215,7 +215,7 @@ module Configuration
|
|
215
215
|
log.info "thumbnailing '#{@source_image_name}' to '#{name}' with spec: #{rendered_spec}"
|
216
216
|
|
217
217
|
begin
|
218
|
-
thumbnail = client.thumbnail(source_image.data, *rendered_spec)
|
218
|
+
thumbnail = client.with_headers(request_state.headers).thumbnail(source_image.data, *rendered_spec)
|
219
219
|
request_state.memory_limit.borrow(thumbnail.data.bytesize, "thumbnail '#{name}'")
|
220
220
|
|
221
221
|
input_mime_type = thumbnail.input_mime_type
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class ErrorReporter <
|
1
|
+
class ErrorReporter < Controller
|
2
2
|
self.define do
|
3
3
|
on error(
|
4
4
|
Configuration::S3NoSuchKeyError,
|
@@ -20,6 +20,14 @@ class ErrorReporter < Controler
|
|
20
20
|
write_error 400, error
|
21
21
|
end
|
22
22
|
|
23
|
+
on error Configuration::SourceFailoverAllFailedError do |error|
|
24
|
+
if [Configuration::S3NoSuchKeyError, Configuration::NoSuchFileError].member? error.errors.first.class
|
25
|
+
write_error 404, error
|
26
|
+
else
|
27
|
+
write_error 500, error
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
23
31
|
run DefaultErrorReporter
|
24
32
|
end
|
25
33
|
end
|
@@ -4,22 +4,27 @@ class RubyStringTemplate
|
|
4
4
|
super "no value for '\#{#{name}}' in template '#{template}'"
|
5
5
|
end
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
def initialize(template, &resolver)
|
9
9
|
@template = template.to_s
|
10
10
|
@resolver = resolver ? resolver : ->(locals, name){locals[name]}
|
11
11
|
end
|
12
12
|
|
13
13
|
def render(locals = {})
|
14
|
-
template = @template
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
template = @template.dup
|
15
|
+
values = {}
|
16
|
+
|
17
|
+
template.scan(/#\{[^\}]+\}/um).uniq.each do |placeholder|
|
18
|
+
name = placeholder.match(/#\{([^\}]*)\}/u).captures.first.to_sym
|
18
19
|
value = @resolver.call(locals, name)
|
19
20
|
value or fail NoValueForTemplatePlaceholderError.new(name, @template)
|
20
|
-
|
21
|
-
template = template.gsub(tag, value)
|
21
|
+
values[placeholder] = value.to_s
|
22
22
|
end
|
23
|
+
|
24
|
+
values.each_pair do |placeholder, value|
|
25
|
+
template.gsub!(placeholder, value)
|
26
|
+
end
|
27
|
+
|
23
28
|
template
|
24
29
|
end
|
25
30
|
end
|