rack 2.2.22 → 3.2.6

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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +588 -71
  3. data/CONTRIBUTING.md +63 -55
  4. data/MIT-LICENSE +1 -1
  5. data/README.md +384 -0
  6. data/SPEC.rdoc +243 -277
  7. data/lib/rack/auth/abstract/handler.rb +3 -1
  8. data/lib/rack/auth/abstract/request.rb +5 -1
  9. data/lib/rack/auth/basic.rb +1 -3
  10. data/lib/rack/bad_request.rb +8 -0
  11. data/lib/rack/body_proxy.rb +21 -3
  12. data/lib/rack/builder.rb +108 -69
  13. data/lib/rack/cascade.rb +2 -3
  14. data/lib/rack/common_logger.rb +22 -17
  15. data/lib/rack/conditional_get.rb +20 -16
  16. data/lib/rack/constants.rb +68 -0
  17. data/lib/rack/content_length.rb +12 -16
  18. data/lib/rack/content_type.rb +8 -5
  19. data/lib/rack/deflater.rb +40 -26
  20. data/lib/rack/directory.rb +10 -4
  21. data/lib/rack/etag.rb +17 -23
  22. data/lib/rack/events.rb +25 -6
  23. data/lib/rack/files.rb +16 -18
  24. data/lib/rack/head.rb +8 -8
  25. data/lib/rack/headers.rb +238 -0
  26. data/lib/rack/lint.rb +817 -648
  27. data/lib/rack/lock.rb +2 -5
  28. data/lib/rack/media_type.rb +6 -7
  29. data/lib/rack/method_override.rb +5 -1
  30. data/lib/rack/mime.rb +14 -5
  31. data/lib/rack/mock.rb +1 -300
  32. data/lib/rack/mock_request.rb +161 -0
  33. data/lib/rack/mock_response.rb +156 -0
  34. data/lib/rack/multipart/generator.rb +7 -5
  35. data/lib/rack/multipart/parser.rb +282 -101
  36. data/lib/rack/multipart/uploaded_file.rb +45 -4
  37. data/lib/rack/multipart.rb +53 -40
  38. data/lib/rack/null_logger.rb +9 -0
  39. data/lib/rack/query_parser.rb +116 -121
  40. data/lib/rack/recursive.rb +2 -0
  41. data/lib/rack/reloader.rb +0 -2
  42. data/lib/rack/request.rb +272 -144
  43. data/lib/rack/response.rb +151 -66
  44. data/lib/rack/rewindable_input.rb +27 -5
  45. data/lib/rack/runtime.rb +7 -6
  46. data/lib/rack/sendfile.rb +37 -32
  47. data/lib/rack/show_exceptions.rb +25 -6
  48. data/lib/rack/show_status.rb +17 -9
  49. data/lib/rack/static.rb +15 -11
  50. data/lib/rack/tempfile_reaper.rb +15 -4
  51. data/lib/rack/urlmap.rb +3 -1
  52. data/lib/rack/utils.rb +326 -244
  53. data/lib/rack/version.rb +3 -15
  54. data/lib/rack.rb +13 -90
  55. metadata +15 -41
  56. data/README.rdoc +0 -355
  57. data/Rakefile +0 -130
  58. data/bin/rackup +0 -5
  59. data/contrib/rack.png +0 -0
  60. data/contrib/rack.svg +0 -150
  61. data/contrib/rack_logo.svg +0 -164
  62. data/contrib/rdoc.css +0 -412
  63. data/example/lobster.ru +0 -6
  64. data/example/protectedlobster.rb +0 -16
  65. data/example/protectedlobster.ru +0 -10
  66. data/lib/rack/auth/digest/md5.rb +0 -131
  67. data/lib/rack/auth/digest/nonce.rb +0 -53
  68. data/lib/rack/auth/digest/params.rb +0 -54
  69. data/lib/rack/auth/digest/request.rb +0 -43
  70. data/lib/rack/chunked.rb +0 -117
  71. data/lib/rack/core_ext/regexp.rb +0 -14
  72. data/lib/rack/file.rb +0 -7
  73. data/lib/rack/handler/cgi.rb +0 -59
  74. data/lib/rack/handler/fastcgi.rb +0 -100
  75. data/lib/rack/handler/lsws.rb +0 -61
  76. data/lib/rack/handler/scgi.rb +0 -71
  77. data/lib/rack/handler/thin.rb +0 -34
  78. data/lib/rack/handler/webrick.rb +0 -129
  79. data/lib/rack/handler.rb +0 -104
  80. data/lib/rack/lobster.rb +0 -70
  81. data/lib/rack/logger.rb +0 -20
  82. data/lib/rack/server.rb +0 -466
  83. data/lib/rack/session/abstract/id.rb +0 -523
  84. data/lib/rack/session/cookie.rb +0 -203
  85. data/lib/rack/session/memcache.rb +0 -10
  86. data/lib/rack/session/pool.rb +0 -90
  87. data/rack.gemspec +0 -46
@@ -1,8 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'ostruct'
4
3
  require 'erb'
5
4
 
5
+ require_relative 'constants'
6
+ require_relative 'utils'
7
+ require_relative 'request'
8
+
6
9
  module Rack
7
10
  # Rack::ShowExceptions catches all exceptions raised from the app it
8
11
  # wraps. It shows a useful backtrace with the sourcefile and
@@ -15,6 +18,11 @@ module Rack
15
18
  class ShowExceptions
16
19
  CONTEXT = 7
17
20
 
21
+ Frame = Struct.new(:filename, :lineno, :function,
22
+ :pre_context_lineno, :pre_context,
23
+ :context_line, :post_context_lineno,
24
+ :post_context)
25
+
18
26
  def initialize(app)
19
27
  @app = app
20
28
  end
@@ -55,7 +63,16 @@ module Rack
55
63
  private :accepts_html?
56
64
 
57
65
  def dump_exception(exception)
58
- string = "#{exception.class}: #{exception.message}\n".dup
66
+ if exception.respond_to?(:detailed_message)
67
+ message = exception.detailed_message(highlight: false)
68
+ # :nocov:
69
+ # Ruby 3.2 added Exception#detailed_message, so the else
70
+ # branch cannot be hit on the current Ruby version.
71
+ else
72
+ message = exception.message
73
+ # :nocov:
74
+ end
75
+ string = "#{exception.class}: #{message}\n".dup
59
76
  string << exception.backtrace.map { |l| "\t#{l}" }.join("\n")
60
77
  string
61
78
  end
@@ -70,7 +87,7 @@ module Rack
70
87
  # This double assignment is to prevent an "unused variable" warning.
71
88
  # Yes, it is dumb, but I don't like Ruby yelling at me.
72
89
  frames = frames = exception.backtrace.map { |line|
73
- frame = OpenStruct.new
90
+ frame = Frame.new
74
91
  if line =~ /(.*?):(\d+)(:in `(.*)')?/
75
92
  frame.filename = $1
76
93
  frame.lineno = $2.to_i
@@ -159,7 +176,7 @@ module Rack
159
176
  div.commands { margin-left: 40px; }
160
177
  div.commands a { color:black; text-decoration:none; }
161
178
  #summary { background: #ffc; }
162
- #summary h2 { font-weight: normal; color: #666; }
179
+ #summary h2 { font-family: monospace; font-weight: normal; color: #666; white-space: pre-wrap; }
163
180
  #summary ul#quicklinks { list-style-type: none; margin-bottom: 2em; }
164
181
  #summary ul#quicklinks li { float: left; padding: 0 1em; }
165
182
  #summary ul#quicklinks>li+li { border-left: 1px #666 solid; }
@@ -227,7 +244,11 @@ module Rack
227
244
 
228
245
  <div id="summary">
229
246
  <h1><%=h exception.class %> at <%=h path %></h1>
247
+ <% if exception.respond_to?(:detailed_message) %>
248
+ <h2><%=h exception.detailed_message(highlight: false) %></h2>
249
+ <% else %>
230
250
  <h2><%=h exception.message %></h2>
251
+ <% end %>
231
252
  <table><tr>
232
253
  <th>Ruby</th>
233
254
  <td>
@@ -384,7 +405,5 @@ module Rack
384
405
  </body>
385
406
  </html>
386
407
  HTML
387
-
388
- # :startdoc:
389
408
  end
390
409
  end
@@ -2,6 +2,11 @@
2
2
 
3
3
  require 'erb'
4
4
 
5
+ require_relative 'constants'
6
+ require_relative 'utils'
7
+ require_relative 'request'
8
+ require_relative 'body_proxy'
9
+
5
10
  module Rack
6
11
  # Rack::ShowStatus catches all empty responses and replaces them
7
12
  # with a site explaining the error.
@@ -17,8 +22,7 @@ module Rack
17
22
  end
18
23
 
19
24
  def call(env)
20
- status, headers, body = @app.call(env)
21
- headers = Utils::HeaderHash[headers]
25
+ status, headers, body = response = @app.call(env)
22
26
  empty = headers[CONTENT_LENGTH].to_i <= 0
23
27
 
24
28
  # client or server error, or explicit message
@@ -33,12 +37,18 @@ module Rack
33
37
  # Yes, it is dumb, but I don't like Ruby yelling at me.
34
38
  detail = detail = env[RACK_SHOWSTATUS_DETAIL] || message
35
39
 
36
- body = @template.result(binding)
37
- size = body.bytesize
38
- [status, headers.merge(CONTENT_TYPE => "text/html", CONTENT_LENGTH => size.to_s), [body]]
39
- else
40
- [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
41
49
  end
50
+
51
+ response
42
52
  end
43
53
 
44
54
  def h(obj) # :nodoc:
@@ -107,7 +117,5 @@ TEMPLATE = <<'HTML'
107
117
  </body>
108
118
  </html>
109
119
  HTML
110
-
111
- # :startdoc:
112
120
  end
113
121
  end
data/lib/rack/static.rb CHANGED
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'constants'
4
+ require_relative 'files'
5
+ require_relative 'mime'
6
+
3
7
  module Rack
4
8
 
5
9
  # The Rack::Static middleware intercepts requests for static files
@@ -78,19 +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
- (require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4'
90
-
91
93
  def initialize(app, options = {})
92
94
  @app = app
93
95
  @urls = options[:urls] || ["/favicon.ico"]
96
+ if @urls.kind_of?(Array)
97
+ @urls = @urls.map { |url| [url, url.end_with?('/') ? url : "#{url}/".freeze].freeze }.freeze
98
+ end
94
99
  @index = options[:index]
95
100
  @gzip = options[:gzip]
96
101
  @cascade = options[:cascade]
@@ -113,7 +118,7 @@ module Rack
113
118
  end
114
119
 
115
120
  def route_file(path)
116
- @urls.kind_of?(Array) && @urls.any? { |url| path.index(url) == 0 }
121
+ @urls.kind_of?(Array) && @urls.any? { |url, url_slash| path == url || path.start_with?(url_slash) }
117
122
  end
118
123
 
119
124
  def can_serve(path)
@@ -138,10 +143,8 @@ module Rack
138
143
  elsif response[0] == 304
139
144
  # Do nothing, leave headers as is
140
145
  else
141
- if mime_type = Mime.mime_type(::File.extname(path), 'text/plain')
142
- response[1][CONTENT_TYPE] = mime_type
143
- end
144
- response[1]['Content-Encoding'] = 'gzip'
146
+ response[1][CONTENT_TYPE] = Mime.mime_type(::File.extname(path), 'text/plain')
147
+ response[1]['content-encoding'] = 'gzip'
145
148
  end
146
149
  end
147
150
 
@@ -165,6 +168,8 @@ module Rack
165
168
 
166
169
  # Convert HTTP header rules to HTTP headers
167
170
  def applicable_rules(path)
171
+ path = ::Rack::Utils.unescape_path(path)
172
+
168
173
  @header_rules.find_all do |rule, new_headers|
169
174
  case rule
170
175
  when :all
@@ -172,10 +177,9 @@ module Rack
172
177
  when :fonts
173
178
  /\.(?:ttf|otf|eot|woff2|woff|svg)\z/.match?(path)
174
179
  when String
175
- path = ::Rack::Utils.unescape(path)
176
180
  path.start_with?(rule) || path.start_with?('/' + rule)
177
181
  when Array
178
- /\.(#{rule.join('|')})\z/.match?(path)
182
+ /\.#{Regexp.union(rule)}\z/.match?(path)
179
183
  when Regexp
180
184
  rule.match?(path)
181
185
  else
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'constants'
4
+ require_relative 'body_proxy'
5
+
3
6
  module Rack
4
7
 
5
8
  # Middleware tracks and cleans Tempfiles created throughout a request (i.e. Rack::Multipart)
@@ -12,11 +15,19 @@ module Rack
12
15
 
13
16
  def call(env)
14
17
  env[RACK_TEMPFILES] ||= []
15
- status, headers, body = @app.call(env)
16
- body_proxy = BodyProxy.new(body) do
17
- 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
18
24
  end
19
- [status, headers, body_proxy]
25
+
26
+ response[2] = BodyProxy.new(body) do
27
+ env[RACK_TEMPFILES]&.each(&:close!)
28
+ end
29
+
30
+ response
20
31
  end
21
32
  end
22
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
@@ -74,7 +76,7 @@ module Rack
74
76
  return app.call(env)
75
77
  end
76
78
 
77
- [404, { CONTENT_TYPE => "text/plain", "X-Cascade" => "pass" }, ["Not Found: #{path}"]]
79
+ [404, { CONTENT_TYPE => "text/plain", "x-cascade" => "pass" }, ["Not Found: #{path}"]]
78
80
 
79
81
  ensure
80
82
  env[PATH_INFO] = path