httpimagestore 1.4.1 → 1.5.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.
- data/.idea/.name +1 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/codeStyleSettings.xml +13 -0
- data/.idea/dictionaries/wcc.xml +8 -0
- data/.idea/encodings.xml +5 -0
- data/.idea/httpimagestore.iml +69 -0
- data/.idea/jenkinsSettings.xml +9 -0
- data/.idea/misc.xml +5 -0
- data/.idea/modules.xml +9 -0
- data/.idea/scopes/scope_settings.xml +5 -0
- data/.idea/vcs.xml +7 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +4 -4
- data/README.md +55 -33
- data/VERSION +1 -1
- data/bin/httpimagestore +19 -5
- data/features/cache-control.feature +8 -9
- data/features/compatibility.feature +46 -21
- data/features/error-reporting.feature +15 -16
- data/features/flexi.feature +4 -5
- data/features/health-check.feature +1 -2
- data/features/request-matching.feature +211 -0
- data/features/s3-store-and-thumbnail.feature +3 -10
- data/features/storage.feature +7 -9
- data/httpimagestore.gemspec +17 -5
- data/lib/httpimagestore/configuration/handler.rb +55 -30
- data/lib/httpimagestore/configuration/output.rb +51 -2
- data/spec/configuration_handler_spec.rb +4 -22
- data/spec/configuration_output_spec.rb +86 -2
- metadata +17 -5
data/features/storage.feature
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
Feature: Storing images under different names
|
|
2
2
|
Storage supports UUID and SHA digest based auto generated storage as well as user provided via request or static configuration string.
|
|
3
3
|
|
|
4
|
-
|
|
5
4
|
Background:
|
|
6
5
|
Given httpthumbnailer server is running at http://localhost:3100/health_check
|
|
7
6
|
Given httpimagestore server is running at http://localhost:3000/health_check with the following configuration
|
|
8
7
|
"""
|
|
9
|
-
path "input_digest"
|
|
10
|
-
path "input_sha256"
|
|
11
|
-
path "image_digest"
|
|
12
|
-
path "image_sha256"
|
|
13
|
-
path "uuid"
|
|
14
|
-
path "image_meta"
|
|
15
|
-
path "input_image_meta"
|
|
8
|
+
path "input_digest" "#{input_digest}"
|
|
9
|
+
path "input_sha256" "#{input_sha256}"
|
|
10
|
+
path "image_digest" "#{image_digest}"
|
|
11
|
+
path "image_sha256" "#{image_sha256}"
|
|
12
|
+
path "uuid" "#{uuid}"
|
|
13
|
+
path "image_meta" "#{image_width}x#{image_height}.#{image_mime_extension}"
|
|
14
|
+
path "input_image_meta" "#{input_image_width}x#{input_image_height}.#{input_image_mime_extension}"
|
|
16
15
|
|
|
17
16
|
post "images" "input_digest" {
|
|
18
17
|
thumbnail "input" "thumbnail" operation="crop" width="50" height="50"
|
|
@@ -196,4 +195,3 @@ Feature: Storing images under different names
|
|
|
196
195
|
509x719.png
|
|
197
196
|
"""
|
|
198
197
|
Then file /tmp/509x719.png will contain PNG image of size 50x100
|
|
199
|
-
|
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.5.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 = "2013-10-
|
|
12
|
+
s.date = "2013-10-22"
|
|
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,6 +19,17 @@ 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",
|
|
22
33
|
".rspec",
|
|
23
34
|
"Gemfile",
|
|
24
35
|
"Gemfile.lock",
|
|
@@ -32,6 +43,7 @@ Gem::Specification.new do |s|
|
|
|
32
43
|
"features/error-reporting.feature",
|
|
33
44
|
"features/flexi.feature",
|
|
34
45
|
"features/health-check.feature",
|
|
46
|
+
"features/request-matching.feature",
|
|
35
47
|
"features/s3-store-and-thumbnail.feature",
|
|
36
48
|
"features/step_definitions/httpimagestore_steps.rb",
|
|
37
49
|
"features/storage.feature",
|
|
@@ -81,7 +93,7 @@ Gem::Specification.new do |s|
|
|
|
81
93
|
s.specification_version = 3
|
|
82
94
|
|
|
83
95
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
|
84
|
-
s.add_runtime_dependency(%q<unicorn-cuba-base>, ["~> 1.1.
|
|
96
|
+
s.add_runtime_dependency(%q<unicorn-cuba-base>, ["~> 1.1.2"])
|
|
85
97
|
s.add_runtime_dependency(%q<httpthumbnailer-client>, ["~> 1.1.1"])
|
|
86
98
|
s.add_runtime_dependency(%q<aws-sdk>, ["~> 1.10"])
|
|
87
99
|
s.add_runtime_dependency(%q<mime-types>, ["~> 1.17"])
|
|
@@ -96,7 +108,7 @@ Gem::Specification.new do |s|
|
|
|
96
108
|
s.add_development_dependency(%q<prawn>, ["= 0.8.4"])
|
|
97
109
|
s.add_development_dependency(%q<httpthumbnailer>, [">= 0"])
|
|
98
110
|
else
|
|
99
|
-
s.add_dependency(%q<unicorn-cuba-base>, ["~> 1.1.
|
|
111
|
+
s.add_dependency(%q<unicorn-cuba-base>, ["~> 1.1.2"])
|
|
100
112
|
s.add_dependency(%q<httpthumbnailer-client>, ["~> 1.1.1"])
|
|
101
113
|
s.add_dependency(%q<aws-sdk>, ["~> 1.10"])
|
|
102
114
|
s.add_dependency(%q<mime-types>, ["~> 1.17"])
|
|
@@ -112,7 +124,7 @@ Gem::Specification.new do |s|
|
|
|
112
124
|
s.add_dependency(%q<httpthumbnailer>, [">= 0"])
|
|
113
125
|
end
|
|
114
126
|
else
|
|
115
|
-
s.add_dependency(%q<unicorn-cuba-base>, ["~> 1.1.
|
|
127
|
+
s.add_dependency(%q<unicorn-cuba-base>, ["~> 1.1.2"])
|
|
116
128
|
s.add_dependency(%q<httpthumbnailer-client>, ["~> 1.1.1"])
|
|
117
129
|
s.add_dependency(%q<aws-sdk>, ["~> 1.10"])
|
|
118
130
|
s.add_dependency(%q<mime-types>, ["~> 1.17"])
|
|
@@ -66,12 +66,11 @@ module Configuration
|
|
|
66
66
|
request_state[name] = request_state.generate_meta_variable(name) or raise VariableNotDefinedError.new(name)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
merge! query_string
|
|
70
69
|
self[:path] = path
|
|
71
70
|
merge! matches
|
|
72
71
|
self[:query_string_options] = query_string.sort.map{|kv| kv.join(':')}.join(',')
|
|
73
72
|
|
|
74
|
-
log.debug "processing request with body length: #{body.bytesize} bytes and variables: #{
|
|
73
|
+
log.debug "processing request with body length: #{body.bytesize} bytes and variables: #{map{|k,v| "#{k}: '#{v}'"}.join(', ')}"
|
|
75
74
|
|
|
76
75
|
@body = body
|
|
77
76
|
@images = Images.new(memory_limit)
|
|
@@ -177,14 +176,6 @@ module Configuration
|
|
|
177
176
|
end
|
|
178
177
|
end
|
|
179
178
|
|
|
180
|
-
class OutputOK
|
|
181
|
-
def realize(request_state)
|
|
182
|
-
request_state.output do
|
|
183
|
-
write_plain 200, 'OK'
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
|
|
188
179
|
class InclusionMatcher
|
|
189
180
|
def initialize(value, template)
|
|
190
181
|
@value = value
|
|
@@ -259,13 +250,28 @@ module Configuration
|
|
|
259
250
|
end
|
|
260
251
|
|
|
261
252
|
class Matcher
|
|
262
|
-
def initialize(
|
|
263
|
-
@
|
|
253
|
+
def initialize(names, debug_type = '', debug_value = '', &matcher)
|
|
254
|
+
@names = names
|
|
264
255
|
@matcher = matcher
|
|
256
|
+
@debug_type = debug_type
|
|
257
|
+
@debug_value = case debug_value
|
|
258
|
+
when Regexp
|
|
259
|
+
"/#{debug_value.source}/"
|
|
260
|
+
else
|
|
261
|
+
debug_value.inspect
|
|
262
|
+
end
|
|
265
263
|
end
|
|
266
264
|
|
|
267
|
-
attr_reader :
|
|
265
|
+
attr_reader :names
|
|
268
266
|
attr_reader :matcher
|
|
267
|
+
|
|
268
|
+
def to_s
|
|
269
|
+
if @names.empty?
|
|
270
|
+
"#{@debug_type}(#{@debug_value})"
|
|
271
|
+
else
|
|
272
|
+
"#{@debug_type}(#{@names.join(',')} => #{@debug_value})"
|
|
273
|
+
end
|
|
274
|
+
end
|
|
269
275
|
end
|
|
270
276
|
|
|
271
277
|
class Handler < Scope
|
|
@@ -280,7 +286,7 @@ module Configuration
|
|
|
280
286
|
end
|
|
281
287
|
|
|
282
288
|
def self.parse(configuration, node)
|
|
283
|
-
handler_configuration =
|
|
289
|
+
handler_configuration =
|
|
284
290
|
Struct.new(
|
|
285
291
|
:global,
|
|
286
292
|
:http_method,
|
|
@@ -295,45 +301,64 @@ module Configuration
|
|
|
295
301
|
handler_configuration.http_method = node.name
|
|
296
302
|
handler_configuration.uri_matchers = node.values.map do |matcher|
|
|
297
303
|
case matcher
|
|
298
|
-
# URI
|
|
304
|
+
# URI matchers
|
|
299
305
|
when %r{^:([^/]+)/(.*)/$} # :foobar/.*/
|
|
300
|
-
name = $1
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
306
|
+
name = $1.to_sym
|
|
307
|
+
_regexp = Regexp.new($2)
|
|
308
|
+
regexp = Regexp.new("(#{$2})")
|
|
309
|
+
Matcher.new([name], 'Regexp', _regexp) do
|
|
310
|
+
regexp
|
|
311
|
+
end
|
|
312
|
+
when %r{^/(.*)/$} # /.*/
|
|
313
|
+
regexp = $1
|
|
314
|
+
_regexp = Regexp.new($1)
|
|
315
|
+
names = Regexp.new($1).names.map{|n| n.to_sym}
|
|
316
|
+
Matcher.new(names, 'Regexp', _regexp) do
|
|
317
|
+
-> {
|
|
318
|
+
matchdata = env["PATH_INFO"].match(/\A\/(?<_match_>#{regexp})(?<_tail_>(?:\/|\z))/)
|
|
319
|
+
|
|
320
|
+
next false unless matchdata
|
|
321
|
+
|
|
322
|
+
path, *vars = matchdata.captures
|
|
323
|
+
|
|
324
|
+
env["SCRIPT_NAME"] += "/#{path}"
|
|
325
|
+
env["PATH_INFO"] = "#{vars.pop}#{matchdata.post_match}"
|
|
326
|
+
|
|
327
|
+
captures.push(*vars)
|
|
328
|
+
}
|
|
304
329
|
end
|
|
305
330
|
when /^:(.+)\?(.*)$/ # :foo?bar
|
|
306
331
|
name = $1.to_sym
|
|
307
332
|
default = $2
|
|
308
|
-
Matcher.new(name) do
|
|
333
|
+
Matcher.new([name], 'SegmentDefault', "<segment>|#{default}") do
|
|
309
334
|
->{match(name) || captures.push(default)}
|
|
310
335
|
end
|
|
311
336
|
when /^:(.+)$/ # :foobar
|
|
312
337
|
name = $1.to_sym
|
|
313
|
-
Matcher.new(name) do
|
|
338
|
+
Matcher.new([name], 'Segment', '<segment>') do
|
|
314
339
|
name
|
|
315
340
|
end
|
|
316
341
|
# Query string matchers
|
|
317
342
|
when /^\&([^=]+)=(.+)$/# ?foo=bar
|
|
318
|
-
name = $1
|
|
343
|
+
name = $1.to_sym
|
|
319
344
|
value = $2
|
|
320
|
-
Matcher.new(
|
|
321
|
-
->{req[name] && req[name] == value}
|
|
345
|
+
Matcher.new([name], 'QueryKeyValue', "#{name}=#{value}") do
|
|
346
|
+
->{req[name] && req[name] == value && captures.push(req[name])}
|
|
322
347
|
end
|
|
323
348
|
when /^\&:(.+)\?(.*)$/# &:foo?bar
|
|
324
|
-
name = $1
|
|
349
|
+
name = $1.to_sym
|
|
325
350
|
default = $2
|
|
326
|
-
Matcher.new(name
|
|
351
|
+
Matcher.new([name], 'QueryKeyDefault', "#{name}=<key>|#{default}") do
|
|
327
352
|
->{captures.push(req[name] || default)}
|
|
328
353
|
end
|
|
329
354
|
when /^\&:(.+)$/# &:foo
|
|
330
|
-
name = $1
|
|
331
|
-
Matcher.new(name
|
|
355
|
+
name = $1.to_sym
|
|
356
|
+
Matcher.new([name], 'QueryKey', "#{name}=<key>") do
|
|
332
357
|
->{req[name] && captures.push(req[name])}
|
|
333
358
|
end
|
|
334
|
-
#
|
|
359
|
+
# Literal URI segment matcher
|
|
335
360
|
else # foobar
|
|
336
|
-
Matcher.new(
|
|
361
|
+
Matcher.new([], "Literal", matcher) do
|
|
337
362
|
Regexp.escape(matcher)
|
|
338
363
|
end
|
|
339
364
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'httpimagestore/configuration/handler'
|
|
2
|
+
require 'httpimagestore/ruby_string_template'
|
|
2
3
|
|
|
3
4
|
module Configuration
|
|
4
5
|
class StorePathNotSetForImage < ConfigurationError
|
|
@@ -13,6 +14,53 @@ module Configuration
|
|
|
13
14
|
end
|
|
14
15
|
end
|
|
15
16
|
|
|
17
|
+
class OutputText
|
|
18
|
+
def self.match(node)
|
|
19
|
+
node.name == 'output_text'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.parse(configuration, node)
|
|
23
|
+
configuration.output and raise StatementCollisionError.new(node, 'output')
|
|
24
|
+
text = node.grab_values('text').first
|
|
25
|
+
status, cache_control = *node.grab_attributes('status', 'cache-control')
|
|
26
|
+
configuration.output = OutputText.new(text, status || 200, cache_control)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def initialize(text, status, cache_control)
|
|
30
|
+
@text = RubyStringTemplate.new(text || fail("no text?!"))
|
|
31
|
+
@status = status || 200
|
|
32
|
+
@cache_control = cache_control
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def realize(request_state)
|
|
36
|
+
# make sure variables are available in request context
|
|
37
|
+
status = @status
|
|
38
|
+
text = @text.render(request_state)
|
|
39
|
+
cache_control = @cache_control
|
|
40
|
+
request_state.output do
|
|
41
|
+
res['Cache-Control'] = cache_control if cache_control
|
|
42
|
+
write_plain status.to_i, text.to_s
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class OutputOK < OutputText
|
|
48
|
+
def self.match(node)
|
|
49
|
+
node.name == 'output_ok'
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.parse(configuration, node)
|
|
53
|
+
configuration.output and raise StatementCollisionError.new(node, 'output')
|
|
54
|
+
cache_control = node.grab_attributes('cache-control').first
|
|
55
|
+
configuration.output = OutputOK.new(cache_control)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def initialize(cache_control = nil)
|
|
59
|
+
super 'OK', 200, cache_control
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
Handler::register_node_parser OutputText
|
|
63
|
+
|
|
16
64
|
class OutputMultiBase
|
|
17
65
|
class ImageName < String
|
|
18
66
|
include ConditionalInclusion
|
|
@@ -39,7 +87,8 @@ module Configuration
|
|
|
39
87
|
@names = names
|
|
40
88
|
end
|
|
41
89
|
end
|
|
42
|
-
|
|
90
|
+
Handler::register_node_parser OutputOK
|
|
91
|
+
|
|
43
92
|
class OutputImage
|
|
44
93
|
include ClassLogging
|
|
45
94
|
|
|
@@ -61,7 +110,7 @@ module Configuration
|
|
|
61
110
|
|
|
62
111
|
def realize(request_state)
|
|
63
112
|
image = request_state.images[@name]
|
|
64
|
-
mime_type =
|
|
113
|
+
mime_type =
|
|
65
114
|
if image.mime_type
|
|
66
115
|
image.mime_type
|
|
67
116
|
else
|
|
@@ -28,10 +28,10 @@ describe Configuration do
|
|
|
28
28
|
subject.handlers.length.should == 3
|
|
29
29
|
|
|
30
30
|
subject.handlers[0].http_method.should == 'get'
|
|
31
|
-
subject.handlers[0].uri_matchers.map{|m| m.
|
|
31
|
+
subject.handlers[0].uri_matchers.map{|m| m.names}.flatten.should == [:operation, :width, :height, :options]
|
|
32
32
|
|
|
33
33
|
subject.handlers[1].http_method.should == 'put'
|
|
34
|
-
subject.handlers[1].uri_matchers.map{|m| m.
|
|
34
|
+
subject.handlers[1].uri_matchers.map{|m| m.names}.flatten.should == [:test]
|
|
35
35
|
|
|
36
36
|
subject.handlers[2].http_method.should == 'post'
|
|
37
37
|
subject.handlers[2].uri_matchers.should be_empty
|
|
@@ -62,11 +62,6 @@ describe Configuration do
|
|
|
62
62
|
subject[:path].should == '/hello/world.jpg'
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
-
it 'should provide query string params' do
|
|
66
|
-
subject[:width].should == '123'
|
|
67
|
-
subject[:height].should == '321'
|
|
68
|
-
end
|
|
69
|
-
|
|
70
65
|
it 'should provide matches' do
|
|
71
66
|
subject[:operation].should == 'pad'
|
|
72
67
|
end
|
|
@@ -149,7 +144,7 @@ describe Configuration do
|
|
|
149
144
|
subject[:input_digest]
|
|
150
145
|
}.to raise_error Configuration::NoRequestBodyToGenerateMetaVariableError, %q{need not empty request body to generate value for 'input_digest'}
|
|
151
146
|
end
|
|
152
|
-
|
|
147
|
+
|
|
153
148
|
it 'should raise ImageNotLoadedError when asking for image related variable of not loaded image' do
|
|
154
149
|
expect {
|
|
155
150
|
subject.with_locals(image_name: 'abc')[:image_mime_extension]
|
|
@@ -202,7 +197,7 @@ describe Configuration do
|
|
|
202
197
|
limit.borrow 1
|
|
203
198
|
request_state.images['test'] = Configuration::Image.new('x')
|
|
204
199
|
limit.limit.should == 1
|
|
205
|
-
|
|
200
|
+
|
|
206
201
|
limit.borrow 1
|
|
207
202
|
limit.limit.should == 0
|
|
208
203
|
request_state.images['test'] = Configuration::Image.new('x')
|
|
@@ -255,19 +250,6 @@ describe Configuration do
|
|
|
255
250
|
subject.handlers[1].output.should be_a Configuration::OutputOK
|
|
256
251
|
subject.handlers[2].output.should be_a Configuration::OutputOK
|
|
257
252
|
end
|
|
258
|
-
|
|
259
|
-
describe Configuration::OutputOK do
|
|
260
|
-
it 'should output 200 with OK text/plain message when realized' do
|
|
261
|
-
state = Configuration::RequestState.new('abc')
|
|
262
|
-
subject.handlers[2].output.realize(state)
|
|
263
|
-
|
|
264
|
-
env = CubaResponseEnv.new
|
|
265
|
-
env.instance_eval &state.output_callback
|
|
266
|
-
env.res.status.should == 200
|
|
267
|
-
env.res.data.should == "OK\r\n"
|
|
268
|
-
env.res['Content-Type'].should == 'text/plain'
|
|
269
|
-
end
|
|
270
|
-
end
|
|
271
253
|
end
|
|
272
254
|
end
|
|
273
255
|
end
|
|
@@ -17,6 +17,91 @@ describe Configuration do
|
|
|
17
17
|
CubaResponseEnv.new
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
describe Configuration::OutputText do
|
|
21
|
+
subject do
|
|
22
|
+
Configuration.read(<<-'EOF')
|
|
23
|
+
get "test" {
|
|
24
|
+
output_text "hello world"
|
|
25
|
+
}
|
|
26
|
+
get "test" {
|
|
27
|
+
output_text "bad stuff" status=500
|
|
28
|
+
}
|
|
29
|
+
get "test" {
|
|
30
|
+
output_text "welcome" cache-control="public"
|
|
31
|
+
}
|
|
32
|
+
get "test" {
|
|
33
|
+
output_text "test1: #{test1} test2: #{test2}"
|
|
34
|
+
}
|
|
35
|
+
EOF
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'should output hello world with default 200 status' do
|
|
39
|
+
subject.handlers[0].output.realize(state)
|
|
40
|
+
env = CubaResponseEnv.new
|
|
41
|
+
env.instance_eval &state.output_callback
|
|
42
|
+
env.res.status.should == 200
|
|
43
|
+
env.res.data.should == "hello world\r\n"
|
|
44
|
+
env.res['Content-Type'].should == 'text/plain'
|
|
45
|
+
env.res['Cache-Control'].should be_nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'should output bad stuff with 500 status' do
|
|
49
|
+
subject.handlers[1].output.realize(state)
|
|
50
|
+
env = CubaResponseEnv.new
|
|
51
|
+
env.instance_eval &state.output_callback
|
|
52
|
+
env.res.status.should == 500
|
|
53
|
+
env.res.data.should == "bad stuff\r\n"
|
|
54
|
+
env.res['Content-Type'].should == 'text/plain'
|
|
55
|
+
env.res['Cache-Control'].should be_nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'should output welcome with public cache control' do
|
|
59
|
+
subject.handlers[2].output.realize(state)
|
|
60
|
+
env = CubaResponseEnv.new
|
|
61
|
+
env.instance_eval &state.output_callback
|
|
62
|
+
env.res.status.should == 200
|
|
63
|
+
env.res.data.should == "welcome\r\n"
|
|
64
|
+
env.res['Content-Type'].should == 'text/plain'
|
|
65
|
+
env.res['Cache-Control'].should == 'public'
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it 'should output text interpolated with variable values' do
|
|
69
|
+
state = Configuration::RequestState.new
|
|
70
|
+
state[:test1] = 'abc'
|
|
71
|
+
state[:test2] = 'xyz'
|
|
72
|
+
|
|
73
|
+
subject.handlers[3].output.realize(state)
|
|
74
|
+
env = CubaResponseEnv.new
|
|
75
|
+
env.instance_eval &state.output_callback
|
|
76
|
+
env.res.data.should == "test1: abc test2: xyz\r\n"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe Configuration::OutputOK do
|
|
81
|
+
subject do
|
|
82
|
+
Configuration.read(<<-EOF)
|
|
83
|
+
put "test" {
|
|
84
|
+
output_ok
|
|
85
|
+
}
|
|
86
|
+
EOF
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
before :each do
|
|
90
|
+
subject.handlers[0].sources[0].realize(state)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'should output 200 with OK text/plain message when realized' do
|
|
94
|
+
state = Configuration::RequestState.new('abc')
|
|
95
|
+
subject.handlers[0].output.realize(state)
|
|
96
|
+
|
|
97
|
+
env = CubaResponseEnv.new
|
|
98
|
+
env.instance_eval &state.output_callback
|
|
99
|
+
env.res.status.should == 200
|
|
100
|
+
env.res.data.should == "OK\r\n"
|
|
101
|
+
env.res['Content-Type'].should == 'text/plain'
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
20
105
|
describe Configuration::OutputImage do
|
|
21
106
|
subject do
|
|
22
107
|
Configuration.read(<<-EOF)
|
|
@@ -270,7 +355,7 @@ describe Configuration do
|
|
|
270
355
|
env.res['Content-Type'].should == 'text/uri-list'
|
|
271
356
|
env.res.data.should == "file://test.out\r\nfile://test.out2\r\n"
|
|
272
357
|
end
|
|
273
|
-
|
|
358
|
+
|
|
274
359
|
describe 'conditional inclusion support' do
|
|
275
360
|
let :state do
|
|
276
361
|
Configuration::RequestState.new('abc', list: 'input,image2')
|
|
@@ -335,4 +420,3 @@ describe Configuration do
|
|
|
335
420
|
end
|
|
336
421
|
end
|
|
337
422
|
end
|
|
338
|
-
|