rack 1.6.13 → 2.0.9

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 (141) hide show
  1. checksums.yaml +4 -4
  2. data/COPYING +1 -1
  3. data/HISTORY.md +138 -8
  4. data/README.rdoc +18 -28
  5. data/Rakefile +6 -14
  6. data/SPEC +3 -3
  7. data/contrib/rack_logo.svg +164 -111
  8. data/example/protectedlobster.rb +1 -1
  9. data/example/protectedlobster.ru +1 -1
  10. data/lib/rack/auth/abstract/request.rb +5 -1
  11. data/lib/rack/auth/digest/params.rb +2 -3
  12. data/lib/rack/auth/digest/request.rb +1 -1
  13. data/lib/rack/body_proxy.rb +14 -9
  14. data/lib/rack/builder.rb +3 -3
  15. data/lib/rack/chunked.rb +5 -5
  16. data/lib/rack/{commonlogger.rb → common_logger.rb} +3 -3
  17. data/lib/rack/content_length.rb +2 -2
  18. data/lib/rack/deflater.rb +4 -39
  19. data/lib/rack/directory.rb +66 -54
  20. data/lib/rack/etag.rb +5 -4
  21. data/lib/rack/events.rb +154 -0
  22. data/lib/rack/file.rb +64 -40
  23. data/lib/rack/handler/cgi.rb +15 -16
  24. data/lib/rack/handler/fastcgi.rb +13 -14
  25. data/lib/rack/handler/lsws.rb +11 -11
  26. data/lib/rack/handler/scgi.rb +15 -15
  27. data/lib/rack/handler/thin.rb +3 -0
  28. data/lib/rack/handler/webrick.rb +24 -26
  29. data/lib/rack/handler.rb +3 -25
  30. data/lib/rack/head.rb +15 -17
  31. data/lib/rack/lint.rb +40 -40
  32. data/lib/rack/lobster.rb +1 -1
  33. data/lib/rack/lock.rb +15 -10
  34. data/lib/rack/logger.rb +2 -2
  35. data/lib/rack/media_type.rb +38 -0
  36. data/lib/rack/{methodoverride.rb → method_override.rb} +6 -6
  37. data/lib/rack/mime.rb +18 -5
  38. data/lib/rack/mock.rb +36 -54
  39. data/lib/rack/multipart/generator.rb +5 -5
  40. data/lib/rack/multipart/parser.rb +270 -157
  41. data/lib/rack/multipart/uploaded_file.rb +1 -2
  42. data/lib/rack/multipart.rb +35 -6
  43. data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
  44. data/lib/rack/query_parser.rb +192 -0
  45. data/lib/rack/recursive.rb +8 -8
  46. data/lib/rack/request.rb +394 -305
  47. data/lib/rack/response.rb +130 -57
  48. data/lib/rack/rewindable_input.rb +1 -12
  49. data/lib/rack/runtime.rb +10 -18
  50. data/lib/rack/sendfile.rb +5 -7
  51. data/lib/rack/server.rb +30 -23
  52. data/lib/rack/session/abstract/id.rb +110 -75
  53. data/lib/rack/session/cookie.rb +24 -17
  54. data/lib/rack/session/memcache.rb +9 -9
  55. data/lib/rack/session/pool.rb +8 -8
  56. data/lib/rack/show_exceptions.rb +386 -0
  57. data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
  58. data/lib/rack/static.rb +30 -5
  59. data/lib/rack/tempfile_reaper.rb +2 -2
  60. data/lib/rack/urlmap.rb +15 -14
  61. data/lib/rack/utils.rb +138 -211
  62. data/lib/rack.rb +70 -21
  63. data/rack.gemspec +10 -9
  64. data/test/builder/an_underscore_app.rb +5 -0
  65. data/test/builder/options.ru +1 -1
  66. data/test/cgi/test.fcgi +1 -0
  67. data/test/cgi/test.gz +0 -0
  68. data/test/helper.rb +34 -0
  69. data/test/multipart/filename_with_encoded_words +7 -0
  70. data/test/multipart/filename_with_single_quote +7 -0
  71. data/test/multipart/quoted +15 -0
  72. data/test/multipart/rack-logo.png +0 -0
  73. data/test/multipart/unity3d_wwwform +11 -0
  74. data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
  75. data/test/spec_auth_basic.rb +27 -19
  76. data/test/spec_auth_digest.rb +47 -46
  77. data/test/spec_body_proxy.rb +27 -27
  78. data/test/spec_builder.rb +51 -41
  79. data/test/spec_cascade.rb +24 -22
  80. data/test/spec_cgi.rb +49 -67
  81. data/test/spec_chunked.rb +37 -35
  82. data/test/{spec_commonlogger.rb → spec_common_logger.rb} +23 -21
  83. data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
  84. data/test/spec_config.rb +3 -2
  85. data/test/spec_content_length.rb +18 -17
  86. data/test/spec_content_type.rb +13 -12
  87. data/test/spec_deflater.rb +85 -49
  88. data/test/spec_directory.rb +87 -27
  89. data/test/spec_etag.rb +32 -31
  90. data/test/spec_events.rb +133 -0
  91. data/test/spec_fastcgi.rb +50 -72
  92. data/test/spec_file.rb +120 -77
  93. data/test/spec_handler.rb +19 -34
  94. data/test/spec_head.rb +15 -14
  95. data/test/spec_lint.rb +164 -199
  96. data/test/spec_lobster.rb +24 -23
  97. data/test/spec_lock.rb +79 -39
  98. data/test/spec_logger.rb +4 -3
  99. data/test/spec_media_type.rb +42 -0
  100. data/test/{spec_methodoverride.rb → spec_method_override.rb} +34 -35
  101. data/test/spec_mime.rb +19 -19
  102. data/test/spec_mock.rb +206 -144
  103. data/test/spec_multipart.rb +322 -200
  104. data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
  105. data/test/spec_recursive.rb +17 -14
  106. data/test/spec_request.rb +780 -605
  107. data/test/spec_response.rb +233 -112
  108. data/test/spec_rewindable_input.rb +50 -40
  109. data/test/spec_runtime.rb +11 -10
  110. data/test/spec_sendfile.rb +30 -35
  111. data/test/spec_server.rb +78 -52
  112. data/test/spec_session_abstract_id.rb +11 -33
  113. data/test/spec_session_abstract_session_hash.rb +45 -0
  114. data/test/spec_session_cookie.rb +99 -67
  115. data/test/spec_session_memcache.rb +67 -68
  116. data/test/spec_session_pool.rb +52 -51
  117. data/test/{spec_showexceptions.rb → spec_show_exceptions.rb} +23 -28
  118. data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
  119. data/test/spec_static.rb +71 -32
  120. data/test/spec_tempfile_reaper.rb +11 -10
  121. data/test/spec_thin.rb +55 -50
  122. data/test/spec_urlmap.rb +79 -78
  123. data/test/spec_utils.rb +441 -346
  124. data/test/spec_version.rb +2 -8
  125. data/test/spec_webrick.rb +93 -71
  126. data/test/static/foo.html +1 -0
  127. data/test/testrequest.rb +1 -1
  128. data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
  129. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
  130. metadata +57 -36
  131. data/KNOWN-ISSUES +0 -44
  132. data/lib/rack/backports/uri/common_18.rb +0 -56
  133. data/lib/rack/backports/uri/common_192.rb +0 -52
  134. data/lib/rack/backports/uri/common_193.rb +0 -29
  135. data/lib/rack/handler/evented_mongrel.rb +0 -8
  136. data/lib/rack/handler/mongrel.rb +0 -106
  137. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  138. data/lib/rack/showexceptions.rb +0 -387
  139. data/lib/rack/utils/okjson.rb +0 -600
  140. data/test/spec_mongrel.rb +0 -182
  141. /data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
data/lib/rack/utils.rb CHANGED
@@ -1,35 +1,28 @@
1
1
  # -*- encoding: binary -*-
2
+ require 'uri'
2
3
  require 'fileutils'
3
4
  require 'set'
4
5
  require 'tempfile'
5
- require 'rack/multipart'
6
+ require 'rack/query_parser'
6
7
  require 'time'
7
8
 
8
- major, minor, patch = RUBY_VERSION.split('.').map { |v| v.to_i }
9
-
10
- if major == 1 && minor < 9
11
- require 'rack/backports/uri/common_18'
12
- elsif major == 1 && minor == 9 && patch == 2 && RUBY_PATCHLEVEL <= 328 && RUBY_ENGINE != 'jruby'
13
- require 'rack/backports/uri/common_192'
14
- elsif major == 1 && minor == 9 && patch == 3 && RUBY_PATCHLEVEL < 125
15
- require 'rack/backports/uri/common_193'
16
- else
17
- require 'uri/common'
18
- end
19
-
20
9
  module Rack
21
10
  # Rack::Utils contains a grab-bag of useful methods for writing web
22
11
  # applications adopted from all kinds of Ruby libraries.
23
12
 
24
13
  module Utils
25
- # ParameterTypeError is the error that is raised when incoming structural
26
- # parameters (parsed by parse_nested_query) contain conflicting types.
27
- class ParameterTypeError < TypeError; end
14
+ ParameterTypeError = QueryParser::ParameterTypeError
15
+ InvalidParameterError = QueryParser::InvalidParameterError
16
+ DEFAULT_SEP = QueryParser::DEFAULT_SEP
17
+ COMMON_SEP = QueryParser::COMMON_SEP
18
+ KeySpaceConstrainedParams = QueryParser::Params
28
19
 
29
- # InvalidParameterError is the error that is raised when incoming structural
30
- # parameters (parsed by parse_nested_query) contain invalid format or byte
31
- # sequence.
32
- class InvalidParameterError < ArgumentError; end
20
+ class << self
21
+ attr_accessor :default_query_parser
22
+ end
23
+ # The default number of bytes to allow parameter keys to take up.
24
+ # This helps prevent a rogue client from flooding a Request.
25
+ self.default_query_parser = QueryParser.make_default(65536, 100)
33
26
 
34
27
  # URI escapes. (CGI style space to +)
35
28
  def escape(s)
@@ -40,137 +33,70 @@ module Rack
40
33
  # Like URI escaping, but with %20 instead of +. Strictly speaking this is
41
34
  # true URI escaping.
42
35
  def escape_path(s)
43
- escape(s).gsub('+', '%20')
36
+ ::URI::DEFAULT_PARSER.escape s
44
37
  end
45
38
  module_function :escape_path
46
39
 
40
+ # Unescapes the **path** component of a URI. See Rack::Utils.unescape for
41
+ # unescaping query parameters or form components.
42
+ def unescape_path(s)
43
+ ::URI::DEFAULT_PARSER.unescape s
44
+ end
45
+ module_function :unescape_path
46
+
47
+
47
48
  # Unescapes a URI escaped string with +encoding+. +encoding+ will be the
48
49
  # target encoding of the string returned, and it defaults to UTF-8
49
- if defined?(::Encoding)
50
- def unescape(s, encoding = Encoding::UTF_8)
51
- URI.decode_www_form_component(s, encoding)
52
- end
53
- else
54
- def unescape(s, encoding = nil)
55
- URI.decode_www_form_component(s, encoding)
56
- end
50
+ def unescape(s, encoding = Encoding::UTF_8)
51
+ URI.decode_www_form_component(s, encoding)
57
52
  end
58
53
  module_function :unescape
59
54
 
60
- DEFAULT_SEP = /[&;] */n
61
-
62
55
  class << self
63
- attr_accessor :key_space_limit
64
- attr_accessor :param_depth_limit
65
56
  attr_accessor :multipart_part_limit
66
57
  end
67
58
 
68
- # The default number of bytes to allow parameter keys to take up.
69
- # This helps prevent a rogue client from flooding a Request.
70
- self.key_space_limit = 65536
71
-
72
- # Default depth at which the parameter parser will raise an exception for
73
- # being too deep. This helps prevent SystemStackErrors
74
- self.param_depth_limit = 100
75
-
76
59
  # The maximum number of parts a request can contain. Accepting too many part
77
60
  # can lead to the server running out of file handles.
78
61
  # Set to `0` for no limit.
79
- # FIXME: RACK_MULTIPART_LIMIT was introduced by mistake and it will be removed in 1.7.0
80
- self.multipart_part_limit = (ENV['RACK_MULTIPART_PART_LIMIT'] || ENV['RACK_MULTIPART_LIMIT'] || 128).to_i
81
-
82
- # Stolen from Mongrel, with some small modifications:
83
- # Parses a query string by breaking it up at the '&'
84
- # and ';' characters. You can also use this to parse
85
- # cookies by changing the characters used in the second
86
- # parameter (which defaults to '&;').
87
- def parse_query(qs, d = nil, &unescaper)
88
- unescaper ||= method(:unescape)
89
-
90
- params = KeySpaceConstrainedParams.new
91
-
92
- (qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
93
- next if p.empty?
94
- k, v = p.split('=', 2).map(&unescaper)
62
+ self.multipart_part_limit = (ENV['RACK_MULTIPART_PART_LIMIT'] || 128).to_i
95
63
 
96
- if cur = params[k]
97
- if cur.class == Array
98
- params[k] << v
99
- else
100
- params[k] = [cur, v]
101
- end
102
- else
103
- params[k] = v
104
- end
105
- end
106
-
107
- return params.to_params_hash
64
+ def self.param_depth_limit
65
+ default_query_parser.param_depth_limit
108
66
  end
109
- module_function :parse_query
110
-
111
- # parse_nested_query expands a query string into structural types. Supported
112
- # types are Arrays, Hashes and basic value types. It is possible to supply
113
- # query strings with parameters of conflicting types, in this case a
114
- # ParameterTypeError is raised. Users are encouraged to return a 400 in this
115
- # case.
116
- def parse_nested_query(qs, d = nil)
117
- params = KeySpaceConstrainedParams.new
118
67
 
119
- (qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
120
- k, v = p.split('=', 2).map { |s| unescape(s) }
68
+ def self.param_depth_limit=(v)
69
+ self.default_query_parser = self.default_query_parser.new_depth_limit(v)
70
+ end
121
71
 
122
- normalize_params(params, k, v)
123
- end
72
+ def self.key_space_limit
73
+ default_query_parser.key_space_limit
74
+ end
124
75
 
125
- return params.to_params_hash
126
- rescue ArgumentError => e
127
- raise InvalidParameterError, e.message
76
+ def self.key_space_limit=(v)
77
+ self.default_query_parser = self.default_query_parser.new_space_limit(v)
128
78
  end
129
- module_function :parse_nested_query
130
79
 
131
- # normalize_params recursively expands parameters into structural types. If
132
- # the structural types represented by two different parameter names are in
133
- # conflict, a ParameterTypeError is raised.
134
- def normalize_params(params, name, v = nil, depth = Utils.param_depth_limit)
135
- raise RangeError if depth <= 0
136
-
137
- name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
138
- k = $1 || ''
139
- after = $' || ''
140
-
141
- return if k.empty?
142
-
143
- if after == ""
144
- params[k] = v
145
- elsif after == "["
146
- params[name] = v
147
- elsif after == "[]"
148
- params[k] ||= []
149
- raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
150
- params[k] << v
151
- elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$)
152
- child_key = $1
153
- params[k] ||= []
154
- raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
155
- if params_hash_type?(params[k].last) && !params[k].last.key?(child_key)
156
- normalize_params(params[k].last, child_key, v, depth - 1)
157
- else
158
- params[k] << normalize_params(params.class.new, child_key, v, depth - 1)
159
- end
160
- else
161
- params[k] ||= params.class.new
162
- raise ParameterTypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params_hash_type?(params[k])
163
- params[k] = normalize_params(params[k], after, v, depth - 1)
80
+ if defined?(Process::CLOCK_MONOTONIC)
81
+ def clock_time
82
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
83
+ end
84
+ else
85
+ def clock_time
86
+ Time.now.to_f
164
87
  end
88
+ end
89
+ module_function :clock_time
165
90
 
166
- return params
91
+ def parse_query(qs, d = nil, &unescaper)
92
+ Rack::Utils.default_query_parser.parse_query(qs, d, &unescaper)
167
93
  end
168
- module_function :normalize_params
94
+ module_function :parse_query
169
95
 
170
- def params_hash_type?(obj)
171
- obj.kind_of?(KeySpaceConstrainedParams) || obj.kind_of?(Hash)
96
+ def parse_nested_query(qs, d = nil)
97
+ Rack::Utils.default_query_parser.parse_nested_query(qs, d)
172
98
  end
173
- module_function :params_hash_type?
99
+ module_function :parse_nested_query
174
100
 
175
101
  def build_query(params)
176
102
  params.map { |k, v|
@@ -236,13 +162,8 @@ module Rack
236
162
  '"' => "&quot;",
237
163
  "/" => "&#x2F;"
238
164
  }
239
- if //.respond_to?(:encoding)
240
- ESCAPE_HTML_PATTERN = Regexp.union(*ESCAPE_HTML.keys)
241
- else
242
- # On 1.8, there is a kcode = 'u' bug that allows for XSS otherwise
243
- # TODO doesn't apply to jruby, so a better condition above might be preferable?
244
- ESCAPE_HTML_PATTERN = /#{Regexp.union(*ESCAPE_HTML.keys)}/n
245
- end
165
+
166
+ ESCAPE_HTML_PATTERN = Regexp.union(*ESCAPE_HTML.keys)
246
167
 
247
168
  # Escape ampersands, brackets and quotes to their HTML/XML entities.
248
169
  def escape_html(string)
@@ -278,12 +199,28 @@ module Rack
278
199
  end
279
200
  module_function :select_best_encoding
280
201
 
281
- def set_cookie_header!(header, key, value)
202
+ def parse_cookies(env)
203
+ parse_cookies_header env[HTTP_COOKIE]
204
+ end
205
+ module_function :parse_cookies
206
+
207
+ def parse_cookies_header(header)
208
+ # According to RFC 2109:
209
+ # If multiple cookies satisfy the criteria above, they are ordered in
210
+ # the Cookie header such that those with more specific Path attributes
211
+ # precede those with less specific. Ordering with respect to other
212
+ # attributes (e.g., Domain) is unspecified.
213
+ cookies = parse_query(header, ';,') { |s| unescape(s) rescue s }
214
+ cookies.each_with_object({}) { |(k,v), hash| hash[k] = Array === v ? v.first : v }
215
+ end
216
+ module_function :parse_cookies_header
217
+
218
+ def add_cookie_to_header(header, key, value)
282
219
  case value
283
220
  when Hash
284
- domain = "; domain=" + value[:domain] if value[:domain]
285
- path = "; path=" + value[:path] if value[:path]
286
- max_age = "; max-age=" + value[:max_age].to_s if value[:max_age]
221
+ domain = "; domain=#{value[:domain]}" if value[:domain]
222
+ path = "; path=#{value[:path]}" if value[:path]
223
+ max_age = "; max-age=#{value[:max_age]}" if value[:max_age]
287
224
  # There is an RFC mess in the area of date formatting for Cookies. Not
288
225
  # only are there contradicting RFCs and examples within RFC text, but
289
226
  # there are also numerous conflicting names of fields and partially
@@ -291,7 +228,7 @@ module Rack
291
228
  #
292
229
  # These are best described in RFC 2616 3.3.1. This RFC text also
293
230
  # specifies that RFC 822 as updated by RFC 1123 is preferred. That is a
294
- # fixed length format with space-date delimeted fields.
231
+ # fixed length format with space-date delimited fields.
295
232
  #
296
233
  # See also RFC 1123 section 5.2.14.
297
234
  #
@@ -315,6 +252,8 @@ module Rack
315
252
  case value[:same_site]
316
253
  when false, nil
317
254
  nil
255
+ when :none, 'None', :None
256
+ '; SameSite=None'.freeze
318
257
  when :lax, 'Lax', :Lax
319
258
  '; SameSite=Lax'.freeze
320
259
  when true, :strict, 'Strict', :Strict
@@ -325,31 +264,37 @@ module Rack
325
264
  value = value[:value]
326
265
  end
327
266
  value = [value] unless Array === value
328
- cookie = escape(key) + "=" +
329
- value.map { |v| escape v }.join("&") +
330
- "#{domain}#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}"
331
267
 
332
- case header["Set-Cookie"]
268
+ cookie = "#{escape(key)}=#{value.map { |v| escape v }.join('&')}#{domain}" \
269
+ "#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}"
270
+
271
+ case header
333
272
  when nil, ''
334
- header["Set-Cookie"] = cookie
273
+ cookie
335
274
  when String
336
- header["Set-Cookie"] = [header["Set-Cookie"], cookie].join("\n")
275
+ [header, cookie].join("\n")
337
276
  when Array
338
- header["Set-Cookie"] = (header["Set-Cookie"] + [cookie]).join("\n")
277
+ (header + [cookie]).join("\n")
278
+ else
279
+ raise ArgumentError, "Unrecognized cookie header value. Expected String, Array, or nil, got #{header.inspect}"
339
280
  end
281
+ end
282
+ module_function :add_cookie_to_header
340
283
 
284
+ def set_cookie_header!(header, key, value)
285
+ header[SET_COOKIE] = add_cookie_to_header(header[SET_COOKIE], key, value)
341
286
  nil
342
287
  end
343
288
  module_function :set_cookie_header!
344
289
 
345
- def delete_cookie_header!(header, key, value = {})
346
- case header["Set-Cookie"]
290
+ def make_delete_cookie_header(header, key, value)
291
+ case header
347
292
  when nil, ''
348
293
  cookies = []
349
294
  when String
350
- cookies = header["Set-Cookie"].split("\n")
295
+ cookies = header.split("\n")
351
296
  when Array
352
- cookies = header["Set-Cookie"]
297
+ cookies = header
353
298
  end
354
299
 
355
300
  cookies.reject! { |cookie|
@@ -362,29 +307,28 @@ module Rack
362
307
  end
363
308
  }
364
309
 
365
- header["Set-Cookie"] = cookies.join("\n")
366
-
367
- set_cookie_header!(header, key,
368
- {:value => '', :path => nil, :domain => nil,
369
- :max_age => '0',
370
- :expires => Time.at(0) }.merge(value))
310
+ cookies.join("\n")
311
+ end
312
+ module_function :make_delete_cookie_header
371
313
 
314
+ def delete_cookie_header!(header, key, value = {})
315
+ header[SET_COOKIE] = add_remove_cookie_to_header(header[SET_COOKIE], key, value)
372
316
  nil
373
317
  end
374
318
  module_function :delete_cookie_header!
375
319
 
376
- # Return the bytesize of String; uses String#size under Ruby 1.8 and
377
- # String#bytesize under 1.9.
378
- if ''.respond_to?(:bytesize)
379
- def bytesize(string)
380
- string.bytesize
381
- end
382
- else
383
- def bytesize(string)
384
- string.size
385
- end
320
+ # Adds a cookie that will *remove* a cookie from the client. Hence the
321
+ # strange method name.
322
+ def add_remove_cookie_to_header(header, key, value = {})
323
+ new_header = make_delete_cookie_header(header, key, value)
324
+
325
+ add_cookie_to_header(new_header, key,
326
+ {:value => '', :path => nil, :domain => nil,
327
+ :max_age => '0',
328
+ :expires => Time.at(0) }.merge(value))
329
+
386
330
  end
387
- module_function :bytesize
331
+ module_function :add_remove_cookie_to_header
388
332
 
389
333
  def rfc2822(time)
390
334
  time.rfc2822
@@ -411,8 +355,13 @@ module Rack
411
355
  # Returns nil if the header is missing or syntactically invalid.
412
356
  # Returns an empty array if none of the ranges are satisfiable.
413
357
  def byte_ranges(env, size)
358
+ warn "`byte_ranges` is deprecated, please use `get_byte_ranges`" if $VERBOSE
359
+ get_byte_ranges env['HTTP_RANGE'], size
360
+ end
361
+ module_function :byte_ranges
362
+
363
+ def get_byte_ranges(http_range, size)
414
364
  # See <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35>
415
- http_range = env['HTTP_RANGE']
416
365
  return nil unless http_range && http_range =~ /bytes=([^;]+)/
417
366
  ranges = []
418
367
  $1.split(/,\s*/).each do |range_spec|
@@ -438,7 +387,7 @@ module Rack
438
387
  end
439
388
  ranges
440
389
  end
441
- module_function :byte_ranges
390
+ module_function :get_byte_ranges
442
391
 
443
392
  # Constant time string comparison.
444
393
  #
@@ -447,7 +396,7 @@ module Rack
447
396
  # on variable length plaintext strings because it could leak length info
448
397
  # via timing attacks.
449
398
  def secure_compare(a, b)
450
- return false unless bytesize(a) == bytesize(b)
399
+ return false unless a.bytesize == b.bytesize
451
400
 
452
401
  l = a.unpack("C*")
453
402
 
@@ -496,6 +445,12 @@ module Rack
496
445
  hash.each { |k, v| self[k] = v }
497
446
  end
498
447
 
448
+ # on dup/clone, we need to duplicate @names hash
449
+ def initialize_copy(other)
450
+ super
451
+ @names = other.names.dup
452
+ end
453
+
499
454
  def each
500
455
  super do |k, v|
501
456
  yield(k, v.respond_to?(:to_ary) ? v.to_ary.join("\n") : v)
@@ -513,21 +468,20 @@ module Rack
513
468
  end
514
469
 
515
470
  def []=(k, v)
516
- canonical = k.downcase
471
+ canonical = k.downcase.freeze
517
472
  delete k if @names[canonical] && @names[canonical] != k # .delete is expensive, don't invoke it unless necessary
518
- @names[k] = @names[canonical] = k
473
+ @names[canonical] = k
519
474
  super k, v
520
475
  end
521
476
 
522
477
  def delete(k)
523
478
  canonical = k.downcase
524
479
  result = super @names.delete(canonical)
525
- @names.delete_if { |name,| name.downcase == canonical }
526
480
  result
527
481
  end
528
482
 
529
483
  def include?(k)
530
- @names.include?(k) || @names.include?(k.downcase)
484
+ super || @names.include?(k.downcase)
531
485
  end
532
486
 
533
487
  alias_method :has_key?, :include?
@@ -549,45 +503,11 @@ module Rack
549
503
  other.each { |k, v| self[k] = v }
550
504
  self
551
505
  end
552
- end
553
-
554
- class KeySpaceConstrainedParams
555
- def initialize(limit = Utils.key_space_limit)
556
- @limit = limit
557
- @size = 0
558
- @params = {}
559
- end
560
-
561
- def [](key)
562
- @params[key]
563
- end
564
506
 
565
- def []=(key, value)
566
- @size += key.size if key && !@params.key?(key)
567
- raise RangeError, 'exceeded available parameter key space' if @size > @limit
568
- @params[key] = value
569
- end
570
-
571
- def key?(key)
572
- @params.key?(key)
573
- end
574
-
575
- def to_params_hash
576
- hash = @params
577
- hash.keys.each do |key|
578
- value = hash[key]
579
- if value.kind_of?(self.class)
580
- if value.object_id == self.object_id
581
- hash[key] = hash
582
- else
583
- hash[key] = value.to_params_hash
584
- end
585
- elsif value.kind_of?(Array)
586
- value.map! {|x| x.kind_of?(self.class) ? x.to_params_hash : x}
587
- end
507
+ protected
508
+ def names
509
+ @names
588
510
  end
589
- hash
590
- end
591
511
  end
592
512
 
593
513
  # Every standard HTTP code mapped to the appropriate message.
@@ -635,6 +555,7 @@ module Rack
635
555
  415 => 'Unsupported Media Type',
636
556
  416 => 'Range Not Satisfiable',
637
557
  417 => 'Expectation Failed',
558
+ 421 => 'Misdirected Request',
638
559
  422 => 'Unprocessable Entity',
639
560
  423 => 'Locked',
640
561
  424 => 'Failed Dependency',
@@ -642,6 +563,7 @@ module Rack
642
563
  428 => 'Precondition Required',
643
564
  429 => 'Too Many Requests',
644
565
  431 => 'Request Header Fields Too Large',
566
+ 451 => 'Unavailable for Legal Reasons',
645
567
  500 => 'Internal Server Error',
646
568
  501 => 'Not Implemented',
647
569
  502 => 'Bad Gateway',
@@ -656,7 +578,7 @@ module Rack
656
578
  }
657
579
 
658
580
  # Responses with HTTP status codes that should not have an entity body
659
- STATUS_WITH_NO_ENTITY_BODY = Set.new((100..199).to_a << 204 << 205 << 304)
581
+ STATUS_WITH_NO_ENTITY_BODY = Set.new((100..199).to_a << 204 << 304)
660
582
 
661
583
  SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message|
662
584
  [message.downcase.gsub(/\s|-|'/, '_').to_sym, code]
@@ -671,8 +593,6 @@ module Rack
671
593
  end
672
594
  module_function :status_code
673
595
 
674
- Multipart = Rack::Multipart
675
-
676
596
  PATH_SEPS = Regexp.union(*[::File::SEPARATOR, ::File::ALT_SEPARATOR].compact)
677
597
 
678
598
  def clean_path_info(path_info)
@@ -691,5 +611,12 @@ module Rack
691
611
  end
692
612
  module_function :clean_path_info
693
613
 
614
+ NULL_BYTE = "\0".freeze
615
+
616
+ def valid_path?(path)
617
+ path.valid_encoding? && !path.include?(NULL_BYTE)
618
+ end
619
+ module_function :valid_path?
620
+
694
621
  end
695
622
  end
data/lib/rack.rb CHANGED
@@ -7,7 +7,7 @@
7
7
  # modules and classes.
8
8
  #
9
9
  # All modules meant for use in your application are <tt>autoload</tt>ed here,
10
- # so it should be enough just to <tt>require rack.rb</tt> in your code.
10
+ # so it should be enough just to <tt>require 'rack'</tt> in your code.
11
11
 
12
12
  module Rack
13
13
  # The Rack protocol version number implemented.
@@ -18,27 +18,80 @@ module Rack
18
18
  VERSION.join(".")
19
19
  end
20
20
 
21
+ RELEASE = "2.0.9"
22
+
21
23
  # Return the Rack release as a dotted string.
22
24
  def self.release
23
- "1.6.13"
25
+ RELEASE
24
26
  end
25
- PATH_INFO = 'PATH_INFO'.freeze
26
- REQUEST_METHOD = 'REQUEST_METHOD'.freeze
27
- SCRIPT_NAME = 'SCRIPT_NAME'.freeze
28
- QUERY_STRING = 'QUERY_STRING'.freeze
29
- CACHE_CONTROL = 'Cache-Control'.freeze
30
- CONTENT_LENGTH = 'Content-Length'.freeze
31
- CONTENT_TYPE = 'Content-Type'.freeze
32
27
 
33
- GET = 'GET'.freeze
34
- HEAD = 'HEAD'.freeze
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
47
+
48
+ # 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
59
+
60
+ # 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
35
88
 
36
89
  autoload :Builder, "rack/builder"
37
90
  autoload :BodyProxy, "rack/body_proxy"
38
91
  autoload :Cascade, "rack/cascade"
39
92
  autoload :Chunked, "rack/chunked"
40
- autoload :CommonLogger, "rack/commonlogger"
41
- autoload :ConditionalGet, "rack/conditionalget"
93
+ autoload :CommonLogger, "rack/common_logger"
94
+ autoload :ConditionalGet, "rack/conditional_get"
42
95
  autoload :Config, "rack/config"
43
96
  autoload :ContentLength, "rack/content_length"
44
97
  autoload :ContentType, "rack/content_type"
@@ -52,16 +105,16 @@ module Rack
52
105
  autoload :Lint, "rack/lint"
53
106
  autoload :Lock, "rack/lock"
54
107
  autoload :Logger, "rack/logger"
55
- autoload :MethodOverride, "rack/methodoverride"
108
+ autoload :MethodOverride, "rack/method_override"
56
109
  autoload :Mime, "rack/mime"
57
- autoload :NullLogger, "rack/nulllogger"
110
+ autoload :NullLogger, "rack/null_logger"
58
111
  autoload :Recursive, "rack/recursive"
59
112
  autoload :Reloader, "rack/reloader"
60
113
  autoload :Runtime, "rack/runtime"
61
114
  autoload :Sendfile, "rack/sendfile"
62
115
  autoload :Server, "rack/server"
63
- autoload :ShowExceptions, "rack/showexceptions"
64
- autoload :ShowStatus, "rack/showstatus"
116
+ autoload :ShowExceptions, "rack/show_exceptions"
117
+ autoload :ShowStatus, "rack/show_status"
65
118
  autoload :Static, "rack/static"
66
119
  autoload :TempfileReaper, "rack/tempfile_reaper"
67
120
  autoload :URLMap, "rack/urlmap"
@@ -91,8 +144,4 @@ module Rack
91
144
  autoload :Pool, "rack/session/pool"
92
145
  autoload :Memcache, "rack/session/memcache"
93
146
  end
94
-
95
- module Utils
96
- autoload :OkJson, "rack/utils/okjson"
97
- end
98
147
  end