rack 2.0.9.3 → 2.1.4.3

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 (189) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +92 -0
  3. data/{COPYING → MIT-LICENSE} +4 -2
  4. data/README.rdoc +76 -116
  5. data/Rakefile +25 -18
  6. data/SPEC +9 -9
  7. data/bin/rackup +1 -0
  8. data/example/lobster.ru +2 -0
  9. data/example/protectedlobster.rb +3 -1
  10. data/example/protectedlobster.ru +2 -0
  11. data/lib/rack/auth/abstract/handler.rb +3 -1
  12. data/lib/rack/auth/abstract/request.rb +2 -0
  13. data/lib/rack/auth/basic.rb +4 -1
  14. data/lib/rack/auth/digest/md5.rb +9 -7
  15. data/lib/rack/auth/digest/nonce.rb +6 -3
  16. data/lib/rack/auth/digest/params.rb +4 -2
  17. data/lib/rack/auth/digest/request.rb +2 -0
  18. data/lib/rack/body_proxy.rb +3 -6
  19. data/lib/rack/builder.rb +39 -15
  20. data/lib/rack/cascade.rb +6 -5
  21. data/lib/rack/chunked.rb +29 -6
  22. data/lib/rack/common_logger.rb +9 -8
  23. data/lib/rack/conditional_get.rb +3 -1
  24. data/lib/rack/config.rb +2 -0
  25. data/lib/rack/content_length.rb +3 -1
  26. data/lib/rack/content_type.rb +3 -1
  27. data/lib/rack/core_ext/regexp.rb +14 -0
  28. data/lib/rack/deflater.rb +32 -17
  29. data/lib/rack/directory.rb +19 -16
  30. data/lib/rack/etag.rb +3 -1
  31. data/lib/rack/events.rb +5 -3
  32. data/lib/rack/file.rb +4 -173
  33. data/lib/rack/files.rb +178 -0
  34. data/lib/rack/handler/cgi.rb +3 -1
  35. data/lib/rack/handler/fastcgi.rb +4 -2
  36. data/lib/rack/handler/lsws.rb +3 -1
  37. data/lib/rack/handler/scgi.rb +9 -6
  38. data/lib/rack/handler/thin.rb +3 -1
  39. data/lib/rack/handler/webrick.rb +4 -2
  40. data/lib/rack/handler.rb +7 -2
  41. data/lib/rack/head.rb +2 -0
  42. data/lib/rack/lint.rb +14 -11
  43. data/lib/rack/lobster.rb +7 -5
  44. data/lib/rack/lock.rb +2 -0
  45. data/lib/rack/logger.rb +2 -0
  46. data/lib/rack/media_type.rb +10 -5
  47. data/lib/rack/method_override.rb +4 -2
  48. data/lib/rack/mime.rb +9 -1
  49. data/lib/rack/mock.rb +74 -15
  50. data/lib/rack/multipart/generator.rb +6 -7
  51. data/lib/rack/multipart/parser.rb +50 -45
  52. data/lib/rack/multipart/uploaded_file.rb +2 -0
  53. data/lib/rack/multipart.rb +3 -1
  54. data/lib/rack/null_logger.rb +2 -0
  55. data/lib/rack/query_parser.rb +51 -25
  56. data/lib/rack/recursive.rb +7 -5
  57. data/lib/rack/reloader.rb +10 -4
  58. data/lib/rack/request.rb +79 -26
  59. data/lib/rack/response.rb +71 -31
  60. data/lib/rack/rewindable_input.rb +4 -2
  61. data/lib/rack/runtime.rb +4 -2
  62. data/lib/rack/sendfile.rb +15 -8
  63. data/lib/rack/server.rb +88 -18
  64. data/lib/rack/session/abstract/id.rb +30 -20
  65. data/lib/rack/session/cookie.rb +10 -9
  66. data/lib/rack/session/memcache.rb +4 -93
  67. data/lib/rack/session/pool.rb +4 -2
  68. data/lib/rack/show_exceptions.rb +15 -9
  69. data/lib/rack/show_status.rb +4 -2
  70. data/lib/rack/static.rb +15 -10
  71. data/lib/rack/tempfile_reaper.rb +2 -0
  72. data/lib/rack/urlmap.rb +11 -2
  73. data/lib/rack/utils.rb +58 -71
  74. data/lib/rack.rb +63 -60
  75. data/rack.gemspec +17 -7
  76. metadata +28 -170
  77. data/HISTORY.md +0 -520
  78. data/test/builder/an_underscore_app.rb +0 -5
  79. data/test/builder/anything.rb +0 -5
  80. data/test/builder/comment.ru +0 -4
  81. data/test/builder/end.ru +0 -5
  82. data/test/builder/line.ru +0 -1
  83. data/test/builder/options.ru +0 -2
  84. data/test/cgi/assets/folder/test.js +0 -1
  85. data/test/cgi/assets/fonts/font.eot +0 -1
  86. data/test/cgi/assets/images/image.png +0 -1
  87. data/test/cgi/assets/index.html +0 -1
  88. data/test/cgi/assets/javascripts/app.js +0 -1
  89. data/test/cgi/assets/stylesheets/app.css +0 -1
  90. data/test/cgi/lighttpd.conf +0 -26
  91. data/test/cgi/rackup_stub.rb +0 -6
  92. data/test/cgi/sample_rackup.ru +0 -5
  93. data/test/cgi/test +0 -9
  94. data/test/cgi/test+directory/test+file +0 -1
  95. data/test/cgi/test.fcgi +0 -9
  96. data/test/cgi/test.gz +0 -0
  97. data/test/cgi/test.ru +0 -5
  98. data/test/gemloader.rb +0 -10
  99. data/test/helper.rb +0 -34
  100. data/test/multipart/bad_robots +0 -259
  101. data/test/multipart/binary +0 -0
  102. data/test/multipart/content_type_and_no_filename +0 -6
  103. data/test/multipart/empty +0 -10
  104. data/test/multipart/fail_16384_nofile +0 -814
  105. data/test/multipart/file1.txt +0 -1
  106. data/test/multipart/filename_and_modification_param +0 -7
  107. data/test/multipart/filename_and_no_name +0 -6
  108. data/test/multipart/filename_with_encoded_words +0 -7
  109. data/test/multipart/filename_with_escaped_quotes +0 -6
  110. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  111. data/test/multipart/filename_with_null_byte +0 -7
  112. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  113. data/test/multipart/filename_with_single_quote +0 -7
  114. data/test/multipart/filename_with_unescaped_percentages +0 -6
  115. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  116. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  117. data/test/multipart/filename_with_unescaped_quotes +0 -6
  118. data/test/multipart/ie +0 -6
  119. data/test/multipart/invalid_character +0 -6
  120. data/test/multipart/mixed_files +0 -21
  121. data/test/multipart/nested +0 -10
  122. data/test/multipart/none +0 -9
  123. data/test/multipart/quoted +0 -15
  124. data/test/multipart/rack-logo.png +0 -0
  125. data/test/multipart/semicolon +0 -6
  126. data/test/multipart/text +0 -15
  127. data/test/multipart/three_files_three_fields +0 -31
  128. data/test/multipart/unity3d_wwwform +0 -11
  129. data/test/multipart/webkit +0 -32
  130. data/test/rackup/config.ru +0 -31
  131. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  132. data/test/spec_auth_basic.rb +0 -89
  133. data/test/spec_auth_digest.rb +0 -260
  134. data/test/spec_body_proxy.rb +0 -85
  135. data/test/spec_builder.rb +0 -233
  136. data/test/spec_cascade.rb +0 -63
  137. data/test/spec_cgi.rb +0 -84
  138. data/test/spec_chunked.rb +0 -103
  139. data/test/spec_common_logger.rb +0 -107
  140. data/test/spec_conditional_get.rb +0 -103
  141. data/test/spec_config.rb +0 -23
  142. data/test/spec_content_length.rb +0 -86
  143. data/test/spec_content_type.rb +0 -46
  144. data/test/spec_deflater.rb +0 -375
  145. data/test/spec_directory.rb +0 -148
  146. data/test/spec_etag.rb +0 -108
  147. data/test/spec_events.rb +0 -133
  148. data/test/spec_fastcgi.rb +0 -85
  149. data/test/spec_file.rb +0 -264
  150. data/test/spec_handler.rb +0 -57
  151. data/test/spec_head.rb +0 -46
  152. data/test/spec_lint.rb +0 -520
  153. data/test/spec_lobster.rb +0 -59
  154. data/test/spec_lock.rb +0 -204
  155. data/test/spec_logger.rb +0 -24
  156. data/test/spec_media_type.rb +0 -42
  157. data/test/spec_method_override.rb +0 -110
  158. data/test/spec_mime.rb +0 -51
  159. data/test/spec_mock.rb +0 -359
  160. data/test/spec_multipart.rb +0 -721
  161. data/test/spec_null_logger.rb +0 -21
  162. data/test/spec_recursive.rb +0 -75
  163. data/test/spec_request.rb +0 -1423
  164. data/test/spec_response.rb +0 -528
  165. data/test/spec_rewindable_input.rb +0 -128
  166. data/test/spec_runtime.rb +0 -50
  167. data/test/spec_sendfile.rb +0 -125
  168. data/test/spec_server.rb +0 -193
  169. data/test/spec_session_abstract_id.rb +0 -31
  170. data/test/spec_session_abstract_session_hash.rb +0 -45
  171. data/test/spec_session_cookie.rb +0 -442
  172. data/test/spec_session_memcache.rb +0 -357
  173. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  174. data/test/spec_session_pool.rb +0 -247
  175. data/test/spec_show_exceptions.rb +0 -93
  176. data/test/spec_show_status.rb +0 -104
  177. data/test/spec_static.rb +0 -184
  178. data/test/spec_tempfile_reaper.rb +0 -64
  179. data/test/spec_thin.rb +0 -96
  180. data/test/spec_urlmap.rb +0 -237
  181. data/test/spec_utils.rb +0 -742
  182. data/test/spec_version.rb +0 -11
  183. data/test/spec_webrick.rb +0 -206
  184. data/test/static/another/index.html +0 -1
  185. data/test/static/foo.html +0 -1
  186. data/test/static/index.html +0 -1
  187. data/test/testrequest.rb +0 -78
  188. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  189. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/lib/rack/static.rb CHANGED
@@ -1,11 +1,15 @@
1
- require "rack/file"
1
+ # frozen_string_literal: true
2
+
3
+ require "rack/files"
2
4
  require "rack/utils"
3
5
 
6
+ require_relative 'core_ext/regexp'
7
+
4
8
  module Rack
5
9
 
6
10
  # The Rack::Static middleware intercepts requests for static files
7
11
  # (javascript files, images, stylesheets, etc) based on the url prefixes or
8
- # route mappings passed in the options, and serves them using a Rack::File
12
+ # route mappings passed in the options, and serves them using a Rack::Files
9
13
  # object. This allows a Rack stack to serve both static and dynamic content.
10
14
  #
11
15
  # Examples:
@@ -82,8 +86,9 @@ module Rack
82
86
  # ]
83
87
  #
84
88
  class Static
89
+ using ::Rack::RegexpExtensions
85
90
 
86
- def initialize(app, options={})
91
+ def initialize(app, options = {})
87
92
  @app = app
88
93
  @urls = options[:urls] || ["/favicon.ico"]
89
94
  @index = options[:index]
@@ -93,13 +98,13 @@ module Rack
93
98
  # HTTP Headers
94
99
  @header_rules = options[:header_rules] || []
95
100
  # Allow for legacy :cache_control option while prioritizing global header_rules setting
96
- @header_rules.unshift([:all, {CACHE_CONTROL => options[:cache_control]}]) if options[:cache_control]
101
+ @header_rules.unshift([:all, { CACHE_CONTROL => options[:cache_control] }]) if options[:cache_control]
97
102
 
98
- @file_server = Rack::File.new(root)
103
+ @file_server = Rack::Files.new(root)
99
104
  end
100
105
 
101
106
  def add_index_root?(path)
102
- @index && path =~ /\/$/
107
+ @index && route_file(path) && path.end_with?('/')
103
108
  end
104
109
 
105
110
  def overwrite_file_path(path)
@@ -120,7 +125,7 @@ module Rack
120
125
  if can_serve(path)
121
126
  if overwrite_file_path(path)
122
127
  env[PATH_INFO] = (add_index_root?(path) ? path + @index : @urls[path])
123
- elsif @gzip && env['HTTP_ACCEPT_ENCODING'] =~ /\bgzip\b/
128
+ elsif @gzip && env['HTTP_ACCEPT_ENCODING'] && /\bgzip\b/.match?(env['HTTP_ACCEPT_ENCODING'])
124
129
  path = env[PATH_INFO]
125
130
  env[PATH_INFO] += '.gz'
126
131
  response = @file_server.call(env)
@@ -157,14 +162,14 @@ module Rack
157
162
  when :all
158
163
  true
159
164
  when :fonts
160
- path =~ /\.(?:ttf|otf|eot|woff2|woff|svg)\z/
165
+ /\.(?:ttf|otf|eot|woff2|woff|svg)\z/.match?(path)
161
166
  when String
162
167
  path = ::Rack::Utils.unescape(path)
163
168
  path.start_with?(rule) || path.start_with?('/' + rule)
164
169
  when Array
165
- path =~ /\.(#{rule.join('|')})\z/
170
+ /\.(#{rule.join('|')})\z/.match?(path)
166
171
  when Regexp
167
- path =~ rule
172
+ rule.match?(path)
168
173
  else
169
174
  false
170
175
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rack/body_proxy'
2
4
 
3
5
  module Rack
data/lib/rack/urlmap.rb CHANGED
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
1
5
  module Rack
2
6
  # Rack::URLMap takes a hash mapping urls or paths to apps, and
3
7
  # dispatches accordingly. Support for HTTP/1.1 host names exists if
@@ -20,9 +24,11 @@ module Rack
20
24
  end
21
25
 
22
26
  def remap(map)
27
+ @known_hosts = Set[]
23
28
  @mapping = map.map { |location, app|
24
29
  if location =~ %r{\Ahttps?://(.*?)(/.*)}
25
30
  host, location = $1, $2
31
+ @known_hosts << host
26
32
  else
27
33
  host = nil
28
34
  end
@@ -50,10 +56,13 @@ module Rack
50
56
  is_same_server = casecmp?(http_host, server_name) ||
51
57
  casecmp?(http_host, "#{server_name}:#{server_port}")
52
58
 
59
+ is_host_known = @known_hosts.include? http_host
60
+
53
61
  @mapping.each do |host, location, match, app|
54
62
  unless casecmp?(http_host, host) \
55
63
  || casecmp?(server_name, host) \
56
- || (!host && is_same_server)
64
+ || (!host && is_same_server) \
65
+ || (!host && !is_host_known) # If we don't have a matching host, default to the first without a specified host
57
66
  next
58
67
  end
59
68
 
@@ -68,7 +77,7 @@ module Rack
68
77
  return app.call(env)
69
78
  end
70
79
 
71
- [404, {CONTENT_TYPE => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path}"]]
80
+ [404, { CONTENT_TYPE => "text/plain", "X-Cascade" => "pass" }, ["Not Found: #{path}"]]
72
81
 
73
82
  ensure
74
83
  env[PATH_INFO] = path
data/lib/rack/utils.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  # -*- encoding: binary -*-
2
+ # frozen_string_literal: true
3
+
2
4
  require 'uri'
3
5
  require 'fileutils'
4
6
  require 'set'
@@ -6,11 +8,15 @@ require 'tempfile'
6
8
  require 'rack/query_parser'
7
9
  require 'time'
8
10
 
11
+ require_relative 'core_ext/regexp'
12
+
9
13
  module Rack
10
14
  # Rack::Utils contains a grab-bag of useful methods for writing web
11
15
  # applications adopted from all kinds of Ruby libraries.
12
16
 
13
17
  module Utils
18
+ using ::Rack::RegexpExtensions
19
+
14
20
  ParameterTypeError = QueryParser::ParameterTypeError
15
21
  InvalidParameterError = QueryParser::InvalidParameterError
16
22
  DEFAULT_SEP = QueryParser::DEFAULT_SEP
@@ -129,7 +135,7 @@ module Rack
129
135
  when Hash
130
136
  value.map { |k, v|
131
137
  build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
132
- }.reject(&:empty?).join('&')
138
+ }.delete_if(&:empty?).join('&')
133
139
  when nil
134
140
  prefix
135
141
  else
@@ -143,7 +149,7 @@ module Rack
143
149
  q_value_header.to_s.split(/\s*,\s*/).map do |part|
144
150
  value, parameters = part.split(/\s*;\s*/, 2)
145
151
  quality = 1.0
146
- if md = /\Aq=([\d.]+)/.match(parameters)
152
+ if parameters && (md = /\Aq=([\d.]+)/.match(parameters))
147
153
  quality = md[1].to_f
148
154
  end
149
155
  [value, quality]
@@ -186,27 +192,26 @@ module Rack
186
192
  # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
187
193
 
188
194
  expanded_accept_encoding =
189
- accept_encoding.map { |m, q|
195
+ accept_encoding.each_with_object([]) do |(m, q), list|
190
196
  if m == "*"
191
- (available_encodings - accept_encoding.map { |m2, _| m2 }).map { |m2| [m2, q] }
197
+ (available_encodings - accept_encoding.map(&:first))
198
+ .each { |m2| list << [m2, q] }
192
199
  else
193
- [[m, q]]
200
+ list << [m, q]
194
201
  end
195
- }.inject([]) { |mem, list|
196
- mem + list
197
- }
202
+ end
198
203
 
199
- encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map { |m, _| m }
204
+ encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map!(&:first)
200
205
 
201
206
  unless encoding_candidates.include?("identity")
202
207
  encoding_candidates.push("identity")
203
208
  end
204
209
 
205
- expanded_accept_encoding.each { |m, q|
210
+ expanded_accept_encoding.each do |m, q|
206
211
  encoding_candidates.delete(m) if q == 0.0
207
- }
212
+ end
208
213
 
209
- return (encoding_candidates & available_encodings)[0]
214
+ (encoding_candidates & available_encodings)[0]
210
215
  end
211
216
  module_function :select_best_encoding
212
217
 
@@ -221,8 +226,12 @@ module Rack
221
226
  # the Cookie header such that those with more specific Path attributes
222
227
  # precede those with less specific. Ordering with respect to other
223
228
  # attributes (e.g., Domain) is unspecified.
224
- cookies = parse_query(header, ';,') { |s| unescape(s) rescue s }
225
- cookies.each_with_object({}) { |(k,v), hash| hash[k] = Array === v ? v.first : v }
229
+ return {} unless header
230
+ header.split(/[;,] */n).each_with_object({}) do |cookie, cookies|
231
+ next if cookie.empty?
232
+ key, value = cookie.split('=', 2)
233
+ cookies[key] = (unescape(value) rescue value) unless cookies.key?(key)
234
+ end
226
235
  end
227
236
  module_function :parse_cookies_header
228
237
 
@@ -232,31 +241,7 @@ module Rack
232
241
  domain = "; domain=#{value[:domain]}" if value[:domain]
233
242
  path = "; path=#{value[:path]}" if value[:path]
234
243
  max_age = "; max-age=#{value[:max_age]}" if value[:max_age]
235
- # There is an RFC mess in the area of date formatting for Cookies. Not
236
- # only are there contradicting RFCs and examples within RFC text, but
237
- # there are also numerous conflicting names of fields and partially
238
- # cross-applicable specifications.
239
- #
240
- # These are best described in RFC 2616 3.3.1. This RFC text also
241
- # specifies that RFC 822 as updated by RFC 1123 is preferred. That is a
242
- # fixed length format with space-date delimited fields.
243
- #
244
- # See also RFC 1123 section 5.2.14.
245
- #
246
- # RFC 6265 also specifies "sane-cookie-date" as RFC 1123 date, defined
247
- # in RFC 2616 3.3.1. RFC 6265 also gives examples that clearly denote
248
- # the space delimited format. These formats are compliant with RFC 2822.
249
- #
250
- # For reference, all involved RFCs are:
251
- # RFC 822
252
- # RFC 1123
253
- # RFC 2109
254
- # RFC 2616
255
- # RFC 2822
256
- # RFC 2965
257
- # RFC 6265
258
- expires = "; expires=" +
259
- rfc2822(value[:expires].clone.gmtime) if value[:expires]
244
+ expires = "; expires=#{value[:expires].httpdate}" if value[:expires]
260
245
  secure = "; secure" if value[:secure]
261
246
  httponly = "; HttpOnly" if (value.key?(:httponly) ? value[:httponly] : value[:http_only])
262
247
  same_site =
@@ -264,11 +249,11 @@ module Rack
264
249
  when false, nil
265
250
  nil
266
251
  when :none, 'None', :None
267
- '; SameSite=None'.freeze
252
+ '; SameSite=None'
268
253
  when :lax, 'Lax', :Lax
269
- '; SameSite=Lax'.freeze
254
+ '; SameSite=Lax'
270
255
  when true, :strict, 'Strict', :Strict
271
- '; SameSite=Strict'.freeze
256
+ '; SameSite=Strict'
272
257
  else
273
258
  raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}"
274
259
  end
@@ -308,15 +293,15 @@ module Rack
308
293
  cookies = header
309
294
  end
310
295
 
311
- cookies.reject! { |cookie|
312
- if value[:domain]
313
- cookie =~ /\A#{escape(key)}=.*domain=#{value[:domain]}/
314
- elsif value[:path]
315
- cookie =~ /\A#{escape(key)}=.*path=#{value[:path]}/
316
- else
317
- cookie =~ /\A#{escape(key)}=/
318
- end
319
- }
296
+ regexp = if value[:domain]
297
+ /\A#{escape(key)}=.*domain=#{value[:domain]}/
298
+ elsif value[:path]
299
+ /\A#{escape(key)}=.*path=#{value[:path]}/
300
+ else
301
+ /\A#{escape(key)}=/
302
+ end
303
+
304
+ cookies.reject! { |cookie| regexp.match? cookie }
320
305
 
321
306
  cookies.join("\n")
322
307
  end
@@ -334,9 +319,9 @@ module Rack
334
319
  new_header = make_delete_cookie_header(header, key, value)
335
320
 
336
321
  add_cookie_to_header(new_header, key,
337
- {:value => '', :path => nil, :domain => nil,
338
- :max_age => '0',
339
- :expires => Time.at(0) }.merge(value))
322
+ { value: '', path: nil, domain: nil,
323
+ max_age: '0',
324
+ expires: Time.at(0) }.merge(value))
340
325
 
341
326
  end
342
327
  module_function :add_remove_cookie_to_header
@@ -392,7 +377,7 @@ module Rack
392
377
  else
393
378
  r1 = r1.to_i
394
379
  return nil if r1 < r0 # backwards range is syntactically invalid
395
- r1 = size-1 if r1 >= size
380
+ r1 = size - 1 if r1 >= size
396
381
  end
397
382
  end
398
383
  ranges << (r0..r1) if r0 <= r1
@@ -413,7 +398,7 @@ module Rack
413
398
  l = a.unpack("C*")
414
399
 
415
400
  r, i = 0, -1
416
- b.each_byte { |v| r |= v ^ l[i+=1] }
401
+ b.each_byte { |v| r |= v ^ l[i += 1] }
417
402
  r == 0
418
403
  end
419
404
  module_function :secure_compare
@@ -439,19 +424,17 @@ module Rack
439
424
  self.class.new(@for, app)
440
425
  end
441
426
 
442
- def context(env, app=@app)
427
+ def context(env, app = @app)
443
428
  recontext(app).call(env)
444
429
  end
445
430
  end
446
431
 
447
432
  # A case-insensitive Hash that preserves the original case of a
448
433
  # header when set.
449
- class HeaderHash < Hash
450
- def self.new(hash={})
451
- HeaderHash === hash ? hash : super(hash)
452
- end
453
-
454
- def initialize(hash={})
434
+ #
435
+ # @api private
436
+ class HeaderHash < Hash # :nodoc:
437
+ def initialize(hash = {})
455
438
  super()
456
439
  @names = {}
457
440
  hash.each { |k, v| self[k] = v }
@@ -471,7 +454,7 @@ module Rack
471
454
 
472
455
  def to_hash
473
456
  hash = {}
474
- each { |k,v| hash[k] = v }
457
+ each { |k, v| hash[k] = v }
475
458
  hash
476
459
  end
477
460
 
@@ -524,13 +507,14 @@ module Rack
524
507
 
525
508
  # Every standard HTTP code mapped to the appropriate message.
526
509
  # Generated with:
527
- # curl -s https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv | \
528
- # ruby -ne 'm = /^(\d{3}),(?!Unassigned|\(Unused\))([^,]+)/.match($_) and \
529
- # puts "#{m[1]} => \x27#{m[2].strip}\x27,"'
510
+ # curl -s https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv | \
511
+ # ruby -ne 'm = /^(\d{3}),(?!Unassigned|\(Unused\))([^,]+)/.match($_) and \
512
+ # puts "#{m[1]} => \x27#{m[2].strip}\x27,"'
530
513
  HTTP_STATUS_CODES = {
531
514
  100 => 'Continue',
532
515
  101 => 'Switching Protocols',
533
516
  102 => 'Processing',
517
+ 103 => 'Early Hints',
534
518
  200 => 'OK',
535
519
  201 => 'Created',
536
520
  202 => 'Accepted',
@@ -547,6 +531,7 @@ module Rack
547
531
  303 => 'See Other',
548
532
  304 => 'Not Modified',
549
533
  305 => 'Use Proxy',
534
+ 306 => '(Unused)',
550
535
  307 => 'Temporary Redirect',
551
536
  308 => 'Permanent Redirect',
552
537
  400 => 'Bad Request',
@@ -571,6 +556,7 @@ module Rack
571
556
  422 => 'Unprocessable Entity',
572
557
  423 => 'Locked',
573
558
  424 => 'Failed Dependency',
559
+ 425 => 'Too Early',
574
560
  426 => 'Upgrade Required',
575
561
  428 => 'Precondition Required',
576
562
  429 => 'Too Many Requests',
@@ -585,12 +571,13 @@ module Rack
585
571
  506 => 'Variant Also Negotiates',
586
572
  507 => 'Insufficient Storage',
587
573
  508 => 'Loop Detected',
574
+ 509 => 'Bandwidth Limit Exceeded',
588
575
  510 => 'Not Extended',
589
576
  511 => 'Network Authentication Required'
590
577
  }
591
578
 
592
579
  # Responses with HTTP status codes that should not have an entity body
593
- STATUS_WITH_NO_ENTITY_BODY = Set.new((100..199).to_a << 204 << 304)
580
+ STATUS_WITH_NO_ENTITY_BODY = Hash[((100..199).to_a << 204 << 304).product([true])]
594
581
 
595
582
  SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message|
596
583
  [message.downcase.gsub(/\s|-|'/, '_').to_sym, code]
@@ -598,7 +585,7 @@ module Rack
598
585
 
599
586
  def status_code(status)
600
587
  if status.is_a?(Symbol)
601
- SYMBOL_TO_STATUS_CODE[status] || 500
588
+ SYMBOL_TO_STATUS_CODE.fetch(status) { raise ArgumentError, "Unrecognized status code #{status.inspect}" }
602
589
  else
603
590
  status.to_i
604
591
  end
@@ -619,11 +606,11 @@ module Rack
619
606
 
620
607
  clean.unshift '/' if parts.empty? || parts.first.empty?
621
608
 
622
- ::File.join(*clean)
609
+ ::File.join clean
623
610
  end
624
611
  module_function :clean_path_info
625
612
 
626
- NULL_BYTE = "\0".freeze
613
+ NULL_BYTE = "\0"
627
614
 
628
615
  def valid_path?(path)
629
616
  path.valid_encoding? && !path.include?(NULL_BYTE)
data/lib/rack.rb CHANGED
@@ -1,7 +1,9 @@
1
- # Copyright (C) 2007, 2008, 2009, 2010 Christian Neukirchen <purl.org/net/chneukirchen>
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2007-2019 Leah Neukirchen <http://leahneukirchen.org/infopage.html>
2
4
  #
3
5
  # Rack is freely distributable under the terms of an MIT-style license.
4
- # See COPYING or http://www.opensource.org/licenses/mit-license.php.
6
+ # See MIT-LICENSE or https://opensource.org/licenses/MIT.
5
7
 
6
8
  # The Rack main module, serving as a namespace for all core Rack
7
9
  # modules and classes.
@@ -11,80 +13,80 @@
11
13
 
12
14
  module Rack
13
15
  # The Rack protocol version number implemented.
14
- VERSION = [1,3]
16
+ VERSION = [1, 3]
15
17
 
16
18
  # Return the Rack protocol version as a dotted string.
17
19
  def self.version
18
20
  VERSION.join(".")
19
21
  end
20
22
 
21
- RELEASE = "2.0.9.3"
23
+ RELEASE = "2.1.4.3"
22
24
 
23
25
  # Return the Rack release as a dotted string.
24
26
  def self.release
25
27
  RELEASE
26
28
  end
27
29
 
28
- HTTP_HOST = 'HTTP_HOST'.freeze
29
- HTTP_VERSION = 'HTTP_VERSION'.freeze
30
- HTTPS = 'HTTPS'.freeze
31
- PATH_INFO = 'PATH_INFO'.freeze
32
- REQUEST_METHOD = 'REQUEST_METHOD'.freeze
33
- REQUEST_PATH = 'REQUEST_PATH'.freeze
34
- SCRIPT_NAME = 'SCRIPT_NAME'.freeze
35
- QUERY_STRING = 'QUERY_STRING'.freeze
36
- SERVER_PROTOCOL = 'SERVER_PROTOCOL'.freeze
37
- SERVER_NAME = 'SERVER_NAME'.freeze
38
- SERVER_ADDR = 'SERVER_ADDR'.freeze
39
- SERVER_PORT = 'SERVER_PORT'.freeze
40
- CACHE_CONTROL = 'Cache-Control'.freeze
41
- CONTENT_LENGTH = 'Content-Length'.freeze
42
- CONTENT_TYPE = 'Content-Type'.freeze
43
- SET_COOKIE = 'Set-Cookie'.freeze
44
- TRANSFER_ENCODING = 'Transfer-Encoding'.freeze
45
- HTTP_COOKIE = 'HTTP_COOKIE'.freeze
46
- ETAG = 'ETag'.freeze
30
+ HTTP_HOST = 'HTTP_HOST'
31
+ HTTP_VERSION = 'HTTP_VERSION'
32
+ HTTPS = 'HTTPS'
33
+ PATH_INFO = 'PATH_INFO'
34
+ REQUEST_METHOD = 'REQUEST_METHOD'
35
+ REQUEST_PATH = 'REQUEST_PATH'
36
+ SCRIPT_NAME = 'SCRIPT_NAME'
37
+ QUERY_STRING = 'QUERY_STRING'
38
+ SERVER_PROTOCOL = 'SERVER_PROTOCOL'
39
+ SERVER_NAME = 'SERVER_NAME'
40
+ SERVER_ADDR = 'SERVER_ADDR'
41
+ SERVER_PORT = 'SERVER_PORT'
42
+ CACHE_CONTROL = 'Cache-Control'
43
+ CONTENT_LENGTH = 'Content-Length'
44
+ CONTENT_TYPE = 'Content-Type'
45
+ SET_COOKIE = 'Set-Cookie'
46
+ TRANSFER_ENCODING = 'Transfer-Encoding'
47
+ HTTP_COOKIE = 'HTTP_COOKIE'
48
+ ETAG = 'ETag'
47
49
 
48
50
  # HTTP method verbs
49
- GET = 'GET'.freeze
50
- POST = 'POST'.freeze
51
- PUT = 'PUT'.freeze
52
- PATCH = 'PATCH'.freeze
53
- DELETE = 'DELETE'.freeze
54
- HEAD = 'HEAD'.freeze
55
- OPTIONS = 'OPTIONS'.freeze
56
- LINK = 'LINK'.freeze
57
- UNLINK = 'UNLINK'.freeze
58
- TRACE = 'TRACE'.freeze
51
+ GET = 'GET'
52
+ POST = 'POST'
53
+ PUT = 'PUT'
54
+ PATCH = 'PATCH'
55
+ DELETE = 'DELETE'
56
+ HEAD = 'HEAD'
57
+ OPTIONS = 'OPTIONS'
58
+ LINK = 'LINK'
59
+ UNLINK = 'UNLINK'
60
+ TRACE = 'TRACE'
59
61
 
60
62
  # Rack environment variables
61
- RACK_VERSION = 'rack.version'.freeze
62
- RACK_TEMPFILES = 'rack.tempfiles'.freeze
63
- RACK_ERRORS = 'rack.errors'.freeze
64
- RACK_LOGGER = 'rack.logger'.freeze
65
- RACK_INPUT = 'rack.input'.freeze
66
- RACK_SESSION = 'rack.session'.freeze
67
- RACK_SESSION_OPTIONS = 'rack.session.options'.freeze
68
- RACK_SHOWSTATUS_DETAIL = 'rack.showstatus.detail'.freeze
69
- RACK_MULTITHREAD = 'rack.multithread'.freeze
70
- RACK_MULTIPROCESS = 'rack.multiprocess'.freeze
71
- RACK_RUNONCE = 'rack.run_once'.freeze
72
- RACK_URL_SCHEME = 'rack.url_scheme'.freeze
73
- RACK_HIJACK = 'rack.hijack'.freeze
74
- RACK_IS_HIJACK = 'rack.hijack?'.freeze
75
- RACK_HIJACK_IO = 'rack.hijack_io'.freeze
76
- RACK_RECURSIVE_INCLUDE = 'rack.recursive.include'.freeze
77
- RACK_MULTIPART_BUFFER_SIZE = 'rack.multipart.buffer_size'.freeze
78
- RACK_MULTIPART_TEMPFILE_FACTORY = 'rack.multipart.tempfile_factory'.freeze
79
- RACK_REQUEST_FORM_INPUT = 'rack.request.form_input'.freeze
80
- RACK_REQUEST_FORM_HASH = 'rack.request.form_hash'.freeze
81
- RACK_REQUEST_FORM_VARS = 'rack.request.form_vars'.freeze
82
- RACK_REQUEST_COOKIE_HASH = 'rack.request.cookie_hash'.freeze
83
- RACK_REQUEST_COOKIE_STRING = 'rack.request.cookie_string'.freeze
84
- RACK_REQUEST_QUERY_HASH = 'rack.request.query_hash'.freeze
85
- RACK_REQUEST_QUERY_STRING = 'rack.request.query_string'.freeze
86
- RACK_METHODOVERRIDE_ORIGINAL_METHOD = 'rack.methodoverride.original_method'.freeze
87
- RACK_SESSION_UNPACKED_COOKIE_DATA = 'rack.session.unpacked_cookie_data'.freeze
63
+ RACK_VERSION = 'rack.version'
64
+ RACK_TEMPFILES = 'rack.tempfiles'
65
+ RACK_ERRORS = 'rack.errors'
66
+ RACK_LOGGER = 'rack.logger'
67
+ RACK_INPUT = 'rack.input'
68
+ RACK_SESSION = 'rack.session'
69
+ RACK_SESSION_OPTIONS = 'rack.session.options'
70
+ RACK_SHOWSTATUS_DETAIL = 'rack.showstatus.detail'
71
+ RACK_MULTITHREAD = 'rack.multithread'
72
+ RACK_MULTIPROCESS = 'rack.multiprocess'
73
+ RACK_RUNONCE = 'rack.run_once'
74
+ RACK_URL_SCHEME = 'rack.url_scheme'
75
+ RACK_HIJACK = 'rack.hijack'
76
+ RACK_IS_HIJACK = 'rack.hijack?'
77
+ RACK_HIJACK_IO = 'rack.hijack_io'
78
+ RACK_RECURSIVE_INCLUDE = 'rack.recursive.include'
79
+ RACK_MULTIPART_BUFFER_SIZE = 'rack.multipart.buffer_size'
80
+ RACK_MULTIPART_TEMPFILE_FACTORY = 'rack.multipart.tempfile_factory'
81
+ RACK_REQUEST_FORM_INPUT = 'rack.request.form_input'
82
+ RACK_REQUEST_FORM_HASH = 'rack.request.form_hash'
83
+ RACK_REQUEST_FORM_VARS = 'rack.request.form_vars'
84
+ RACK_REQUEST_COOKIE_HASH = 'rack.request.cookie_hash'
85
+ RACK_REQUEST_COOKIE_STRING = 'rack.request.cookie_string'
86
+ RACK_REQUEST_QUERY_HASH = 'rack.request.query_hash'
87
+ RACK_REQUEST_QUERY_STRING = 'rack.request.query_string'
88
+ RACK_METHODOVERRIDE_ORIGINAL_METHOD = 'rack.methodoverride.original_method'
89
+ RACK_SESSION_UNPACKED_COOKIE_DATA = 'rack.session.unpacked_cookie_data'
88
90
 
89
91
  autoload :Builder, "rack/builder"
90
92
  autoload :BodyProxy, "rack/body_proxy"
@@ -97,6 +99,7 @@ module Rack
97
99
  autoload :ContentType, "rack/content_type"
98
100
  autoload :ETag, "rack/etag"
99
101
  autoload :File, "rack/file"
102
+ autoload :Files, "rack/files"
100
103
  autoload :Deflater, "rack/deflater"
101
104
  autoload :Directory, "rack/directory"
102
105
  autoload :ForwardRequest, "rack/recursive"
data/rack.gemspec CHANGED
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Gem::Specification.new do |s|
2
- s.name = "rack"
4
+ s.name = "rack"
3
5
  s.version = File.read('lib/rack.rb')[/RELEASE += +([\"\'])([\d][\w\.]+)\1/, 2]
4
6
  s.platform = Gem::Platform::RUBY
5
7
  s.summary = "a modular Ruby webserver interface"
@@ -15,20 +17,28 @@ middleware) into a single method call.
15
17
  Also see https://rack.github.io/.
16
18
  EOF
17
19
 
18
- s.files = Dir['{bin/*,contrib/*,example/*,lib/**/*,test/**/*}'] +
19
- %w(COPYING rack.gemspec Rakefile README.rdoc SPEC)
20
+ s.files = Dir['{bin/*,contrib/*,example/*,lib/**/*}'] +
21
+ %w(MIT-LICENSE rack.gemspec Rakefile README.rdoc SPEC)
20
22
  s.bindir = 'bin'
21
- s.executables << 'rackup'
22
- s.require_path = 'lib'
23
- s.extra_rdoc_files = ['README.rdoc', 'HISTORY.md']
24
- s.test_files = Dir['test/spec_*.rb']
23
+ s.executables << 'rackup'
24
+ s.require_path = 'lib'
25
+ s.extra_rdoc_files = ['README.rdoc', 'CHANGELOG.md']
25
26
 
26
27
  s.author = 'Leah Neukirchen'
27
28
  s.email = 'leah@vuxu.org'
28
29
  s.homepage = 'https://rack.github.io/'
29
30
  s.required_ruby_version = '>= 2.2.2'
31
+ s.metadata = {
32
+ "bug_tracker_uri" => "https://github.com/rack/rack/issues",
33
+ "changelog_uri" => "https://github.com/rack/rack/blob/master/CHANGELOG.md",
34
+ "documentation_uri" => "https://rubydoc.info/github/rack/rack",
35
+ "homepage_uri" => "https://rack.github.io",
36
+ "mailing_list_uri" => "https://groups.google.com/forum/#!forum/rack-devel",
37
+ "source_code_uri" => "https://github.com/rack/rack"
38
+ }
30
39
 
31
40
  s.add_development_dependency 'minitest', "~> 5.0"
32
41
  s.add_development_dependency 'minitest-sprint'
42
+ s.add_development_dependency 'minitest-global_expectations'
33
43
  s.add_development_dependency 'rake'
34
44
  end