rack 2.1.0 → 3.1.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.

Potentially problematic release.


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

Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +377 -16
  3. data/CONTRIBUTING.md +144 -0
  4. data/MIT-LICENSE +1 -1
  5. data/README.md +328 -0
  6. data/SPEC.rdoc +365 -0
  7. data/lib/rack/auth/abstract/handler.rb +3 -1
  8. data/lib/rack/auth/abstract/request.rb +2 -2
  9. data/lib/rack/auth/basic.rb +4 -7
  10. data/lib/rack/bad_request.rb +8 -0
  11. data/lib/rack/body_proxy.rb +34 -12
  12. data/lib/rack/builder.rb +162 -59
  13. data/lib/rack/cascade.rb +24 -10
  14. data/lib/rack/common_logger.rb +43 -28
  15. data/lib/rack/conditional_get.rb +30 -25
  16. data/lib/rack/constants.rb +66 -0
  17. data/lib/rack/content_length.rb +10 -16
  18. data/lib/rack/content_type.rb +9 -7
  19. data/lib/rack/deflater.rb +78 -50
  20. data/lib/rack/directory.rb +86 -63
  21. data/lib/rack/etag.rb +14 -22
  22. data/lib/rack/events.rb +18 -17
  23. data/lib/rack/files.rb +99 -61
  24. data/lib/rack/head.rb +8 -9
  25. data/lib/rack/headers.rb +238 -0
  26. data/lib/rack/lint.rb +868 -642
  27. data/lib/rack/lock.rb +2 -6
  28. data/lib/rack/logger.rb +3 -0
  29. data/lib/rack/media_type.rb +9 -4
  30. data/lib/rack/method_override.rb +6 -2
  31. data/lib/rack/mime.rb +14 -5
  32. data/lib/rack/mock.rb +1 -253
  33. data/lib/rack/mock_request.rb +171 -0
  34. data/lib/rack/mock_response.rb +124 -0
  35. data/lib/rack/multipart/generator.rb +15 -8
  36. data/lib/rack/multipart/parser.rb +238 -107
  37. data/lib/rack/multipart/uploaded_file.rb +17 -7
  38. data/lib/rack/multipart.rb +54 -42
  39. data/lib/rack/null_logger.rb +9 -0
  40. data/lib/rack/query_parser.rb +87 -105
  41. data/lib/rack/recursive.rb +3 -1
  42. data/lib/rack/reloader.rb +0 -4
  43. data/lib/rack/request.rb +366 -135
  44. data/lib/rack/response.rb +186 -68
  45. data/lib/rack/rewindable_input.rb +24 -6
  46. data/lib/rack/runtime.rb +8 -7
  47. data/lib/rack/sendfile.rb +29 -27
  48. data/lib/rack/show_exceptions.rb +27 -12
  49. data/lib/rack/show_status.rb +21 -13
  50. data/lib/rack/static.rb +19 -12
  51. data/lib/rack/tempfile_reaper.rb +14 -5
  52. data/lib/rack/urlmap.rb +5 -6
  53. data/lib/rack/utils.rb +274 -260
  54. data/lib/rack/version.rb +21 -0
  55. data/lib/rack.rb +18 -103
  56. metadata +25 -52
  57. data/README.rdoc +0 -262
  58. data/Rakefile +0 -123
  59. data/SPEC +0 -263
  60. data/bin/rackup +0 -5
  61. data/contrib/rack.png +0 -0
  62. data/contrib/rack.svg +0 -150
  63. data/contrib/rack_logo.svg +0 -164
  64. data/contrib/rdoc.css +0 -412
  65. data/example/lobster.ru +0 -6
  66. data/example/protectedlobster.rb +0 -16
  67. data/example/protectedlobster.ru +0 -10
  68. data/lib/rack/auth/digest/md5.rb +0 -131
  69. data/lib/rack/auth/digest/nonce.rb +0 -54
  70. data/lib/rack/auth/digest/params.rb +0 -54
  71. data/lib/rack/auth/digest/request.rb +0 -43
  72. data/lib/rack/chunked.rb +0 -92
  73. data/lib/rack/core_ext/regexp.rb +0 -14
  74. data/lib/rack/file.rb +0 -8
  75. data/lib/rack/handler/cgi.rb +0 -62
  76. data/lib/rack/handler/fastcgi.rb +0 -102
  77. data/lib/rack/handler/lsws.rb +0 -63
  78. data/lib/rack/handler/scgi.rb +0 -73
  79. data/lib/rack/handler/thin.rb +0 -38
  80. data/lib/rack/handler/webrick.rb +0 -122
  81. data/lib/rack/handler.rb +0 -104
  82. data/lib/rack/lobster.rb +0 -72
  83. data/lib/rack/server.rb +0 -467
  84. data/lib/rack/session/abstract/id.rb +0 -528
  85. data/lib/rack/session/cookie.rb +0 -205
  86. data/lib/rack/session/memcache.rb +0 -10
  87. data/lib/rack/session/pool.rb +0 -85
  88. data/rack.gemspec +0 -44
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'ostruct'
4
3
  require 'erb'
5
- require 'rack/request'
6
- require 'rack/utils'
4
+
5
+ require_relative 'constants'
6
+ require_relative 'utils'
7
+ require_relative 'request'
7
8
 
8
9
  module Rack
9
10
  # Rack::ShowExceptions catches all exceptions raised from the app it
@@ -17,6 +18,11 @@ module Rack
17
18
  class ShowExceptions
18
19
  CONTEXT = 7
19
20
 
21
+ Frame = Struct.new(:filename, :lineno, :function,
22
+ :pre_context_lineno, :pre_context,
23
+ :context_line, :post_context_lineno,
24
+ :post_context)
25
+
20
26
  def initialize(app)
21
27
  @app = app
22
28
  end
@@ -57,7 +63,12 @@ module Rack
57
63
  private :accepts_html?
58
64
 
59
65
  def dump_exception(exception)
60
- string = "#{exception.class}: #{exception.message}\n".dup
66
+ if exception.respond_to?(:detailed_message)
67
+ message = exception.detailed_message(highlight: false)
68
+ else
69
+ message = exception.message
70
+ end
71
+ string = "#{exception.class}: #{message}\n".dup
61
72
  string << exception.backtrace.map { |l| "\t#{l}" }.join("\n")
62
73
  string
63
74
  end
@@ -65,14 +76,14 @@ module Rack
65
76
  def pretty(env, exception)
66
77
  req = Rack::Request.new(env)
67
78
 
68
- # This double assignment is to prevent an "unused variable" warning on
69
- # Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me.
79
+ # This double assignment is to prevent an "unused variable" warning.
80
+ # Yes, it is dumb, but I don't like Ruby yelling at me.
70
81
  path = path = (req.script_name + req.path_info).squeeze("/")
71
82
 
72
- # This double assignment is to prevent an "unused variable" warning on
73
- # Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me.
83
+ # This double assignment is to prevent an "unused variable" warning.
84
+ # Yes, it is dumb, but I don't like Ruby yelling at me.
74
85
  frames = frames = exception.backtrace.map { |line|
75
- frame = OpenStruct.new
86
+ frame = Frame.new
76
87
  if line =~ /(.*?):(\d+)(:in `(.*)')?/
77
88
  frame.filename = $1
78
89
  frame.lineno = $2.to_i
@@ -161,7 +172,7 @@ module Rack
161
172
  div.commands { margin-left: 40px; }
162
173
  div.commands a { color:black; text-decoration:none; }
163
174
  #summary { background: #ffc; }
164
- #summary h2 { font-weight: normal; color: #666; }
175
+ #summary h2 { font-family: monospace; font-weight: normal; color: #666; white-space: pre-wrap; }
165
176
  #summary ul#quicklinks { list-style-type: none; margin-bottom: 2em; }
166
177
  #summary ul#quicklinks li { float: left; padding: 0 1em; }
167
178
  #summary ul#quicklinks>li+li { border-left: 1px #666 solid; }
@@ -229,7 +240,11 @@ module Rack
229
240
 
230
241
  <div id="summary">
231
242
  <h1><%=h exception.class %> at <%=h path %></h1>
243
+ <% if exception.respond_to?(:detailed_message) %>
244
+ <h2><%=h exception.detailed_message(highlight: false) %></h2>
245
+ <% else %>
232
246
  <h2><%=h exception.message %></h2>
247
+ <% end %>
233
248
  <table><tr>
234
249
  <th>Ruby</th>
235
250
  <td>
@@ -313,7 +328,7 @@ module Rack
313
328
  <% end %>
314
329
 
315
330
  <h3 id="post-info">POST</h3>
316
- <% if req.POST and not req.POST.empty? %>
331
+ <% if ((req.POST and not req.POST.empty?) rescue (no_post_data = "Invalid POST data"; nil)) %>
317
332
  <table class="req">
318
333
  <thead>
319
334
  <tr>
@@ -331,7 +346,7 @@ module Rack
331
346
  </tbody>
332
347
  </table>
333
348
  <% else %>
334
- <p>No POST data.</p>
349
+ <p><%= no_post_data || "No POST data" %>.</p>
335
350
  <% end %>
336
351
 
337
352
 
@@ -1,8 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'erb'
4
- require 'rack/request'
5
- require 'rack/utils'
4
+
5
+ require_relative 'constants'
6
+ require_relative 'utils'
7
+ require_relative 'request'
8
+ require_relative 'body_proxy'
6
9
 
7
10
  module Rack
8
11
  # Rack::ShowStatus catches all empty responses and replaces them
@@ -19,28 +22,33 @@ module Rack
19
22
  end
20
23
 
21
24
  def call(env)
22
- status, headers, body = @app.call(env)
23
- headers = Utils::HeaderHash.new(headers)
25
+ status, headers, body = response = @app.call(env)
24
26
  empty = headers[CONTENT_LENGTH].to_i <= 0
25
27
 
26
28
  # client or server error, or explicit message
27
29
  if (status.to_i >= 400 && empty) || env[RACK_SHOWSTATUS_DETAIL]
28
- # This double assignment is to prevent an "unused variable" warning on
29
- # Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me.
30
+ # This double assignment is to prevent an "unused variable" warning.
31
+ # Yes, it is dumb, but I don't like Ruby yelling at me.
30
32
  req = req = Rack::Request.new(env)
31
33
 
32
34
  message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s
33
35
 
34
- # This double assignment is to prevent an "unused variable" warning on
35
- # Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me.
36
+ # This double assignment is to prevent an "unused variable" warning.
37
+ # Yes, it is dumb, but I don't like Ruby yelling at me.
36
38
  detail = detail = env[RACK_SHOWSTATUS_DETAIL] || message
37
39
 
38
- body = @template.result(binding)
39
- size = body.bytesize
40
- [status, headers.merge(CONTENT_TYPE => "text/html", CONTENT_LENGTH => size.to_s), [body]]
41
- else
42
- [status, headers, body]
40
+ html = @template.result(binding)
41
+ size = html.bytesize
42
+
43
+ response[2] = Rack::BodyProxy.new([html]) do
44
+ body.close if body.respond_to?(:close)
45
+ end
46
+
47
+ headers[CONTENT_TYPE] = "text/html"
48
+ headers[CONTENT_LENGTH] = size.to_s
43
49
  end
50
+
51
+ response
44
52
  end
45
53
 
46
54
  def h(obj) # :nodoc:
data/lib/rack/static.rb CHANGED
@@ -1,9 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rack/files"
4
- require "rack/utils"
5
-
6
- require_relative 'core_ext/regexp'
3
+ require_relative 'constants'
4
+ require_relative 'files'
5
+ require_relative 'mime'
7
6
 
8
7
  module Rack
9
8
 
@@ -19,6 +18,11 @@ module Rack
19
18
  #
20
19
  # use Rack::Static, :urls => ["/media"]
21
20
  #
21
+ # Same as previous, but instead of returning 404 for missing files under
22
+ # /media, call the next middleware:
23
+ #
24
+ # use Rack::Static, :urls => ["/media"], :cascade => true
25
+ #
22
26
  # Serve all requests beginning with /css or /images from the folder "public"
23
27
  # in the current directory (ie public/css/* and public/images/*):
24
28
  #
@@ -78,21 +82,20 @@ module Rack
78
82
  # :header_rules => [
79
83
  # # Cache all static files in public caches (e.g. Rack::Cache)
80
84
  # # as well as in the browser
81
- # [:all, {'Cache-Control' => 'public, max-age=31536000'}],
85
+ # [:all, {'cache-control' => 'public, max-age=31536000'}],
82
86
  #
83
87
  # # Provide web fonts with cross-origin access-control-headers
84
88
  # # Firefox requires this when serving assets using a Content Delivery Network
85
- # [:fonts, {'Access-Control-Allow-Origin' => '*'}]
89
+ # [:fonts, {'access-control-allow-origin' => '*'}]
86
90
  # ]
87
91
  #
88
92
  class Static
89
- using ::Rack::RegexpExtensions
90
-
91
93
  def initialize(app, options = {})
92
94
  @app = app
93
95
  @urls = options[:urls] || ["/favicon.ico"]
94
96
  @index = options[:index]
95
97
  @gzip = options[:gzip]
98
+ @cascade = options[:cascade]
96
99
  root = options[:root] || Dir.pwd
97
100
 
98
101
  # HTTP Headers
@@ -133,17 +136,21 @@ module Rack
133
136
 
134
137
  if response[0] == 404
135
138
  response = nil
139
+ elsif response[0] == 304
140
+ # Do nothing, leave headers as is
136
141
  else
137
- if mime_type = Mime.mime_type(::File.extname(path), 'text/plain')
138
- response[1][CONTENT_TYPE] = mime_type
139
- end
140
- response[1]['Content-Encoding'] = 'gzip'
142
+ response[1][CONTENT_TYPE] = Mime.mime_type(::File.extname(path), 'text/plain')
143
+ response[1]['content-encoding'] = 'gzip'
141
144
  end
142
145
  end
143
146
 
144
147
  path = env[PATH_INFO]
145
148
  response ||= @file_server.call(env)
146
149
 
150
+ if @cascade && response[0] == 404
151
+ return @app.call(env)
152
+ end
153
+
147
154
  headers = response[1]
148
155
  applicable_rules(path).each do |rule, new_headers|
149
156
  new_headers.each { |field, content| headers[field] = content }
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rack/body_proxy'
3
+ require_relative 'constants'
4
+ require_relative 'body_proxy'
4
5
 
5
6
  module Rack
6
7
 
@@ -14,11 +15,19 @@ module Rack
14
15
 
15
16
  def call(env)
16
17
  env[RACK_TEMPFILES] ||= []
17
- status, headers, body = @app.call(env)
18
- body_proxy = BodyProxy.new(body) do
19
- env[RACK_TEMPFILES].each(&:close!) unless env[RACK_TEMPFILES].nil?
18
+
19
+ begin
20
+ _, _, body = response = @app.call(env)
21
+ rescue Exception
22
+ env[RACK_TEMPFILES]&.each(&:close!)
23
+ raise
24
+ end
25
+
26
+ response[2] = BodyProxy.new(body) do
27
+ env[RACK_TEMPFILES]&.each(&:close!)
20
28
  end
21
- [status, headers, body_proxy]
29
+
30
+ response
22
31
  end
23
32
  end
24
33
  end
data/lib/rack/urlmap.rb CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'set'
4
4
 
5
+ require_relative 'constants'
6
+
5
7
  module Rack
6
8
  # Rack::URLMap takes a hash mapping urls or paths to apps, and
7
9
  # dispatches accordingly. Support for HTTP/1.1 host names exists if
@@ -16,9 +18,6 @@ module Rack
16
18
  # first, since they are most specific.
17
19
 
18
20
  class URLMap
19
- NEGATIVE_INFINITY = -1.0 / 0.0
20
- INFINITY = 1.0 / 0.0
21
-
22
21
  def initialize(map = {})
23
22
  remap(map)
24
23
  end
@@ -38,11 +37,11 @@ module Rack
38
37
  end
39
38
 
40
39
  location = location.chomp('/')
41
- match = Regexp.new("^#{Regexp.quote(location).gsub('/', '/+')}(.*)", nil, 'n')
40
+ match = Regexp.new("^#{Regexp.quote(location).gsub('/', '/+')}(.*)", Regexp::NOENCODING)
42
41
 
43
42
  [host, location, match, app]
44
43
  }.sort_by do |(host, location, _, _)|
45
- [host ? -host.size : INFINITY, -location.size]
44
+ [host ? -host.size : Float::INFINITY, -location.size]
46
45
  end
47
46
  end
48
47
 
@@ -77,7 +76,7 @@ module Rack
77
76
  return app.call(env)
78
77
  end
79
78
 
80
- [404, { CONTENT_TYPE => "text/plain", "X-Cascade" => "pass" }, ["Not Found: #{path}"]]
79
+ [404, { CONTENT_TYPE => "text/plain", "x-cascade" => "pass" }, ["Not Found: #{path}"]]
81
80
 
82
81
  ensure
83
82
  env[PATH_INFO] = path