gin 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +11 -0
- data/lib/gin.rb +1 -4
- data/lib/gin/app.rb +84 -31
- data/test/test_app.rb +60 -27
- metadata +3 -3
data/History.rdoc
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
=== 1.0.2 / 2013-03-12
|
2
|
+
|
3
|
+
* Minor Enhancements
|
4
|
+
* Routes have priority over static assets
|
5
|
+
* Rack::Session and Rack::Protection are off by default
|
6
|
+
* When running as middleware, don't run internal middleware
|
7
|
+
if going to next rack app
|
8
|
+
|
9
|
+
* Bugfixes
|
10
|
+
* Block on reloading to avoid multi-threading issues
|
11
|
+
|
1
12
|
=== 1.0.2 / 2013-03-08
|
2
13
|
|
3
14
|
* Minor Enhancements
|
data/lib/gin.rb
CHANGED
data/lib/gin/app.rb
CHANGED
@@ -18,7 +18,11 @@ class Gin::App
|
|
18
18
|
|
19
19
|
RACK_KEYS = { #:nodoc:
|
20
20
|
:stack => 'gin.stack'.freeze,
|
21
|
+
:http_route => 'gin.http_route'.freeze,
|
21
22
|
:path_params => 'gin.path_query_hash'.freeze,
|
23
|
+
:controller => 'gin.controller'.freeze,
|
24
|
+
:action => 'gin.action'.freeze,
|
25
|
+
:static => 'gin.static'.freeze,
|
22
26
|
:reloaded => 'gin.reloaded'.freeze,
|
23
27
|
:errors => 'gin.errors'.freeze
|
24
28
|
}.freeze
|
@@ -312,11 +316,11 @@ class Gin::App
|
|
312
316
|
|
313
317
|
##
|
314
318
|
# Use rack sessions or not. Supports assigning
|
315
|
-
# hash for options. Defaults to
|
319
|
+
# hash for options. Defaults to false.
|
316
320
|
|
317
321
|
def self.sessions opts=nil
|
318
322
|
@session = opts unless opts.nil?
|
319
|
-
@session =
|
323
|
+
@session = false if @session.nil?
|
320
324
|
@session
|
321
325
|
end
|
322
326
|
|
@@ -333,11 +337,11 @@ class Gin::App
|
|
333
337
|
|
334
338
|
##
|
335
339
|
# Use rack-protection or not. Supports assigning
|
336
|
-
# hash for options. Defaults to
|
340
|
+
# hash for options. Defaults to false.
|
337
341
|
|
338
342
|
def self.protection opts=nil
|
339
343
|
@protection = opts unless opts.nil?
|
340
|
-
@protection =
|
344
|
+
@protection = false if @protection.nil?
|
341
345
|
@protection
|
342
346
|
end
|
343
347
|
|
@@ -431,13 +435,17 @@ class Gin::App
|
|
431
435
|
|
432
436
|
def reload!
|
433
437
|
return unless autoreload
|
434
|
-
|
435
|
-
[self.class.name.split("::").last],
|
436
|
-
self.class.namespace
|
438
|
+
@mutex ||= Mutex.new
|
437
439
|
|
438
|
-
|
439
|
-
|
440
|
-
|
440
|
+
@mutex.synchronize do
|
441
|
+
self.class.erase! [self.class.source_file],
|
442
|
+
[self.class.name.split("::").last],
|
443
|
+
self.class.namespace
|
444
|
+
|
445
|
+
self.class.erase_dependencies!
|
446
|
+
Object.send(:require, self.class.source_file)
|
447
|
+
@app = self.class.source_class.new @rack_app, @logger
|
448
|
+
end
|
441
449
|
end
|
442
450
|
|
443
451
|
|
@@ -445,18 +453,40 @@ class Gin::App
|
|
445
453
|
# Default Rack call method.
|
446
454
|
|
447
455
|
def call env
|
448
|
-
|
449
|
-
|
456
|
+
try_autoreload(env)
|
457
|
+
|
458
|
+
if @app.route!(env)
|
459
|
+
@app.call!(env)
|
460
|
+
|
461
|
+
elsif @app.static!(env)
|
462
|
+
@app.call_static(env)
|
463
|
+
|
464
|
+
elsif @rack_app
|
465
|
+
@rack_app.call(env)
|
466
|
+
|
467
|
+
else
|
468
|
+
@app.call!(env)
|
450
469
|
end
|
470
|
+
end
|
451
471
|
|
452
|
-
if autoreload && !env[RACK_KEYS[:reloaded]]
|
453
|
-
env[RACK_KEYS[:reloaded]] = true
|
454
|
-
reload!
|
455
|
-
@app.call env
|
456
472
|
|
457
|
-
|
473
|
+
##
|
474
|
+
# Check if autoreload is needed and reload.
|
475
|
+
|
476
|
+
def try_autoreload env
|
477
|
+
return if env[RACK_KEYS[:reloaded]]
|
478
|
+
env[RACK_KEYS[:reloaded]] = true
|
479
|
+
reload!
|
480
|
+
end
|
481
|
+
|
482
|
+
|
483
|
+
##
|
484
|
+
# Call App instance stack without static file lookup or reloading.
|
485
|
+
|
486
|
+
def call! env
|
487
|
+
if env[RACK_KEYS[:stack]]
|
458
488
|
env.delete RACK_KEYS[:stack]
|
459
|
-
|
489
|
+
dispatch env, env[RACK_KEYS[:controller]], env[RACK_KEYS[:action]]
|
460
490
|
|
461
491
|
else
|
462
492
|
env[RACK_KEYS[:stack]] = true
|
@@ -466,29 +496,53 @@ class Gin::App
|
|
466
496
|
|
467
497
|
|
468
498
|
##
|
469
|
-
#
|
470
|
-
|
471
|
-
def call! env
|
472
|
-
ctrl, action, env[RACK_KEYS[:path_params]] =
|
473
|
-
router.resources_for env['REQUEST_METHOD'], env['PATH_INFO']
|
499
|
+
# Returns a static file Rack response Array from the given gin.static
|
500
|
+
# env filename.
|
474
501
|
|
475
|
-
|
502
|
+
def call_static env
|
503
|
+
error_delegate.exec(self, env){ send_file env[RACK_KEYS[:static]] }
|
476
504
|
end
|
477
505
|
|
478
506
|
|
479
|
-
|
507
|
+
##
|
508
|
+
# Check if the request is for a static file and set the gin.static env
|
509
|
+
# variable to the filepath.
|
510
|
+
|
511
|
+
def static! env
|
512
|
+
filepath = %w{GET HEAD}.include?(env['REQUEST_METHOD']) &&
|
513
|
+
asset(env['PATH_INFO'])
|
514
|
+
|
515
|
+
filepath ? (env[RACK_KEYS[:static]] = filepath) :
|
516
|
+
env.delete(RACK_KEYS[:static])
|
517
|
+
|
518
|
+
!!env[RACK_KEYS[:static]]
|
519
|
+
end
|
520
|
+
|
480
521
|
|
481
522
|
##
|
482
|
-
# Check if the request
|
523
|
+
# Check if the request routes to a controller and action and set
|
524
|
+
# gin.controller, gin.action, gin.path_query_hash,
|
525
|
+
# and gin.http_route env variables.
|
483
526
|
|
484
|
-
def
|
485
|
-
|
527
|
+
def route! env
|
528
|
+
http_route = "#{env['REQUEST_METHOD']} #{env['PATH_INFO']}"
|
529
|
+
return true if env[RACK_KEYS[:http_route]] == http_route
|
530
|
+
|
531
|
+
env[RACK_KEYS[:controller]], env[RACK_KEYS[:action]], env[RACK_KEYS[:path_params]] =
|
532
|
+
router.resources_for env['REQUEST_METHOD'], env['PATH_INFO']
|
533
|
+
|
534
|
+
env[RACK_KEYS[:http_route]] = http_route
|
535
|
+
|
536
|
+
!!(env[RACK_KEYS[:controller]] && env[RACK_KEYS[:action]])
|
486
537
|
end
|
487
538
|
|
488
539
|
|
540
|
+
STATIC_PATH_CLEANER = %r{\.+/|/\.+} #:nodoc:
|
541
|
+
|
489
542
|
##
|
490
543
|
# Check if an asset exists.
|
491
544
|
# Returns the full path to the asset if found, otherwise nil.
|
545
|
+
# Does not support ./ or ../ for security reasons.
|
492
546
|
|
493
547
|
def asset path
|
494
548
|
path = path.gsub STATIC_PATH_CLEANER, ""
|
@@ -511,9 +565,6 @@ class Gin::App
|
|
511
565
|
|
512
566
|
ctrl.new(self, env).call_action action
|
513
567
|
|
514
|
-
rescue Gin::NotFound => err
|
515
|
-
@rack_app ? @rack_app.call(env) : handle_error(err, env)
|
516
|
-
|
517
568
|
rescue ::Exception => err
|
518
569
|
handle_error(err, env)
|
519
570
|
end
|
@@ -564,6 +615,8 @@ class Gin::App
|
|
564
615
|
|
565
616
|
def setup_protection builder
|
566
617
|
return unless protection
|
618
|
+
require 'rack-protection' unless defined?(Rack::Protection)
|
619
|
+
|
567
620
|
options = Hash === protection ? protection.dup : {}
|
568
621
|
options[:except] = Array options[:except]
|
569
622
|
options[:except] += [:session_hijacking, :remote_token] unless sessions
|
data/test/test_app.rb
CHANGED
@@ -134,7 +134,7 @@ class AppTest < Test::Unit::TestCase
|
|
134
134
|
|
135
135
|
|
136
136
|
def test_protection
|
137
|
-
assert_equal
|
137
|
+
assert_equal false, FooApp.protection
|
138
138
|
|
139
139
|
FooApp.protection(test: "thing")
|
140
140
|
assert_equal({test:"thing"}, FooApp.protection)
|
@@ -171,7 +171,7 @@ class AppTest < Test::Unit::TestCase
|
|
171
171
|
|
172
172
|
|
173
173
|
def test_sessions
|
174
|
-
assert_equal
|
174
|
+
assert_equal false, FooApp.sessions
|
175
175
|
|
176
176
|
FooApp.sessions(test: "thing")
|
177
177
|
assert_equal({test:"thing"}, FooApp.sessions)
|
@@ -247,7 +247,7 @@ class AppTest < Test::Unit::TestCase
|
|
247
247
|
assert FooMiddleware.called?
|
248
248
|
|
249
249
|
FooMiddleware.reset!
|
250
|
-
myapp.
|
250
|
+
myapp.dispatch({'rack.input' => "", 'PATH_INFO' => '/foo', 'REQUEST_METHOD' => 'GET'}, FooController, :index)
|
251
251
|
assert !FooMiddleware.called?
|
252
252
|
end
|
253
253
|
|
@@ -273,6 +273,18 @@ class AppTest < Test::Unit::TestCase
|
|
273
273
|
end
|
274
274
|
|
275
275
|
|
276
|
+
def test_call_rack_app
|
277
|
+
env = {'rack.input' => "", 'PATH_INFO' => '/bad', 'REQUEST_METHOD' => 'GET'}
|
278
|
+
expected = [200, {'Content-Length'=>"5"}, "AHOY!"]
|
279
|
+
myapp = lambda{|env| expected }
|
280
|
+
@app = FooApp.new myapp
|
281
|
+
|
282
|
+
resp = @app.call env
|
283
|
+
assert_equal expected, resp
|
284
|
+
end
|
285
|
+
|
286
|
+
|
287
|
+
|
276
288
|
def test_call!
|
277
289
|
resp = @app.call! 'rack.input' => "",
|
278
290
|
'PATH_INFO' => '/foo',
|
@@ -324,17 +336,6 @@ class AppTest < Test::Unit::TestCase
|
|
324
336
|
end
|
325
337
|
|
326
338
|
|
327
|
-
def test_dispatch_rack_app
|
328
|
-
env = {'rack.input' => "", 'PATH_INFO' => '/bad', 'REQUEST_METHOD' => 'GET'}
|
329
|
-
expected = [200, {'Content-Length'=>"5"}, "AHOY!"]
|
330
|
-
myapp = lambda{|env| expected }
|
331
|
-
@app = FooApp.new myapp
|
332
|
-
|
333
|
-
resp = @app.dispatch env, nil, nil
|
334
|
-
assert_equal expected, resp
|
335
|
-
end
|
336
|
-
|
337
|
-
|
338
339
|
def test_dispatch_error
|
339
340
|
FooApp.environment 'test'
|
340
341
|
env = {'rack.input' => "", 'PATH_INFO' => '/bad', 'REQUEST_METHOD' => 'GET'}
|
@@ -457,33 +458,65 @@ class AppTest < Test::Unit::TestCase
|
|
457
458
|
FooApp.public_dir "./test/mock_config"
|
458
459
|
assert @app.asset("backend.yml") =~ %r{/gin/test/mock_config/backend\.yml$}
|
459
460
|
assert @app.asset("500.html") =~ %r{/gin/public/500\.html$}
|
461
|
+
|
462
|
+
assert !@app.asset("foo/../../mock_config/backend.yml")
|
463
|
+
assert !@app.asset("foo/../../public/500.html")
|
464
|
+
end
|
465
|
+
|
466
|
+
|
467
|
+
def test_bad_asset
|
468
|
+
FooApp.public_dir "./test/mock_config"
|
460
469
|
assert_nil @app.asset("bad_file")
|
461
470
|
assert_nil @app.asset("../../History.rdoc")
|
471
|
+
|
472
|
+
path = File.join(FooApp.public_dir, "../.././test/mock_config/../../History.rdoc")
|
473
|
+
assert File.file?(path)
|
474
|
+
assert_nil @app.asset("../.././test/mock_config/../../History.rdoc")
|
462
475
|
end
|
463
476
|
|
464
477
|
|
465
|
-
def
|
478
|
+
def test_static_no_file
|
466
479
|
env = {'rack.input' => "", 'PATH_INFO' => '/foo', 'REQUEST_METHOD' => 'GET'}
|
467
|
-
assert !@app.static
|
480
|
+
assert !@app.static!(env)
|
481
|
+
end
|
482
|
+
|
468
483
|
|
484
|
+
def test_static
|
485
|
+
env = {'rack.input' => "", 'REQUEST_METHOD' => 'GET'}
|
469
486
|
env['PATH_INFO'] = '/500.html'
|
470
|
-
assert @app.static
|
487
|
+
assert @app.static!(env)
|
488
|
+
assert env['gin.static'] =~ %r{/gin/public/500\.html$}
|
489
|
+
end
|
471
490
|
|
472
|
-
env['PATH_INFO'] = '../../../500.html'
|
473
|
-
assert @app.static?(env) =~ %r{/gin/public/500\.html$}
|
474
491
|
|
492
|
+
def test_static_updir
|
493
|
+
env = {'rack.input' => "", 'REQUEST_METHOD' => 'GET'}
|
494
|
+
env['PATH_INFO'] = '../../gin/public/500.html'
|
495
|
+
assert !@app.static!(env)
|
496
|
+
assert !env['gin.static']
|
497
|
+
end
|
498
|
+
|
499
|
+
|
500
|
+
def test_static_head
|
501
|
+
env = {'rack.input' => "", 'REQUEST_METHOD' => 'GET'}
|
475
502
|
env['REQUEST_METHOD'] = 'HEAD'
|
476
|
-
|
503
|
+
env['PATH_INFO'] = '/500.html'
|
504
|
+
assert @app.static!(env)
|
505
|
+
assert env['gin.static'] =~ %r{/gin/public/500\.html$}
|
506
|
+
end
|
477
507
|
|
508
|
+
|
509
|
+
def test_non_static_verbs
|
510
|
+
env = {'rack.input' => "", 'REQUEST_METHOD' => 'GET'}
|
478
511
|
env['PATH_INFO'] = '/backend.yml'
|
479
|
-
assert !@app.static?(env)
|
480
512
|
|
481
513
|
FooApp.public_dir "./test/mock_config"
|
482
|
-
assert @app.static
|
514
|
+
assert @app.static!(env)
|
515
|
+
assert env['gin.static'] =~ %r{/gin/test/mock_config/backend\.yml$}
|
483
516
|
|
484
517
|
%w{POST PUT DELETE TRACE OPTIONS}.each do |verb|
|
485
518
|
env['REQUEST_METHOD'] = verb
|
486
|
-
assert !@app.static
|
519
|
+
assert !@app.static!(env), "#{verb} should not be a static request"
|
487
520
|
end
|
488
521
|
end
|
489
522
|
|
@@ -568,7 +601,10 @@ class AppTest < Test::Unit::TestCase
|
|
568
601
|
end
|
569
602
|
|
570
603
|
|
571
|
-
def
|
604
|
+
def test_build_w_middleware
|
605
|
+
FooApp.sessions true
|
606
|
+
FooApp.protection true
|
607
|
+
@app = FooApp.new
|
572
608
|
stack = @app.instance_variable_get("@stack")
|
573
609
|
assert Rack::Session::Cookie === stack
|
574
610
|
assert Rack::Protection::FrameOptions === stack.instance_variable_get("@app")
|
@@ -583,9 +619,6 @@ class AppTest < Test::Unit::TestCase
|
|
583
619
|
|
584
620
|
|
585
621
|
def test_build_no_middleware
|
586
|
-
FooApp.sessions false
|
587
|
-
FooApp.protection false
|
588
|
-
@app = FooApp.new
|
589
622
|
stack = @app.instance_variable_get("@stack")
|
590
623
|
assert_equal @app, stack
|
591
624
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-03-
|
12
|
+
date: 2013-03-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
@@ -150,7 +150,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
150
150
|
version: '0'
|
151
151
|
segments:
|
152
152
|
- 0
|
153
|
-
hash:
|
153
|
+
hash: 3408999320760955315
|
154
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
155
|
none: false
|
156
156
|
requirements:
|