gin 1.0.2 → 1.0.3
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/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:
|