httpimagestore 1.7.0 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -2
- data/Gemfile.lock +7 -7
- data/README.md +59 -4
- data/VERSION +1 -1
- data/features/compatibility.feature +3 -3
- data/features/encoding.feature +35 -0
- data/features/error-reporting.feature +11 -0
- data/features/rewrite.feature +122 -0
- data/features/s3-store-and-thumbnail.feature +4 -4
- data/features/step_definitions/httpimagestore_steps.rb +18 -6
- data/features/support/env.rb +11 -9
- data/httpimagestore.gemspec +12 -9
- data/lib/httpimagestore/configuration/file.rb +2 -2
- data/lib/httpimagestore/configuration/handler.rb +7 -3
- data/lib/httpimagestore/configuration/output.rb +55 -17
- data/lib/httpimagestore/configuration/s3.rb +12 -4
- data/spec/configuration_file_spec.rb +3 -4
- data/spec/configuration_handler_spec.rb +1 -2
- data/spec/configuration_identify_spec.rb +1 -2
- data/spec/configuration_output_spec.rb +289 -10
- data/spec/configuration_path_spec.rb +2 -3
- data/spec/configuration_s3_spec.rb +39 -38
- data/spec/configuration_source_failover_spec.rb +1 -1
- data/spec/configuration_spec.rb +1 -2
- data/spec/configuration_thumbnailer_spec.rb +1 -2
- data/spec/spec_helper.rb +15 -7
- data/spec/support/utf_string.txt +1 -0
- metadata +11 -8
@@ -69,9 +69,12 @@ module Configuration
|
|
69
69
|
attr_reader :image_name
|
70
70
|
attr_reader :path_spec
|
71
71
|
|
72
|
-
def initialize(global, image_name, path_spec, matcher)
|
72
|
+
def initialize(global, image_name, scheme, host, port, path_spec, matcher)
|
73
73
|
@global = global
|
74
74
|
@image_name = image_name
|
75
|
+
@scheme = scheme
|
76
|
+
@host = host
|
77
|
+
@port = port
|
75
78
|
@path_spec = path_spec
|
76
79
|
inclusion_matcher matcher
|
77
80
|
end
|
@@ -79,26 +82,42 @@ module Configuration
|
|
79
82
|
def store_path(request_state)
|
80
83
|
store_path = request_state.images[@image_name].store_path or raise StorePathNotSetForImage.new(@image_name)
|
81
84
|
return store_path unless @path_spec
|
82
|
-
rendered_path(store_path, request_state)
|
83
|
-
end
|
84
85
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
86
|
+
locals = {
|
87
|
+
image_name: @image_name,
|
88
|
+
path: store_path
|
89
|
+
}
|
90
|
+
|
91
|
+
rendered_path(request_state.with_locals(locals))
|
91
92
|
end
|
92
93
|
|
93
|
-
|
94
|
+
def store_url(request_state)
|
95
|
+
url = request_state.images[@image_name].store_url or raise StoreURLNotSetForImage.new(@image_name)
|
96
|
+
url = url.dup
|
94
97
|
|
95
|
-
def rendered_path(store_path, request_state)
|
96
|
-
path = @global.paths[@path_spec]
|
97
98
|
locals = {
|
98
|
-
|
99
|
-
|
99
|
+
image_name: @image_name,
|
100
|
+
path: URI.utf_decode(url.path),
|
101
|
+
url: url.to_s
|
100
102
|
}
|
101
|
-
|
103
|
+
locals[:scheme] = url.scheme if url.scheme
|
104
|
+
locals[:host] = url.host if url.host
|
105
|
+
locals[:port] = url.port if url.port
|
106
|
+
|
107
|
+
request_state = request_state.with_locals(locals)
|
108
|
+
|
109
|
+
# optional rewrites
|
110
|
+
url.scheme = request_state.render_template(@scheme) if @scheme
|
111
|
+
url.host = request_state.render_template(@host) if @host
|
112
|
+
url.port = request_state.render_template(@port).to_i if @port
|
113
|
+
url.path = URI.encode(rendered_path(request_state)).tap{|path| path.replace('/' + path) if path[0] != '/'} if @path_spec
|
114
|
+
|
115
|
+
url
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
def rendered_path(request_state)
|
120
|
+
Pathname.new(@global.paths[@path_spec].render(request_state)).cleanpath.to_s
|
102
121
|
end
|
103
122
|
end
|
104
123
|
|
@@ -106,9 +125,9 @@ module Configuration
|
|
106
125
|
nodes = node.values.empty? ? node.children : [node]
|
107
126
|
output_specs = nodes.map do |node|
|
108
127
|
image_name = node.grab_values('image name').first
|
109
|
-
path_spec, if_image_name_on = *node.grab_attributes('path', 'if-image-name-on')
|
128
|
+
scheme, host, port, path_spec, if_image_name_on = *node.grab_attributes('scheme', 'host', 'port', 'path', 'if-image-name-on')
|
110
129
|
matcher = InclusionMatcher.new(image_name, if_image_name_on)
|
111
|
-
OutputSpec.new(configuration.global, image_name, path_spec, matcher)
|
130
|
+
OutputSpec.new(configuration.global, image_name, scheme, host, port, path_spec, matcher)
|
112
131
|
end
|
113
132
|
|
114
133
|
configuration.output and raise StatementCollisionError.new(node, 'output')
|
@@ -214,5 +233,24 @@ module Configuration
|
|
214
233
|
end
|
215
234
|
end
|
216
235
|
Handler::register_node_parser OutputStoreURL
|
236
|
+
|
237
|
+
class OutputStoreURI < OutputMultiBase
|
238
|
+
def self.match(node)
|
239
|
+
node.name == 'output_store_uri'
|
240
|
+
end
|
241
|
+
|
242
|
+
def realize(request_state)
|
243
|
+
urls = @output_specs.select do |output_spec|
|
244
|
+
output_spec.included?(request_state)
|
245
|
+
end.map do |output_spec|
|
246
|
+
output_spec.store_url(request_state).path
|
247
|
+
end
|
248
|
+
|
249
|
+
request_state.output do
|
250
|
+
write_url_list 200, urls
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
Handler::register_node_parser OutputStoreURI
|
217
255
|
end
|
218
256
|
|
@@ -177,11 +177,11 @@ module Configuration
|
|
177
177
|
end
|
178
178
|
|
179
179
|
def private_url
|
180
|
-
s3_object.url_for(:read, expires: 60 * 60 * 24 * 365 * 20)
|
180
|
+
s3_object.url_for(:read, expires: 60 * 60 * 24 * 365 * 20) # expire in 20 years
|
181
181
|
end
|
182
182
|
|
183
183
|
def public_url
|
184
|
-
s3_object.public_url
|
184
|
+
s3_object.public_url
|
185
185
|
end
|
186
186
|
|
187
187
|
def content_type
|
@@ -237,11 +237,19 @@ module Configuration
|
|
237
237
|
end
|
238
238
|
|
239
239
|
def private_url
|
240
|
-
@cache_file.header['private_url']
|
240
|
+
url = @cache_file.header['private_url'] and return URI(url)
|
241
|
+
dirty! :private_url
|
242
|
+
url = super
|
243
|
+
@cache_file.header['private_url'] = url.to_s
|
244
|
+
url
|
241
245
|
end
|
242
246
|
|
243
247
|
def public_url
|
244
|
-
@cache_file.header['public_url']
|
248
|
+
url = @cache_file.header['public_url'] and return URI(url)
|
249
|
+
dirty! :public_url
|
250
|
+
url = super
|
251
|
+
@cache_file.header['public_url'] = url.to_s
|
252
|
+
url
|
245
253
|
end
|
246
254
|
|
247
255
|
def content_type
|
@@ -1,10 +1,9 @@
|
|
1
1
|
require_relative 'spec_helper'
|
2
2
|
require 'httpimagestore/configuration'
|
3
|
-
Configuration::Scope.logger =
|
3
|
+
MemoryLimit.logger = Configuration::Scope.logger = RootLogger.new('/dev/null')
|
4
4
|
|
5
5
|
require 'httpimagestore/configuration/file'
|
6
6
|
require 'httpimagestore/configuration/output'
|
7
|
-
MemoryLimit.logger = Logger.new('/dev/null')
|
8
7
|
|
9
8
|
describe Configuration do
|
10
9
|
let :state do
|
@@ -54,7 +53,7 @@ describe Configuration do
|
|
54
53
|
subject.handlers[0].sources[0].realize(state)
|
55
54
|
|
56
55
|
state.images['original'].source_path.should == "test.in"
|
57
|
-
state.images['original'].source_url.should == "file
|
56
|
+
state.images['original'].source_url.to_s.should == "file:/test.in"
|
58
57
|
end
|
59
58
|
|
60
59
|
describe 'context locals' do
|
@@ -220,7 +219,7 @@ describe Configuration do
|
|
220
219
|
subject.handlers[0].stores[0].realize(state)
|
221
220
|
|
222
221
|
state.images['input'].store_path.should == "test.out"
|
223
|
-
state.images['input'].store_url.should == "file
|
222
|
+
state.images['input'].store_url.to_s.should == "file:/test.out"
|
224
223
|
end
|
225
224
|
|
226
225
|
describe 'conditional inclusion support' do
|
@@ -2,11 +2,10 @@ require_relative 'spec_helper'
|
|
2
2
|
require_relative 'support/cuba_response_env'
|
3
3
|
|
4
4
|
require 'httpimagestore/configuration'
|
5
|
-
Configuration::Scope.logger =
|
5
|
+
MemoryLimit.logger = Configuration::Scope.logger = RootLogger.new('/dev/null')
|
6
6
|
|
7
7
|
require 'httpimagestore/configuration/handler'
|
8
8
|
require 'httpimagestore/configuration/output'
|
9
|
-
MemoryLimit.logger = Logger.new('/dev/null')
|
10
9
|
|
11
10
|
describe Configuration do
|
12
11
|
describe Configuration::Handler do
|
@@ -1,11 +1,10 @@
|
|
1
1
|
require_relative 'spec_helper'
|
2
2
|
require 'httpimagestore/configuration'
|
3
|
-
Configuration::Scope.logger =
|
3
|
+
MemoryLimit.logger = Configuration::Scope.logger = RootLogger.new('/dev/null')
|
4
4
|
|
5
5
|
require 'httpimagestore/configuration/output'
|
6
6
|
require 'httpimagestore/configuration/thumbnailer'
|
7
7
|
require 'httpimagestore/configuration/identify'
|
8
|
-
MemoryLimit.logger = Logger.new('/dev/null')
|
9
8
|
|
10
9
|
describe Configuration do
|
11
10
|
describe 'identify' do
|
@@ -2,11 +2,10 @@ require_relative 'spec_helper'
|
|
2
2
|
require_relative 'support/cuba_response_env'
|
3
3
|
|
4
4
|
require 'httpimagestore/configuration'
|
5
|
-
Configuration::Scope.logger =
|
5
|
+
MemoryLimit.logger = Configuration::Scope.logger = RootLogger.new('/dev/null')
|
6
6
|
|
7
7
|
require 'httpimagestore/configuration/output'
|
8
8
|
require 'httpimagestore/configuration/file'
|
9
|
-
MemoryLimit.logger = Logger.new('/dev/null')
|
10
9
|
|
11
10
|
describe Configuration do
|
12
11
|
let :state do
|
@@ -159,6 +158,10 @@ describe Configuration do
|
|
159
158
|
end
|
160
159
|
|
161
160
|
describe 'output store paths and URLs' do
|
161
|
+
let :utf_string do
|
162
|
+
(support_dir + 'utf_string.txt').read.strip
|
163
|
+
end
|
164
|
+
|
162
165
|
let :in_file do
|
163
166
|
Pathname.new("/tmp/test.in")
|
164
167
|
end
|
@@ -179,8 +182,12 @@ describe Configuration do
|
|
179
182
|
Pathname.new('/tmp/abc/t e s t.out')
|
180
183
|
end
|
181
184
|
|
185
|
+
let :utf_test_file do
|
186
|
+
Pathname.new("/tmp/abc/#{utf_string}.out")
|
187
|
+
end
|
188
|
+
|
182
189
|
before :each do
|
183
|
-
test_file.dirname.mkdir
|
190
|
+
test_file.dirname.mkdir unless test_file.dirname.directory?
|
184
191
|
test_file.open('w'){|io| io.write('abc')}
|
185
192
|
space_test_file.open('w'){|io| io.write('abc')}
|
186
193
|
in_file.open('w'){|io| io.write('abc')}
|
@@ -191,6 +198,7 @@ describe Configuration do
|
|
191
198
|
after :each do
|
192
199
|
test_file.exist? and test_file.unlink
|
193
200
|
space_test_file.exist? and space_test_file.unlink
|
201
|
+
utf_test_file.exist? and utf_test_file.unlink
|
194
202
|
test_file.dirname.exist? and test_file.dirname.rmdir
|
195
203
|
out_file.unlink if out_file.exist?
|
196
204
|
out2_file.unlink if out2_file.exist?
|
@@ -391,7 +399,7 @@ describe Configuration do
|
|
391
399
|
|
392
400
|
env.instance_eval &state.output_callback
|
393
401
|
env.res['Content-Type'].should == 'text/uri-list'
|
394
|
-
env.res.data.should == "file
|
402
|
+
env.res.data.should == "file:/test.out\r\n"
|
395
403
|
end
|
396
404
|
|
397
405
|
it 'should provide multiple file store URLs' do
|
@@ -423,7 +431,7 @@ describe Configuration do
|
|
423
431
|
|
424
432
|
env.instance_eval &state.output_callback
|
425
433
|
env.res['Content-Type'].should == 'text/uri-list'
|
426
|
-
env.res.data.should == "file
|
434
|
+
env.res.data.should == "file:/test.out\r\nfile:/test.out2\r\n"
|
427
435
|
end
|
428
436
|
|
429
437
|
describe 'conditional inclusion support' do
|
@@ -468,12 +476,12 @@ describe Configuration do
|
|
468
476
|
|
469
477
|
env.instance_eval &state.output_callback
|
470
478
|
env.res['Content-Type'].should == 'text/uri-list'
|
471
|
-
env.res.data.should == "file
|
479
|
+
env.res.data.should == "file:/test.out1\r\nfile:/test.out3\r\n"
|
472
480
|
end
|
473
481
|
end
|
474
482
|
|
475
|
-
describe '
|
476
|
-
it 'should
|
483
|
+
describe 'URL rewrites' do
|
484
|
+
it 'should allow using path spec to rewrite URL path component' do
|
477
485
|
subject = Configuration.read(<<-'EOF')
|
478
486
|
path "out" "abc/test.out"
|
479
487
|
|
@@ -492,7 +500,93 @@ describe Configuration do
|
|
492
500
|
|
493
501
|
env.instance_eval &state.output_callback
|
494
502
|
env.res['Content-Type'].should == 'text/uri-list'
|
495
|
-
env.res.data.should == "file
|
503
|
+
env.res.data.should == "file:/hello/abc/world/test-xyz.out\r\n"
|
504
|
+
end
|
505
|
+
|
506
|
+
it 'should allow rewriting scheme component' do
|
507
|
+
subject = Configuration.read(<<-'EOF')
|
508
|
+
path "out" "abc/test.out"
|
509
|
+
|
510
|
+
post "single" {
|
511
|
+
store_file "input" root="/tmp" path="out"
|
512
|
+
|
513
|
+
output_store_url "input" scheme="ftp"
|
514
|
+
}
|
515
|
+
EOF
|
516
|
+
|
517
|
+
subject.handlers[0].sources[0].realize(state)
|
518
|
+
subject.handlers[0].stores[0].realize(state)
|
519
|
+
subject.handlers[0].output.realize(state)
|
520
|
+
|
521
|
+
env.instance_eval &state.output_callback
|
522
|
+
env.res['Content-Type'].should == 'text/uri-list'
|
523
|
+
env.res.data.should == "ftp:/abc/test.out\r\n"
|
524
|
+
end
|
525
|
+
|
526
|
+
it 'should allow rewriting host component' do
|
527
|
+
subject = Configuration.read(<<-'EOF')
|
528
|
+
path "out" "abc/test.out"
|
529
|
+
|
530
|
+
post "single" {
|
531
|
+
store_file "input" root="/tmp" path="out"
|
532
|
+
|
533
|
+
output_store_url "input" host="localhost"
|
534
|
+
}
|
535
|
+
EOF
|
536
|
+
|
537
|
+
subject.handlers[0].sources[0].realize(state)
|
538
|
+
subject.handlers[0].stores[0].realize(state)
|
539
|
+
subject.handlers[0].output.realize(state)
|
540
|
+
|
541
|
+
env.instance_eval &state.output_callback
|
542
|
+
env.res['Content-Type'].should == 'text/uri-list'
|
543
|
+
env.res.data.should == "file://localhost/abc/test.out\r\n"
|
544
|
+
end
|
545
|
+
|
546
|
+
it 'should allow rewriting port component' do
|
547
|
+
subject = Configuration.read(<<-'EOF')
|
548
|
+
path "out" "abc/test.out"
|
549
|
+
|
550
|
+
post "single" {
|
551
|
+
store_file "input" root="/tmp" path="out"
|
552
|
+
|
553
|
+
output_store_url "input" port="21"
|
554
|
+
}
|
555
|
+
EOF
|
556
|
+
|
557
|
+
subject.handlers[0].sources[0].realize(state)
|
558
|
+
subject.handlers[0].stores[0].realize(state)
|
559
|
+
subject.handlers[0].output.realize(state)
|
560
|
+
|
561
|
+
env.instance_eval &state.output_callback
|
562
|
+
env.res['Content-Type'].should == 'text/uri-list'
|
563
|
+
env.res.data.should == "file::21/abc/test.out\r\n"
|
564
|
+
end
|
565
|
+
|
566
|
+
it 'should allow using variables for all supported rewrites' do
|
567
|
+
state = Configuration::RequestState.new('abc',
|
568
|
+
remote: 'example.com',
|
569
|
+
remote_port: 21,
|
570
|
+
proto: 'ftp'
|
571
|
+
)
|
572
|
+
subject = Configuration.read(<<-'EOF')
|
573
|
+
path "out" "abc/test.out"
|
574
|
+
path "formatted" "hello/#{dirname}/world/#{basename}-xyz.#{extension}"
|
575
|
+
|
576
|
+
post "single" {
|
577
|
+
store_file "input" root="/tmp" path="out"
|
578
|
+
|
579
|
+
output_store_url "input" scheme="#{proto}" host="#{remote}" port="#{remote_port}" path="formatted"
|
580
|
+
}
|
581
|
+
EOF
|
582
|
+
|
583
|
+
subject.handlers[0].sources[0].realize(state)
|
584
|
+
subject.handlers[0].stores[0].realize(state)
|
585
|
+
subject.handlers[0].output.realize(state)
|
586
|
+
|
587
|
+
env.instance_eval &state.output_callback
|
588
|
+
env.res['Content-Type'].should == 'text/uri-list'
|
589
|
+
env.res.data.should == "ftp://example.com:21/hello/abc/world/test-xyz.out\r\n"
|
496
590
|
end
|
497
591
|
end
|
498
592
|
|
@@ -518,7 +612,7 @@ describe Configuration do
|
|
518
612
|
|
519
613
|
env.instance_eval &state.output_callback
|
520
614
|
env.res['Content-Type'].should == 'text/uri-list'
|
521
|
-
env.res.data.should == "file
|
615
|
+
env.res.data.should == "file:/abc/t%20e%20s%20t.out\r\nfile:/hello/abc/world/t%20e%20s%20t-xyz.out\r\n"
|
522
616
|
end
|
523
617
|
end
|
524
618
|
|
@@ -538,5 +632,190 @@ describe Configuration do
|
|
538
632
|
end
|
539
633
|
end
|
540
634
|
end
|
635
|
+
|
636
|
+
describe Configuration::OutputStoreURI do
|
637
|
+
it 'should provide file store URI' do
|
638
|
+
subject = Configuration.read(<<-EOF)
|
639
|
+
path {
|
640
|
+
"out" "test.out"
|
641
|
+
}
|
642
|
+
|
643
|
+
post "single" {
|
644
|
+
store_file "input" root="/tmp" path="out"
|
645
|
+
|
646
|
+
output_store_uri "input"
|
647
|
+
}
|
648
|
+
EOF
|
649
|
+
|
650
|
+
subject.handlers[0].sources[0].realize(state)
|
651
|
+
subject.handlers[0].stores[0].realize(state)
|
652
|
+
subject.handlers[0].output.realize(state)
|
653
|
+
|
654
|
+
env.instance_eval &state.output_callback
|
655
|
+
env.res['Content-Type'].should == 'text/uri-list'
|
656
|
+
env.res.data.should == "/test.out\r\n"
|
657
|
+
end
|
658
|
+
|
659
|
+
it 'should provide multiple file store URIs' do
|
660
|
+
subject = Configuration.read(<<-EOF)
|
661
|
+
path {
|
662
|
+
"in" "test.in"
|
663
|
+
"out" "test.out"
|
664
|
+
"out2" "test.out2"
|
665
|
+
}
|
666
|
+
|
667
|
+
post "multi" {
|
668
|
+
source_file "original" root="/tmp" path="in"
|
669
|
+
|
670
|
+
store_file "input" root="/tmp" path="out"
|
671
|
+
store_file "original" root="/tmp" path="out2"
|
672
|
+
|
673
|
+
output_store_uri {
|
674
|
+
"input"
|
675
|
+
"original"
|
676
|
+
}
|
677
|
+
}
|
678
|
+
EOF
|
679
|
+
|
680
|
+
subject.handlers[0].sources[0].realize(state)
|
681
|
+
subject.handlers[0].sources[1].realize(state)
|
682
|
+
subject.handlers[0].stores[0].realize(state)
|
683
|
+
subject.handlers[0].stores[1].realize(state)
|
684
|
+
subject.handlers[0].output.realize(state)
|
685
|
+
|
686
|
+
env.instance_eval &state.output_callback
|
687
|
+
env.res['Content-Type'].should == 'text/uri-list'
|
688
|
+
env.res.data.should == "/test.out\r\n/test.out2\r\n"
|
689
|
+
end
|
690
|
+
|
691
|
+
describe 'conditional inclusion support' do
|
692
|
+
let :state do
|
693
|
+
Configuration::RequestState.new('abc', list: 'input,image2')
|
694
|
+
end
|
695
|
+
|
696
|
+
subject do
|
697
|
+
Configuration.read(<<-'EOF')
|
698
|
+
path {
|
699
|
+
"in" "test.in"
|
700
|
+
"out1" "test.out1"
|
701
|
+
"out2" "test.out2"
|
702
|
+
"out3" "test.out3"
|
703
|
+
}
|
704
|
+
|
705
|
+
post "multi" {
|
706
|
+
source_file "image1" root="/tmp" path="in"
|
707
|
+
source_file "image2" root="/tmp" path="in"
|
708
|
+
|
709
|
+
store_file "input" root="/tmp" path="out1"
|
710
|
+
store_file "image1" root="/tmp" path="out2"
|
711
|
+
store_file "image2" root="/tmp" path="out3"
|
712
|
+
|
713
|
+
output_store_uri {
|
714
|
+
"input" if-image-name-on="#{list}"
|
715
|
+
"image1" if-image-name-on="#{list}"
|
716
|
+
"image2" if-image-name-on="#{list}"
|
717
|
+
}
|
718
|
+
}
|
719
|
+
EOF
|
720
|
+
end
|
721
|
+
|
722
|
+
it 'should output store url only for images that names match if-image-name-on list' do
|
723
|
+
subject.handlers[0].sources[0].realize(state)
|
724
|
+
subject.handlers[0].sources[1].realize(state)
|
725
|
+
subject.handlers[0].sources[2].realize(state)
|
726
|
+
subject.handlers[0].stores[0].realize(state)
|
727
|
+
subject.handlers[0].stores[1].realize(state)
|
728
|
+
subject.handlers[0].stores[2].realize(state)
|
729
|
+
subject.handlers[0].output.realize(state)
|
730
|
+
|
731
|
+
env.instance_eval &state.output_callback
|
732
|
+
env.res['Content-Type'].should == 'text/uri-list'
|
733
|
+
env.res.data.should == "/test.out1\r\n/test.out3\r\n"
|
734
|
+
end
|
735
|
+
end
|
736
|
+
|
737
|
+
describe 'URI rewrites' do
|
738
|
+
it 'should allow using path spec to rewrite URI path' do
|
739
|
+
subject = Configuration.read(<<-'EOF')
|
740
|
+
path "out" "abc/test.out"
|
741
|
+
|
742
|
+
path "formatted" "hello/#{dirname}/world/#{basename}-xyz.#{extension}"
|
743
|
+
|
744
|
+
post "single" {
|
745
|
+
store_file "input" root="/tmp" path="out"
|
746
|
+
|
747
|
+
output_store_uri "input" path="formatted"
|
748
|
+
}
|
749
|
+
EOF
|
750
|
+
|
751
|
+
subject.handlers[0].sources[0].realize(state)
|
752
|
+
subject.handlers[0].stores[0].realize(state)
|
753
|
+
subject.handlers[0].output.realize(state)
|
754
|
+
|
755
|
+
env.instance_eval &state.output_callback
|
756
|
+
env.res['Content-Type'].should == 'text/uri-list'
|
757
|
+
env.res.data.should == "/hello/abc/world/test-xyz.out\r\n"
|
758
|
+
end
|
759
|
+
end
|
760
|
+
|
761
|
+
describe 'URI encoding' do
|
762
|
+
let :subject do
|
763
|
+
Configuration.read(<<-'EOF')
|
764
|
+
path "out" "abc/#{name}.out"
|
765
|
+
path "formatted" "hello/#{dirname}/world/#{basename}-xyz.#{extension}"
|
766
|
+
|
767
|
+
post "single" {
|
768
|
+
store_file "input" root="/tmp" path="out"
|
769
|
+
|
770
|
+
output_store_uri {
|
771
|
+
"input"
|
772
|
+
"input" path="formatted"
|
773
|
+
}
|
774
|
+
}
|
775
|
+
EOF
|
776
|
+
end
|
777
|
+
|
778
|
+
it 'should provide properly encoded file store URI' do
|
779
|
+
state = Configuration::RequestState.new('abc', name: 't e s t')
|
780
|
+
|
781
|
+
subject.handlers[0].sources[0].realize(state)
|
782
|
+
subject.handlers[0].stores[0].realize(state)
|
783
|
+
subject.handlers[0].output.realize(state)
|
784
|
+
|
785
|
+
env.instance_eval &state.output_callback
|
786
|
+
env.res['Content-Type'].should == 'text/uri-list'
|
787
|
+
env.res.data.should == "/abc/t%20e%20s%20t.out\r\n/hello/abc/world/t%20e%20s%20t-xyz.out\r\n"
|
788
|
+
end
|
789
|
+
|
790
|
+
it 'should handle UTF-8 characters' do
|
791
|
+
state = Configuration::RequestState.new('abc', name: utf_string)
|
792
|
+
subject.handlers[0].sources[0].realize(state)
|
793
|
+
subject.handlers[0].stores[0].realize(state)
|
794
|
+
subject.handlers[0].output.realize(state)
|
795
|
+
|
796
|
+
env.instance_eval &state.output_callback
|
797
|
+
env.res['Content-Type'].should == 'text/uri-list'
|
798
|
+
l1, l2 = *env.res.data.split("\r\n")
|
799
|
+
URI.utf_decode(l1).should == "/abc/#{utf_string}.out"
|
800
|
+
URI.utf_decode(l2).should == "/hello/abc/world/#{utf_string}-xyz.out"
|
801
|
+
end
|
802
|
+
end
|
803
|
+
|
804
|
+
describe 'error handling' do
|
805
|
+
it 'should raise StoreURLNotSetForImage for output of not stored image' do
|
806
|
+
subject = Configuration.read(<<-EOF)
|
807
|
+
post "single" {
|
808
|
+
output_store_uri "input"
|
809
|
+
}
|
810
|
+
EOF
|
811
|
+
|
812
|
+
subject.handlers[0].sources[0].realize(state)
|
813
|
+
|
814
|
+
expect {
|
815
|
+
subject.handlers[0].output.realize(state)
|
816
|
+
}.to raise_error Configuration::StoreURLNotSetForImage, %{store URL not set for image 'input'}
|
817
|
+
end
|
818
|
+
end
|
819
|
+
end
|
541
820
|
end
|
542
821
|
end
|
@@ -1,10 +1,9 @@
|
|
1
1
|
require_relative 'spec_helper'
|
2
2
|
require 'httpimagestore/configuration'
|
3
|
-
Configuration::Scope.logger =
|
3
|
+
MemoryLimit.logger = Configuration::Scope.logger = RootLogger.new('/dev/null')
|
4
4
|
|
5
5
|
require 'httpimagestore/configuration/handler'
|
6
6
|
require 'httpimagestore/configuration/path'
|
7
|
-
MemoryLimit.logger = Logger.new('/dev/null')
|
8
7
|
|
9
8
|
describe Configuration do
|
10
9
|
describe 'path rendering' do
|
@@ -62,7 +61,7 @@ describe Configuration do
|
|
62
61
|
|
63
62
|
expect {
|
64
63
|
subject.paths['test'].render
|
65
|
-
}.to raise_error Configuration::NoValueForPathTemplatePlaceholerError, %q{cannot generate path 'test' from template '#{abc}#{xyz}': no value for '#{abc}'}
|
64
|
+
}.to raise_error Configuration::NoValueForPathTemplatePlaceholerError, %q{cannot generate path 'test' from template '#{abc}#{xyz}': no value for '#{abc}'}
|
66
65
|
end
|
67
66
|
end
|
68
67
|
|