rack 1.3.10 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack might be problematic. Click here for more details.

Files changed (83) hide show
  1. data/COPYING +1 -1
  2. data/KNOWN-ISSUES +0 -9
  3. data/README.rdoc +4 -118
  4. data/Rakefile +15 -0
  5. data/SPEC +3 -5
  6. data/lib/rack.rb +0 -12
  7. data/lib/rack/auth/abstract/request.rb +1 -5
  8. data/lib/rack/auth/basic.rb +1 -1
  9. data/lib/rack/auth/digest/nonce.rb +1 -1
  10. data/lib/rack/backports/uri/common_18.rb +28 -14
  11. data/lib/rack/backports/uri/common_192.rb +17 -14
  12. data/lib/rack/body_proxy.rb +0 -10
  13. data/lib/rack/builder.rb +26 -18
  14. data/lib/rack/cascade.rb +1 -12
  15. data/lib/rack/chunked.rb +2 -0
  16. data/lib/rack/content_type.rb +7 -1
  17. data/lib/rack/deflater.rb +1 -5
  18. data/lib/rack/directory.rb +5 -1
  19. data/lib/rack/file.rb +26 -9
  20. data/lib/rack/handler.rb +2 -2
  21. data/lib/rack/head.rb +0 -1
  22. data/lib/rack/lint.rb +3 -5
  23. data/lib/rack/methodoverride.rb +10 -4
  24. data/lib/rack/mime.rb +606 -171
  25. data/lib/rack/mock.rb +2 -1
  26. data/lib/rack/multipart.rb +2 -2
  27. data/lib/rack/multipart/parser.rb +3 -10
  28. data/lib/rack/reloader.rb +1 -1
  29. data/lib/rack/request.rb +45 -13
  30. data/lib/rack/response.rb +15 -14
  31. data/lib/rack/sendfile.rb +8 -6
  32. data/lib/rack/server.rb +4 -30
  33. data/lib/rack/session/abstract/id.rb +25 -6
  34. data/lib/rack/session/cookie.rb +12 -16
  35. data/lib/rack/static.rb +21 -8
  36. data/lib/rack/urlmap.rb +28 -13
  37. data/lib/rack/utils.rb +22 -28
  38. data/rack.gemspec +5 -5
  39. data/test/builder/end.ru +2 -0
  40. data/test/cgi/lighttpd.conf +1 -0
  41. data/test/cgi/sample_rackup.ru +1 -1
  42. data/test/cgi/test+directory/test+file +1 -0
  43. data/test/cgi/test.ru +1 -1
  44. data/test/gemloader.rb +6 -2
  45. data/test/spec_auth_basic.rb +4 -9
  46. data/test/spec_auth_digest.rb +3 -16
  47. data/test/spec_body_proxy.rb +0 -4
  48. data/test/spec_builder.rb +63 -20
  49. data/test/spec_cascade.rb +10 -13
  50. data/test/spec_cgi.rb +1 -1
  51. data/test/spec_chunked.rb +39 -12
  52. data/test/spec_commonlogger.rb +4 -3
  53. data/test/spec_conditionalget.rb +16 -12
  54. data/test/spec_content_length.rb +1 -1
  55. data/test/spec_content_type.rb +6 -0
  56. data/test/spec_deflater.rb +2 -2
  57. data/test/spec_directory.rb +12 -0
  58. data/test/spec_fastcgi.rb +1 -1
  59. data/test/spec_file.rb +58 -8
  60. data/test/spec_head.rb +6 -18
  61. data/test/spec_lint.rb +2 -2
  62. data/test/spec_methodoverride.rb +15 -0
  63. data/test/spec_mock.rb +6 -2
  64. data/test/spec_mongrel.rb +8 -8
  65. data/test/spec_multipart.rb +10 -63
  66. data/test/spec_request.rb +94 -21
  67. data/test/spec_response.rb +22 -24
  68. data/test/spec_sendfile.rb +3 -0
  69. data/test/spec_server.rb +2 -49
  70. data/test/spec_session_cookie.rb +58 -22
  71. data/test/spec_session_memcache.rb +31 -1
  72. data/test/spec_session_pool.rb +10 -4
  73. data/test/spec_static.rb +8 -0
  74. data/test/spec_thin.rb +2 -2
  75. data/test/spec_utils.rb +38 -35
  76. data/test/spec_webrick.rb +5 -3
  77. data/test/static/index.html +1 -0
  78. metadata +13 -18
  79. data/contrib/rack.png +0 -0
  80. data/contrib/rack.svg +0 -150
  81. data/lib/rack/backports/uri/common_193.rb +0 -29
  82. data/test/builder/line.ru +0 -1
  83. data/test/spec_auth.rb +0 -57
data/COPYING CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012 Christian Neukirchen <purl.org/net/chneukirchen>
1
+ Copyright (c) 2007, 2008, 2009, 2010 Christian Neukirchen <purl.org/net/chneukirchen>
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to
@@ -1,12 +1,3 @@
1
- = Known issues with Rack and ECMA-262
2
-
3
- * Many users expect the escape() function defined in ECMA-262 to be compatible
4
- with URI. Confusion is especially strong because the documentation for the
5
- escape function includes a reference to the URI specifications. ECMA-262
6
- escape is not however a URI escape function, it is a javascript escape
7
- function, and is not fully compatible. Most notably, for characters outside of
8
- the BMP. Users should use the more correct encodeURI functions.
9
-
10
1
  = Known issues with Rack and Web servers
11
2
 
12
3
  * Lighttpd sets wrong SCRIPT_NAME and PATH_INFO if you mount your
@@ -1,4 +1,4 @@
1
- = Rack, a modular Ruby webserver interface {<img src="https://secure.travis-ci.org/rack/rack.png" alt="Build Status" />}[http://travis-ci.org/rack/rack] {<img src="https://gemnasium.com/rack/rack.png" alt="Dependency Status" />}[https://gemnasium.com/rack/rack]
1
+ = Rack, a modular Ruby webserver interface
2
2
 
3
3
  Rack provides a minimal, modular and adaptable interface for developing
4
4
  web applications in Ruby. By wrapping HTTP requests and responses in
@@ -27,11 +27,8 @@ These web servers include Rack handlers in their distributions:
27
27
  * Fuzed
28
28
  * Glassfish v3
29
29
  * Phusion Passenger (which is mod_rack for Apache and for nginx)
30
- * Puma
31
30
  * Rainbows!
32
31
  * Unicorn
33
- * unixrack
34
- * uWSGI
35
32
  * Zbatery
36
33
 
37
34
  Any valid Rack app will run the same on all these handlers, without
@@ -135,11 +132,7 @@ at my site:
135
132
 
136
133
  Testing Rack requires the bacon testing framework:
137
134
 
138
- bundle install --without extra # to be able to run the fast tests
139
-
140
- Or:
141
-
142
- bundle install # this assumes that you have installed native extensions!
135
+ gem install bacon
143
136
 
144
137
  There are two rake-based test tasks:
145
138
 
@@ -362,7 +355,7 @@ run on port 11211) and memcache-client installed.
362
355
  * July 16, 2011: Sixteenth public release 1.3.2
363
356
  * Fix for Rails and rack-test, Rack::Utils#escape calls to_s
364
357
 
365
- * September 16, 2011: Seventeenth public release 1.3.3
358
+ * Not Yet Released: Seventeenth public release 1.3.3
366
359
  * Fix bug with broken query parameters in Rack::ShowExceptions
367
360
  * Rack::Request#cookies no longer swallows exceptions on broken input
368
361
  * Prevents XSS attacks enabled by bug in Ruby 1.8's regexp engine
@@ -380,10 +373,6 @@ run on port 11211) and memcache-client installed.
380
373
  * October 17, 2011: Twentieth public release 1.3.5
381
374
  * Fix annoying warnings caused by the backport in 1.3.4
382
375
 
383
- * December 28th, 2011: Twenty first public release: 1.1.3.
384
- * Security fix. http://www.ocert.org/advisories/ocert-2011-003.html
385
- Further information here: http://jruby.org/2011/12/27/jruby-1-6-5-1
386
-
387
376
  * December 28th, 2011: Twenty fourth public release 1.4.0
388
377
  * Ruby 1.8.6 support has officially been dropped. Not all tests pass.
389
378
  * Raise sane error messages for broken config.ru
@@ -403,114 +392,11 @@ run on port 11211) and memcache-client installed.
403
392
  * Support added for HTTP_X_FORWARDED_SCHEME
404
393
  * Numerous bug fixes, including many fixes for new and alternate rubies
405
394
 
406
- * January 22nd, 2012: Twenty fifth public release 1.4.1
407
- * Alter the keyspace limit calculations to reduce issues with nested params
408
- * Add a workaround for multipart parsing where files contain unescaped "%"
409
- * Added Rack::Response::Helpers#method_not_allowed? (code 405)
410
- * Rack::File now returns 404 for illegal directory traversals
411
- * Rack::File now returns 405 for illegal methods (non HEAD/GET)
412
- * Rack::Cascade now catches 405 by default, as well as 404
413
- * Cookies missing '--' no longer cause an exception to be raised
414
- * Various style changes and documentation spelling errors
415
- * Rack::BodyProxy always ensures to execute its block
416
- * Additional test coverage around cookies and secrets
417
- * Rack::Session::Cookie can now be supplied either secret or old_secret
418
- * Tests are no longer dependent on set order
419
- * Rack::Static no longer defaults to serving index files
420
- * Rack.release was fixed
421
-
422
- * January 6th, 2013: Twenty sixth public release 1.1.4
423
- * Add warnings when users do not provide a session secret
424
-
425
- * January 6th, 2013: Twenty seventh public release 1.2.6
426
- * Add warnings when users do not provide a session secret
427
- * Fix parsing performance for unquoted filenames
428
-
429
- * January 6th, 2013: Twenty eighth public release 1.3.7
430
- * Add warnings when users do not provide a session secret
431
- * Fix parsing performance for unquoted filenames
432
- * Updated URI backports
433
- * Fix URI backport version matching, and silence constant warnings
434
- * Correct parameter parsing with empty values
435
- * Correct rackup '-I' flag, to allow multiple uses
436
- * Correct rackup pidfile handling
437
- * Report rackup line numbers correctly
438
- * Fix request loops caused by non-stale nonces with time limits
439
- * Fix reloader on Windows
440
- * Prevent infinite recursions from Response#to_ary
441
- * Various middleware better conforms to the body close specification
442
- * Updated language for the body close specification
443
- * Additional notes regarding ECMA escape compatibility issues
444
- * Fix the parsing of multiple ranges in range headers
445
-
446
- * January 6th, 2013: Twenty ninth public release 1.4.2
447
- * Add warnings when users do not provide a session secret
448
- * Fix parsing performance for unquoted filenames
449
- * Updated URI backports
450
- * Fix URI backport version matching, and silence constant warnings
451
- * Correct parameter parsing with empty values
452
- * Correct rackup '-I' flag, to allow multiple uses
453
- * Correct rackup pidfile handling
454
- * Report rackup line numbers correctly
455
- * Fix request loops caused by non-stale nonces with time limits
456
- * Fix reloader on Windows
457
- * Prevent infinite recursions from Response#to_ary
458
- * Various middleware better conforms to the body close specification
459
- * Updated language for the body close specification
460
- * Additional notes regarding ECMA escape compatibility issues
461
- * Fix the parsing of multiple ranges in range headers
462
- * Prevent errors from empty parameter keys
463
- * Added PATCH verb to Rack::Request
464
- * Various documentation updates
465
- * Fix session merge semantics (fixes rack-test)
466
- * Rack::Static :index can now handle multiple directories
467
- * All tests now utilize Rack::Lint (special thanks to Lars Gierth)
468
- * Rack::File cache_control parameter is now deprecated, and removed by 1.5
469
- * Correct Rack::Directory script name escaping
470
- * Rack::Static supports header rules for sophisticated configurations
471
- * Multipart parsing now works without a Content-Length header
472
- * New logos courtesy of Zachary Scott!
473
- * Rack::BodyProxy now explicitly defines #each, useful for C extensions
474
- * Cookies that are not URI escaped no longer cause exceptions
475
-
476
- * January 7th, 2013: Thirtieth public release 1.3.8
477
- * Security: Prevent unbounded reads in large multipart boundaries
478
-
479
- * January 7th, 2013: Thirty first public release 1.4.3
480
- * Security: Prevent unbounded reads in large multipart boundaries
481
-
482
- * January 13th, 2013: Thirty second public release 1.4.4, 1.3.9, 1.2.7, 1.1.5
483
- * [SEC] Rack::Auth::AbstractRequest no longer symbolizes arbitrary strings
484
- * Fixed erroneous test case in the 1.3.x series
485
-
486
- * February 7th, Thirty fifth public release 1.1.6, 1.2.8, 1.3.10
487
- * Fix CVE-2013-0263, timing attack against Rack::Session::Cookie
488
-
489
- * February 7th, Thirty fifth public release 1.4.5
490
- * Fix CVE-2013-0263, timing attack against Rack::Session::Cookie
491
- * Fix CVE-2013-0262, symlink path traversal in Rack::File
492
-
493
- * February 7th, Thirty fifth public release 1.5.2
494
- * Fix CVE-2013-0263, timing attack against Rack::Session::Cookie
495
- * Fix CVE-2013-0262, symlink path traversal in Rack::File
496
- * Add various methods to Session for enhanced Rails compatibility
497
- * Request#trusted_proxy? now only matches whole stirngs
498
- * Add JSON cookie coder, to be default in Rack 1.6+ due to security concerns
499
- * URLMap host matching in environments that don't set the Host header fixed
500
- * Fix a race condition that could result in overwritten pidfiles
501
- * Various documentation additions
502
-
503
395
  == Contact
504
396
 
505
397
  Please post bugs, suggestions and patches to
506
398
  the bug tracker at <http://github.com/rack/rack/issues>.
507
399
 
508
- Please post security related bugs and suggestions to the core team at
509
- <https://groups.google.com/group/rack-core> or rack-core@googlegroups.com. Due
510
- to wide usage of the library, it is strongly preferred that we manage timing in
511
- order to provide viable patches at the time of disclosure. Your assistance in
512
- this matter is greatly appreciated.
513
-
514
400
  Mailing list archives are available at
515
401
  <http://groups.google.com/group/rack-devel>.
516
402
 
@@ -586,7 +472,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
586
472
 
587
473
  == Links
588
474
 
589
- Rack:: <http://rack.github.com/>
475
+ Rack:: <http://rack.rubyforge.org/>
590
476
  Official Rack repositories:: <http://github.com/rack>
591
477
  Rack Bug Tracking:: <http://github.com/rack/rack/issues>
592
478
  rack-devel mailing list:: <http://groups.google.com/group/rack-devel>
data/Rakefile CHANGED
@@ -3,6 +3,18 @@
3
3
  desc "Run all the tests"
4
4
  task :default => [:test]
5
5
 
6
+ desc "Install gem dependencies"
7
+ task :deps do
8
+ require 'rubygems'
9
+ spec = Gem::Specification.load('rack.gemspec')
10
+ spec.dependencies.each do |dep|
11
+ reqs = dep.requirements_list
12
+ reqs = (["-v"] * reqs.size).zip(reqs).flatten
13
+ # Use system over sh, because we want to ignore errors!
14
+ system "gem", "install", '--conservative', dep.name, *reqs
15
+ end
16
+ end
17
+
6
18
  desc "Make an archive as .tar.gz"
7
19
  task :dist => [:chmod, :changelog, :rdoc, "SPEC"] do
8
20
  sh "git archive --format=tar --prefix=#{release}/ HEAD^{tree} >#{release}.tar"
@@ -73,6 +85,9 @@ task :test => 'SPEC' do
73
85
  sh "bacon -I./lib:./test #{opts} #{specopts}"
74
86
  end
75
87
 
88
+ desc "Run all the tests we run on CI"
89
+ task :ci => :test
90
+
76
91
  desc "Run all the tests"
77
92
  task :fulltest => %w[SPEC chmod] do
78
93
  opts = ENV['TEST'] || '-a'
data/SPEC CHANGED
@@ -146,19 +146,17 @@ consisting of lines (for multiple header values, e.g. multiple
146
146
  The lines must not contain characters below 037.
147
147
  === The Content-Type
148
148
  There must be a <tt>Content-Type</tt>, except when the
149
- +Status+ is 1xx, 204 or 304, in which case there must be none
149
+ +Status+ is 1xx, 204, 205 or 304, in which case there must be none
150
150
  given.
151
151
  === The Content-Length
152
152
  There must not be a <tt>Content-Length</tt> header when the
153
- +Status+ is 1xx, 204 or 304.
153
+ +Status+ is 1xx, 204, 205 or 304.
154
154
  === The Body
155
155
  The Body must respond to +each+
156
156
  and must only yield String values.
157
157
  The Body itself should not be an instance of String, as this will
158
158
  break in Ruby 1.9.
159
- If the Body responds to +close+, it will be called after iteration. If
160
- the body is replaced by a middleware after action, the original body
161
- must be closed first, if it repsonds to close.
159
+ If the Body responds to +close+, it will be called after iteration.
162
160
  If the Body responds to +to_path+, it must return a String
163
161
  identifying the location of a file whose contents are identical
164
162
  to that produced by calling +each+; this may be used by the
@@ -73,18 +73,6 @@ module Rack
73
73
  autoload :Params, "rack/auth/digest/params"
74
74
  autoload :Request, "rack/auth/digest/request"
75
75
  end
76
-
77
- # Not all of the following schemes are "standards", but they are used often.
78
- @schemes = %w[basic digest bearer mac token oauth oauth2]
79
-
80
- def self.add_scheme scheme
81
- @schemes << scheme
82
- @schemes.uniq!
83
- end
84
-
85
- def self.schemes
86
- @schemes.dup
87
- end
88
76
  end
89
77
 
90
78
  module Session
@@ -21,11 +21,7 @@ module Rack
21
21
  end
22
22
 
23
23
  def scheme
24
- @scheme ||=
25
- begin
26
- s = parts.first.downcase
27
- Rack::Auth.schemes.include?(s) ? s.to_sym : s
28
- end
24
+ @scheme ||= parts.first.downcase.to_sym
29
25
  end
30
26
 
31
27
  def params
@@ -41,7 +41,7 @@ module Rack
41
41
 
42
42
  class Request < Auth::AbstractRequest
43
43
  def basic?
44
- !parts.first.nil? && :basic == scheme
44
+ :basic == scheme
45
45
  end
46
46
 
47
47
  def credentials
@@ -38,7 +38,7 @@ module Rack
38
38
  end
39
39
 
40
40
  def stale?
41
- !self.class.time_limit.nil? && (Time.now.to_i - @timestamp) > self.class.time_limit
41
+ !self.class.time_limit.nil? && (@timestamp - Time.now.to_i) < self.class.time_limit
42
42
  end
43
43
 
44
44
  def fresh?
@@ -8,21 +8,7 @@
8
8
 
9
9
  module URI
10
10
  TBLENCWWWCOMP_ = {} # :nodoc:
11
- 256.times do |i|
12
- TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
13
- end
14
- TBLENCWWWCOMP_[' '] = '+'
15
- TBLENCWWWCOMP_.freeze
16
11
  TBLDECWWWCOMP_ = {} # :nodoc:
17
- 256.times do |i|
18
- h, l = i>>4, i&15
19
- TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
20
- TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
21
- TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
22
- TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
23
- end
24
- TBLDECWWWCOMP_['+'] = ' '
25
- TBLDECWWWCOMP_.freeze
26
12
 
27
13
  # Encode given +s+ to URL-encoded form data.
28
14
  #
@@ -40,6 +26,18 @@ module URI
40
26
  '%' + $1.unpack('H2' * Rack::Utils.bytesize($1)).join('%').upcase
41
27
  end.tr(' ', '+')
42
28
  else
29
+ if TBLENCWWWCOMP_.empty?
30
+ tbl = {}
31
+ 256.times do |i|
32
+ tbl[i.chr] = '%%%02X' % i
33
+ end
34
+ tbl[' '] = '+'
35
+ begin
36
+ TBLENCWWWCOMP_.replace(tbl)
37
+ TBLENCWWWCOMP_.freeze
38
+ rescue
39
+ end
40
+ end
43
41
  str.gsub(/[^*\-.0-9A-Z_a-z]/) {|m| TBLENCWWWCOMP_[m]}
44
42
  end
45
43
  end
@@ -50,6 +48,22 @@ module URI
50
48
  #
51
49
  # See URI.encode_www_form_component, URI.decode_www_form
52
50
  def self.decode_www_form_component(str, enc=nil)
51
+ if TBLDECWWWCOMP_.empty?
52
+ tbl = {}
53
+ 256.times do |i|
54
+ h, l = i>>4, i&15
55
+ tbl['%%%X%X' % [h, l]] = i.chr
56
+ tbl['%%%x%X' % [h, l]] = i.chr
57
+ tbl['%%%X%x' % [h, l]] = i.chr
58
+ tbl['%%%x%x' % [h, l]] = i.chr
59
+ end
60
+ tbl['+'] = ' '
61
+ begin
62
+ TBLDECWWWCOMP_.replace(tbl)
63
+ TBLDECWWWCOMP_.freeze
64
+ rescue
65
+ end
66
+ end
53
67
  raise ArgumentError, "invalid %-encoding (#{str})" unless /\A(?:%[0-9a-fA-F]{2}|[^%])*\z/ =~ str
54
68
  str.gsub(/\+|%[0-9a-fA-F]{2}/) {|m| TBLDECWWWCOMP_[m]}
55
69
  end
@@ -17,19 +17,6 @@
17
17
  require 'uri/common'
18
18
 
19
19
  module URI
20
- TBLDECWWWCOMP_ = {} unless const_defined?(:TBLDECWWWCOMP_) #:nodoc:
21
- if TBLDECWWWCOMP_.empty?
22
- 256.times do |i|
23
- h, l = i>>4, i&15
24
- TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
25
- TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
26
- TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
27
- TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
28
- end
29
- TBLDECWWWCOMP_['+'] = ' '
30
- TBLDECWWWCOMP_.freeze
31
- end
32
-
33
20
  def self.decode_www_form(str, enc=Encoding::UTF_8)
34
21
  return [] if str.empty?
35
22
  unless /\A#{WFKV_}=#{WFKV_}(?:[;&]#{WFKV_}=#{WFKV_})*\z/o =~ str
@@ -43,10 +30,26 @@ module URI
43
30
  end
44
31
 
45
32
  def self.decode_www_form_component(str, enc=Encoding::UTF_8)
33
+ if TBLDECWWWCOMP_.empty?
34
+ tbl = {}
35
+ 256.times do |i|
36
+ h, l = i>>4, i&15
37
+ tbl['%%%X%X' % [h, l]] = i.chr
38
+ tbl['%%%x%X' % [h, l]] = i.chr
39
+ tbl['%%%X%x' % [h, l]] = i.chr
40
+ tbl['%%%x%x' % [h, l]] = i.chr
41
+ end
42
+ tbl['+'] = ' '
43
+ begin
44
+ TBLDECWWWCOMP_.replace(tbl)
45
+ TBLDECWWWCOMP_.freeze
46
+ rescue
47
+ end
48
+ end
46
49
  raise ArgumentError, "invalid %-encoding (#{str})" unless /\A[^%]*(?:%\h\h[^%]*)*\z/ =~ str
47
50
  str.gsub(/\+|%\h\h/, TBLDECWWWCOMP_).force_encoding(enc)
48
51
  end
49
52
 
50
- remove_const :WFKV_ if const_defined?(:WFKV_)
53
+ remove_const :WFKV_
51
54
  WFKV_ = '(?:[^%#=;&]*(?:%\h\h[^%#=;&]*)*)' # :nodoc:
52
55
  end
@@ -5,7 +5,6 @@ module Rack
5
5
  end
6
6
 
7
7
  def respond_to?(*args)
8
- return false if args.first.to_s =~ /^to_ary$/
9
8
  super or @body.respond_to?(*args)
10
9
  end
11
10
 
@@ -20,16 +19,7 @@ module Rack
20
19
  @closed
21
20
  end
22
21
 
23
- # N.B. This method is a special case to address the bug described by #434.
24
- # We are applying this special case for #each only. Future bugs of this
25
- # class will be handled by requesting users to patch their ruby
26
- # implementation, to save adding too many methods in this class.
27
- def each(*args, &block)
28
- @body.each(*args, &block)
29
- end
30
-
31
22
  def method_missing(*args, &block)
32
- super if args.first.to_s =~ /^to_ary$/
33
23
  @body.__send__(*args, &block)
34
24
  end
35
25
  end
@@ -20,7 +20,7 @@ module Rack
20
20
  #
21
21
  # app = Rack::Builder.app do
22
22
  # use Rack::CommonLogger
23
- # lambda { |env| [200, {'Content-Type' => 'text/plain'}, 'OK'] }
23
+ # run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['OK']] }
24
24
  # end
25
25
  #
26
26
  # run app
@@ -36,9 +36,9 @@ module Rack
36
36
  if cfgfile[/^#\\(.*)/] && opts
37
37
  options = opts.parse! $1.split(/\s+/)
38
38
  end
39
- cfgfile.sub!(/^__END__\n.*/, '')
39
+ cfgfile.sub!(/^__END__\n.*\Z/m, '')
40
40
  app = eval "Rack::Builder.new {\n" + cfgfile + "\n}.to_app",
41
- TOPLEVEL_BINDING, config, 0
41
+ TOPLEVEL_BINDING, config
42
42
  else
43
43
  require config
44
44
  app = Object.const_get(::File.basename(config, '.rb').capitalize)
@@ -46,13 +46,13 @@ module Rack
46
46
  return app, options
47
47
  end
48
48
 
49
- def initialize(&block)
50
- @ins = []
49
+ def initialize(default_app = nil,&block)
50
+ @use, @map, @run = [], nil, default_app
51
51
  instance_eval(&block) if block_given?
52
52
  end
53
53
 
54
- def self.app(&block)
55
- self.new(&block).to_app
54
+ def self.app(default_app = nil, &block)
55
+ self.new(default_app, &block).to_app
56
56
  end
57
57
 
58
58
  # Specifies a middleware to use in a stack.
@@ -75,7 +75,11 @@ module Rack
75
75
  # The +call+ method in this example sets an additional environment key which then can be
76
76
  # referenced in the application if required.
77
77
  def use(middleware, *args, &block)
78
- @ins << lambda { |app| middleware.new(app, *args, &block) }
78
+ if @map
79
+ mapping, @map = @map, nil
80
+ @use << proc { |app| generate_map app, mapping }
81
+ end
82
+ @use << proc { |app| middleware.new(app, *args, &block) }
79
83
  end
80
84
 
81
85
  # Takes an argument that is an object that responds to #call and returns a Rack response.
@@ -93,7 +97,7 @@ module Rack
93
97
  #
94
98
  # run Heartbeat
95
99
  def run(app)
96
- @ins << app #lambda { |nothing| app }
100
+ @run = app
97
101
  end
98
102
 
99
103
  # Creates a route within the application.
@@ -116,22 +120,26 @@ module Rack
116
120
  # This example includes a piece of middleware which will run before requests hit +Heartbeat+.
117
121
  #
118
122
  def map(path, &block)
119
- if @ins.last.kind_of? Hash
120
- @ins.last[path] = self.class.new(&block).to_app
121
- else
122
- @ins << {}
123
- map(path, &block)
124
- end
123
+ @map ||= {}
124
+ @map[path] = block
125
125
  end
126
126
 
127
127
  def to_app
128
- @ins[-1] = Rack::URLMap.new(@ins.last) if Hash === @ins.last
129
- inner_app = @ins.last
130
- @ins[0...-1].reverse.inject(inner_app) { |a, e| e.call(a) }
128
+ app = @map ? generate_map(@run, @map) : @run
129
+ fail "missing run or map statement" unless app
130
+ @use.reverse.inject(app) { |a,e| e[a] }
131
131
  end
132
132
 
133
133
  def call(env)
134
134
  to_app.call(env)
135
135
  end
136
+
137
+ private
138
+
139
+ def generate_map(default_app, mapping)
140
+ mapped = default_app ? {'/' => default_app} : {}
141
+ mapping.each { |r,b| mapped[r] = self.class.new(default_app, &b) }
142
+ URLMap.new(mapped)
143
+ end
136
144
  end
137
145
  end