rack 1.4.7 → 2.1.4

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 (183) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +77 -0
  3. data/{COPYING → MIT-LICENSE} +4 -2
  4. data/README.rdoc +122 -456
  5. data/Rakefile +32 -31
  6. data/SPEC +119 -29
  7. data/bin/rackup +1 -0
  8. data/contrib/rack_logo.svg +164 -111
  9. data/example/lobster.ru +2 -0
  10. data/example/protectedlobster.rb +4 -2
  11. data/example/protectedlobster.ru +3 -1
  12. data/lib/rack/auth/abstract/handler.rb +7 -5
  13. data/lib/rack/auth/abstract/request.rb +8 -6
  14. data/lib/rack/auth/basic.rb +5 -2
  15. data/lib/rack/auth/digest/md5.rb +10 -8
  16. data/lib/rack/auth/digest/nonce.rb +6 -3
  17. data/lib/rack/auth/digest/params.rb +5 -4
  18. data/lib/rack/auth/digest/request.rb +4 -2
  19. data/lib/rack/body_proxy.rb +11 -9
  20. data/lib/rack/builder.rb +63 -20
  21. data/lib/rack/cascade.rb +10 -9
  22. data/lib/rack/chunked.rb +45 -11
  23. data/lib/rack/{commonlogger.rb → common_logger.rb} +24 -15
  24. data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -6
  25. data/lib/rack/config.rb +7 -0
  26. data/lib/rack/content_length.rb +12 -6
  27. data/lib/rack/content_type.rb +4 -2
  28. data/lib/rack/core_ext/regexp.rb +14 -0
  29. data/lib/rack/deflater.rb +73 -42
  30. data/lib/rack/directory.rb +77 -56
  31. data/lib/rack/etag.rb +25 -13
  32. data/lib/rack/events.rb +156 -0
  33. data/lib/rack/file.rb +4 -143
  34. data/lib/rack/files.rb +178 -0
  35. data/lib/rack/handler/cgi.rb +18 -17
  36. data/lib/rack/handler/fastcgi.rb +21 -17
  37. data/lib/rack/handler/lsws.rb +14 -12
  38. data/lib/rack/handler/scgi.rb +27 -21
  39. data/lib/rack/handler/thin.rb +19 -5
  40. data/lib/rack/handler/webrick.rb +66 -24
  41. data/lib/rack/handler.rb +29 -19
  42. data/lib/rack/head.rb +21 -14
  43. data/lib/rack/lint.rb +259 -65
  44. data/lib/rack/lobster.rb +17 -10
  45. data/lib/rack/lock.rb +19 -10
  46. data/lib/rack/logger.rb +4 -2
  47. data/lib/rack/media_type.rb +43 -0
  48. data/lib/rack/method_override.rb +52 -0
  49. data/lib/rack/mime.rb +43 -6
  50. data/lib/rack/mock.rb +109 -44
  51. data/lib/rack/multipart/generator.rb +11 -12
  52. data/lib/rack/multipart/parser.rb +302 -115
  53. data/lib/rack/multipart/uploaded_file.rb +4 -3
  54. data/lib/rack/multipart.rb +40 -9
  55. data/lib/rack/null_logger.rb +39 -0
  56. data/lib/rack/query_parser.rb +218 -0
  57. data/lib/rack/recursive.rb +14 -11
  58. data/lib/rack/reloader.rb +12 -5
  59. data/lib/rack/request.rb +484 -270
  60. data/lib/rack/response.rb +196 -77
  61. data/lib/rack/rewindable_input.rb +5 -14
  62. data/lib/rack/runtime.rb +13 -6
  63. data/lib/rack/sendfile.rb +44 -20
  64. data/lib/rack/server.rb +175 -61
  65. data/lib/rack/session/abstract/id.rb +276 -133
  66. data/lib/rack/session/cookie.rb +75 -40
  67. data/lib/rack/session/memcache.rb +4 -87
  68. data/lib/rack/session/pool.rb +24 -18
  69. data/lib/rack/show_exceptions.rb +392 -0
  70. data/lib/rack/{showstatus.rb → show_status.rb} +11 -9
  71. data/lib/rack/static.rb +65 -38
  72. data/lib/rack/tempfile_reaper.rb +24 -0
  73. data/lib/rack/urlmap.rb +40 -15
  74. data/lib/rack/utils.rb +316 -285
  75. data/lib/rack.rb +78 -23
  76. data/rack.gemspec +26 -19
  77. metadata +44 -209
  78. data/KNOWN-ISSUES +0 -30
  79. data/lib/rack/backports/uri/common_18.rb +0 -56
  80. data/lib/rack/backports/uri/common_192.rb +0 -52
  81. data/lib/rack/backports/uri/common_193.rb +0 -29
  82. data/lib/rack/handler/evented_mongrel.rb +0 -8
  83. data/lib/rack/handler/mongrel.rb +0 -100
  84. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  85. data/lib/rack/methodoverride.rb +0 -33
  86. data/lib/rack/nulllogger.rb +0 -18
  87. data/lib/rack/showexceptions.rb +0 -378
  88. data/test/builder/anything.rb +0 -5
  89. data/test/builder/comment.ru +0 -4
  90. data/test/builder/end.ru +0 -5
  91. data/test/builder/line.ru +0 -1
  92. data/test/builder/options.ru +0 -2
  93. data/test/cgi/assets/folder/test.js +0 -1
  94. data/test/cgi/assets/fonts/font.eot +0 -1
  95. data/test/cgi/assets/images/image.png +0 -1
  96. data/test/cgi/assets/index.html +0 -1
  97. data/test/cgi/assets/javascripts/app.js +0 -1
  98. data/test/cgi/assets/stylesheets/app.css +0 -1
  99. data/test/cgi/lighttpd.conf +0 -26
  100. data/test/cgi/lighttpd.errors +0 -1
  101. data/test/cgi/rackup_stub.rb +0 -6
  102. data/test/cgi/sample_rackup.ru +0 -5
  103. data/test/cgi/test +0 -9
  104. data/test/cgi/test+directory/test+file +0 -1
  105. data/test/cgi/test.fcgi +0 -8
  106. data/test/cgi/test.ru +0 -5
  107. data/test/gemloader.rb +0 -10
  108. data/test/multipart/bad_robots +0 -259
  109. data/test/multipart/binary +0 -0
  110. data/test/multipart/content_type_and_no_filename +0 -6
  111. data/test/multipart/empty +0 -10
  112. data/test/multipart/fail_16384_nofile +0 -814
  113. data/test/multipart/file1.txt +0 -1
  114. data/test/multipart/filename_and_modification_param +0 -7
  115. data/test/multipart/filename_with_escaped_quotes +0 -6
  116. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  117. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  118. data/test/multipart/filename_with_unescaped_percentages +0 -6
  119. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  120. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  121. data/test/multipart/filename_with_unescaped_quotes +0 -6
  122. data/test/multipart/ie +0 -6
  123. data/test/multipart/mixed_files +0 -21
  124. data/test/multipart/nested +0 -10
  125. data/test/multipart/none +0 -9
  126. data/test/multipart/semicolon +0 -6
  127. data/test/multipart/text +0 -15
  128. data/test/multipart/three_files_three_fields +0 -31
  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.rb +0 -57
  133. data/test/spec_auth_basic.rb +0 -81
  134. data/test/spec_auth_digest.rb +0 -259
  135. data/test/spec_body_proxy.rb +0 -69
  136. data/test/spec_builder.rb +0 -207
  137. data/test/spec_cascade.rb +0 -61
  138. data/test/spec_cgi.rb +0 -102
  139. data/test/spec_chunked.rb +0 -87
  140. data/test/spec_commonlogger.rb +0 -57
  141. data/test/spec_conditionalget.rb +0 -102
  142. data/test/spec_config.rb +0 -22
  143. data/test/spec_content_length.rb +0 -86
  144. data/test/spec_content_type.rb +0 -45
  145. data/test/spec_deflater.rb +0 -187
  146. data/test/spec_directory.rb +0 -88
  147. data/test/spec_etag.rb +0 -98
  148. data/test/spec_fastcgi.rb +0 -107
  149. data/test/spec_file.rb +0 -200
  150. data/test/spec_handler.rb +0 -59
  151. data/test/spec_head.rb +0 -48
  152. data/test/spec_lint.rb +0 -515
  153. data/test/spec_lobster.rb +0 -58
  154. data/test/spec_lock.rb +0 -167
  155. data/test/spec_logger.rb +0 -23
  156. data/test/spec_methodoverride.rb +0 -72
  157. data/test/spec_mock.rb +0 -269
  158. data/test/spec_mongrel.rb +0 -182
  159. data/test/spec_multipart.rb +0 -479
  160. data/test/spec_nulllogger.rb +0 -23
  161. data/test/spec_recursive.rb +0 -72
  162. data/test/spec_request.rb +0 -955
  163. data/test/spec_response.rb +0 -313
  164. data/test/spec_rewindable_input.rb +0 -118
  165. data/test/spec_runtime.rb +0 -49
  166. data/test/spec_sendfile.rb +0 -90
  167. data/test/spec_server.rb +0 -121
  168. data/test/spec_session_abstract_id.rb +0 -43
  169. data/test/spec_session_cookie.rb +0 -361
  170. data/test/spec_session_memcache.rb +0 -321
  171. data/test/spec_session_pool.rb +0 -209
  172. data/test/spec_showexceptions.rb +0 -92
  173. data/test/spec_showstatus.rb +0 -84
  174. data/test/spec_static.rb +0 -145
  175. data/test/spec_thin.rb +0 -86
  176. data/test/spec_urlmap.rb +0 -213
  177. data/test/spec_utils.rb +0 -554
  178. data/test/spec_webrick.rb +0 -143
  179. data/test/static/another/index.html +0 -1
  180. data/test/static/index.html +0 -1
  181. data/test/testrequest.rb +0 -78
  182. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  183. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
@@ -0,0 +1,218 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'core_ext/regexp'
4
+
5
+ module Rack
6
+ class QueryParser
7
+ using ::Rack::RegexpExtensions
8
+
9
+ DEFAULT_SEP = /[&;] */n
10
+ COMMON_SEP = { ";" => /[;] */n, ";," => /[;,] */n, "&" => /[&] */n }
11
+
12
+ # ParameterTypeError is the error that is raised when incoming structural
13
+ # parameters (parsed by parse_nested_query) contain conflicting types.
14
+ class ParameterTypeError < TypeError; end
15
+
16
+ # InvalidParameterError is the error that is raised when incoming structural
17
+ # parameters (parsed by parse_nested_query) contain invalid format or byte
18
+ # sequence.
19
+ class InvalidParameterError < ArgumentError; end
20
+
21
+ def self.make_default(key_space_limit, param_depth_limit)
22
+ new Params, key_space_limit, param_depth_limit
23
+ end
24
+
25
+ attr_reader :key_space_limit, :param_depth_limit
26
+
27
+ def initialize(params_class, key_space_limit, param_depth_limit)
28
+ @params_class = params_class
29
+ @key_space_limit = key_space_limit
30
+ @param_depth_limit = param_depth_limit
31
+ end
32
+
33
+ # Stolen from Mongrel, with some small modifications:
34
+ # Parses a query string by breaking it up at the '&'
35
+ # and ';' characters. You can also use this to parse
36
+ # cookies by changing the characters used in the second
37
+ # parameter (which defaults to '&;').
38
+ def parse_query(qs, d = nil, &unescaper)
39
+ unescaper ||= method(:unescape)
40
+
41
+ params = make_params
42
+
43
+ (qs || '').split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p|
44
+ next if p.empty?
45
+ k, v = p.split('=', 2).map!(&unescaper)
46
+
47
+ if cur = params[k]
48
+ if cur.class == Array
49
+ params[k] << v
50
+ else
51
+ params[k] = [cur, v]
52
+ end
53
+ else
54
+ params[k] = v
55
+ end
56
+ end
57
+
58
+ return params.to_h
59
+ end
60
+
61
+ # parse_nested_query expands a query string into structural types. Supported
62
+ # types are Arrays, Hashes and basic value types. It is possible to supply
63
+ # query strings with parameters of conflicting types, in this case a
64
+ # ParameterTypeError is raised. Users are encouraged to return a 400 in this
65
+ # case.
66
+ def parse_nested_query(qs, d = nil)
67
+ return {} if qs.nil? || qs.empty?
68
+ params = make_params
69
+
70
+ qs.split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p|
71
+ k, v = p.split('=', 2).map! { |s| unescape(s) }
72
+
73
+ normalize_params(params, k, v, param_depth_limit)
74
+ end
75
+
76
+ return params.to_h
77
+ rescue ArgumentError => e
78
+ raise InvalidParameterError, e.message
79
+ end
80
+
81
+ # normalize_params recursively expands parameters into structural types. If
82
+ # the structural types represented by two different parameter names are in
83
+ # conflict, a ParameterTypeError is raised.
84
+ def normalize_params(params, name, v, depth)
85
+ raise RangeError if depth <= 0
86
+
87
+ name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
88
+ k = $1 || ''
89
+ after = $' || ''
90
+
91
+ if k.empty?
92
+ if !v.nil? && name == "[]"
93
+ return Array(v)
94
+ else
95
+ return
96
+ end
97
+ end
98
+
99
+ if after == ''
100
+ params[k] = v
101
+ elsif after == "["
102
+ params[name] = v
103
+ elsif after == "[]"
104
+ params[k] ||= []
105
+ raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
106
+ params[k] << v
107
+ elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$)
108
+ child_key = $1
109
+ params[k] ||= []
110
+ raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
111
+ if params_hash_type?(params[k].last) && !params_hash_has_key?(params[k].last, child_key)
112
+ normalize_params(params[k].last, child_key, v, depth - 1)
113
+ else
114
+ params[k] << normalize_params(make_params, child_key, v, depth - 1)
115
+ end
116
+ else
117
+ params[k] ||= make_params
118
+ raise ParameterTypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params_hash_type?(params[k])
119
+ params[k] = normalize_params(params[k], after, v, depth - 1)
120
+ end
121
+
122
+ params
123
+ end
124
+
125
+ def make_params
126
+ @params_class.new @key_space_limit
127
+ end
128
+
129
+ def new_space_limit(key_space_limit)
130
+ self.class.new @params_class, key_space_limit, param_depth_limit
131
+ end
132
+
133
+ def new_depth_limit(param_depth_limit)
134
+ self.class.new @params_class, key_space_limit, param_depth_limit
135
+ end
136
+
137
+ private
138
+
139
+ def params_hash_type?(obj)
140
+ obj.kind_of?(@params_class)
141
+ end
142
+
143
+ def params_hash_has_key?(hash, key)
144
+ return false if /\[\]/.match?(key)
145
+
146
+ key.split(/[\[\]]+/).inject(hash) do |h, part|
147
+ next h if part == ''
148
+ return false unless params_hash_type?(h) && h.key?(part)
149
+ h[part]
150
+ end
151
+
152
+ true
153
+ end
154
+
155
+ def unescape(s)
156
+ Utils.unescape(s)
157
+ end
158
+
159
+ class Params
160
+ def initialize(limit)
161
+ @limit = limit
162
+ @size = 0
163
+ @params = {}
164
+ end
165
+
166
+ def [](key)
167
+ @params[key]
168
+ end
169
+
170
+ def []=(key, value)
171
+ @size += key.size if key && !@params.key?(key)
172
+ raise RangeError, 'exceeded available parameter key space' if @size > @limit
173
+ @params[key] = value
174
+ end
175
+
176
+ def key?(key)
177
+ @params.key?(key)
178
+ end
179
+
180
+ # Recursively unwraps nested `Params` objects and constructs an object
181
+ # of the same shape, but using the objects' internal representations
182
+ # (Ruby hashes) in place of the objects. The result is a hash consisting
183
+ # purely of Ruby primitives.
184
+ #
185
+ # Mutation warning!
186
+ #
187
+ # 1. This method mutates the internal representation of the `Params`
188
+ # objects in order to save object allocations.
189
+ #
190
+ # 2. The value you get back is a reference to the internal hash
191
+ # representation, not a copy.
192
+ #
193
+ # 3. Because the `Params` object's internal representation is mutable
194
+ # through the `#[]=` method, it is not thread safe. The result of
195
+ # getting the hash representation while another thread is adding a
196
+ # key to it is non-deterministic.
197
+ #
198
+ def to_h
199
+ @params.each do |key, value|
200
+ case value
201
+ when self
202
+ # Handle circular references gracefully.
203
+ @params[key] = @params
204
+ when Params
205
+ @params[key] = value.to_h
206
+ when Array
207
+ value.map! { |v| v.kind_of?(Params) ? v.to_h : v }
208
+ else
209
+ # Ignore anything that is not a `Params` object or
210
+ # a collection that can contain one.
211
+ end
212
+ end
213
+ @params
214
+ end
215
+ alias_method :to_params_hash, :to_h
216
+ end
217
+ end
218
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'uri'
2
4
 
3
5
  module Rack
@@ -10,15 +12,15 @@ module Rack
10
12
  class ForwardRequest < Exception
11
13
  attr_reader :url, :env
12
14
 
13
- def initialize(url, env={})
15
+ def initialize(url, env = {})
14
16
  @url = URI(url)
15
17
  @env = env
16
18
 
17
- @env["PATH_INFO"] = @url.path
18
- @env["QUERY_STRING"] = @url.query if @url.query
19
- @env["HTTP_HOST"] = @url.host if @url.host
20
- @env["HTTP_PORT"] = @url.port if @url.port
21
- @env["rack.url_scheme"] = @url.scheme if @url.scheme
19
+ @env[PATH_INFO] = @url.path
20
+ @env[QUERY_STRING] = @url.query if @url.query
21
+ @env[HTTP_HOST] = @url.host if @url.host
22
+ @env["HTTP_PORT"] = @url.port if @url.port
23
+ @env[RACK_URL_SCHEME] = @url.scheme if @url.scheme
22
24
 
23
25
  super "forwarding to #{url}"
24
26
  end
@@ -39,8 +41,8 @@ module Rack
39
41
  end
40
42
 
41
43
  def _call(env)
42
- @script_name = env["SCRIPT_NAME"]
43
- @app.call(env.merge('rack.recursive.include' => method(:include)))
44
+ @script_name = env[SCRIPT_NAME]
45
+ @app.call(env.merge(RACK_RECURSIVE_INCLUDE => method(:include)))
44
46
  rescue ForwardRequest => req
45
47
  call(env.merge(req.env))
46
48
  end
@@ -51,10 +53,11 @@ module Rack
51
53
  raise ArgumentError, "can only include below #{@script_name}, not #{path}"
52
54
  end
53
55
 
54
- env = env.merge("PATH_INFO" => path, "SCRIPT_NAME" => @script_name,
55
- "REQUEST_METHOD" => "GET",
56
+ env = env.merge(PATH_INFO => path,
57
+ SCRIPT_NAME => @script_name,
58
+ REQUEST_METHOD => GET,
56
59
  "CONTENT_LENGTH" => "0", "CONTENT_TYPE" => "",
57
- "rack.input" => StringIO.new(""))
60
+ RACK_INPUT => StringIO.new(""))
58
61
  @app.call(env)
59
62
  end
60
63
  end
data/lib/rack/reloader.rb CHANGED
@@ -1,9 +1,13 @@
1
- # Copyright (c) 2009 Michael Fellinger m.fellinger@gmail.com
2
- # Rack::Reloader is subject to the terms of an MIT-style license.
3
- # See COPYING or http://www.opensource.org/licenses/mit-license.php.
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2009-2018 Michael Fellinger <m.fellinger@gmail.com>
4
+ # Rack::Reloader is subject to the terms of an MIT-style license.
5
+ # See MIT-LICENSE or https://opensource.org/licenses/MIT.
4
6
 
5
7
  require 'pathname'
6
8
 
9
+ require_relative 'core_ext/regexp'
10
+
7
11
  module Rack
8
12
 
9
13
  # High performant source reloader
@@ -20,12 +24,15 @@ module Rack
20
24
  # It is performing a check/reload cycle at the start of every request, but
21
25
  # also respects a cool down time, during which nothing will be done.
22
26
  class Reloader
27
+ using ::Rack::RegexpExtensions
28
+
23
29
  def initialize(app, cooldown = 10, backend = Stat)
24
30
  @app = app
25
31
  @cooldown = cooldown
26
32
  @last = (Time.now - cooldown)
27
33
  @cache = {}
28
34
  @mtimes = {}
35
+ @reload_mutex = Mutex.new
29
36
 
30
37
  extend backend
31
38
  end
@@ -33,7 +40,7 @@ module Rack
33
40
  def call(env)
34
41
  if @cooldown and Time.now > @last + @cooldown
35
42
  if Thread.list.size > 1
36
- Thread.exclusive{ reload! }
43
+ @reload_mutex.synchronize{ reload! }
37
44
  else
38
45
  reload!
39
46
  end
@@ -68,7 +75,7 @@ module Rack
68
75
  paths = ['./', *$LOAD_PATH].uniq
69
76
 
70
77
  files.map{|file|
71
- next if file =~ /\.(so|bundle)$/ # cannot reload compiled files
78
+ next if /\.(so|bundle)$/.match?(file) # cannot reload compiled files
72
79
 
73
80
  found, stat = figure_path(file, paths)
74
81
  next unless found && stat && mtime = stat.mtime