rack 2.1.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +377 -16
  3. data/CONTRIBUTING.md +144 -0
  4. data/MIT-LICENSE +1 -1
  5. data/README.md +328 -0
  6. data/SPEC.rdoc +365 -0
  7. data/lib/rack/auth/abstract/handler.rb +3 -1
  8. data/lib/rack/auth/abstract/request.rb +2 -2
  9. data/lib/rack/auth/basic.rb +4 -7
  10. data/lib/rack/bad_request.rb +8 -0
  11. data/lib/rack/body_proxy.rb +34 -12
  12. data/lib/rack/builder.rb +162 -59
  13. data/lib/rack/cascade.rb +24 -10
  14. data/lib/rack/common_logger.rb +43 -28
  15. data/lib/rack/conditional_get.rb +30 -25
  16. data/lib/rack/constants.rb +66 -0
  17. data/lib/rack/content_length.rb +10 -16
  18. data/lib/rack/content_type.rb +9 -7
  19. data/lib/rack/deflater.rb +78 -50
  20. data/lib/rack/directory.rb +86 -63
  21. data/lib/rack/etag.rb +14 -22
  22. data/lib/rack/events.rb +18 -17
  23. data/lib/rack/files.rb +99 -61
  24. data/lib/rack/head.rb +8 -9
  25. data/lib/rack/headers.rb +238 -0
  26. data/lib/rack/lint.rb +868 -642
  27. data/lib/rack/lock.rb +2 -6
  28. data/lib/rack/logger.rb +3 -0
  29. data/lib/rack/media_type.rb +9 -4
  30. data/lib/rack/method_override.rb +6 -2
  31. data/lib/rack/mime.rb +14 -5
  32. data/lib/rack/mock.rb +1 -253
  33. data/lib/rack/mock_request.rb +171 -0
  34. data/lib/rack/mock_response.rb +124 -0
  35. data/lib/rack/multipart/generator.rb +15 -8
  36. data/lib/rack/multipart/parser.rb +238 -107
  37. data/lib/rack/multipart/uploaded_file.rb +17 -7
  38. data/lib/rack/multipart.rb +54 -42
  39. data/lib/rack/null_logger.rb +9 -0
  40. data/lib/rack/query_parser.rb +87 -105
  41. data/lib/rack/recursive.rb +3 -1
  42. data/lib/rack/reloader.rb +0 -4
  43. data/lib/rack/request.rb +366 -135
  44. data/lib/rack/response.rb +186 -68
  45. data/lib/rack/rewindable_input.rb +24 -6
  46. data/lib/rack/runtime.rb +8 -7
  47. data/lib/rack/sendfile.rb +29 -27
  48. data/lib/rack/show_exceptions.rb +27 -12
  49. data/lib/rack/show_status.rb +21 -13
  50. data/lib/rack/static.rb +19 -12
  51. data/lib/rack/tempfile_reaper.rb +14 -5
  52. data/lib/rack/urlmap.rb +5 -6
  53. data/lib/rack/utils.rb +274 -260
  54. data/lib/rack/version.rb +21 -0
  55. data/lib/rack.rb +18 -103
  56. metadata +25 -52
  57. data/README.rdoc +0 -262
  58. data/Rakefile +0 -123
  59. data/SPEC +0 -263
  60. data/bin/rackup +0 -5
  61. data/contrib/rack.png +0 -0
  62. data/contrib/rack.svg +0 -150
  63. data/contrib/rack_logo.svg +0 -164
  64. data/contrib/rdoc.css +0 -412
  65. data/example/lobster.ru +0 -6
  66. data/example/protectedlobster.rb +0 -16
  67. data/example/protectedlobster.ru +0 -10
  68. data/lib/rack/auth/digest/md5.rb +0 -131
  69. data/lib/rack/auth/digest/nonce.rb +0 -54
  70. data/lib/rack/auth/digest/params.rb +0 -54
  71. data/lib/rack/auth/digest/request.rb +0 -43
  72. data/lib/rack/chunked.rb +0 -92
  73. data/lib/rack/core_ext/regexp.rb +0 -14
  74. data/lib/rack/file.rb +0 -8
  75. data/lib/rack/handler/cgi.rb +0 -62
  76. data/lib/rack/handler/fastcgi.rb +0 -102
  77. data/lib/rack/handler/lsws.rb +0 -63
  78. data/lib/rack/handler/scgi.rb +0 -73
  79. data/lib/rack/handler/thin.rb +0 -38
  80. data/lib/rack/handler/webrick.rb +0 -122
  81. data/lib/rack/handler.rb +0 -104
  82. data/lib/rack/lobster.rb +0 -72
  83. data/lib/rack/server.rb +0 -467
  84. data/lib/rack/session/abstract/id.rb +0 -528
  85. data/lib/rack/session/cookie.rb +0 -205
  86. data/lib/rack/session/memcache.rb +0 -10
  87. data/lib/rack/session/pool.rb +0 -85
  88. data/rack.gemspec +0 -44
@@ -1,528 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # AUTHOR: blink <blinketje@gmail.com>; blink#ruby-lang@irc.freenode.net
4
- # bugrep: Andreas Zehnder
5
-
6
- require 'rack'
7
- require 'time'
8
- require 'rack/request'
9
- require 'rack/response'
10
- require 'securerandom'
11
- require 'digest/sha2'
12
-
13
- module Rack
14
-
15
- module Session
16
-
17
- class SessionId
18
- ID_VERSION = 2
19
-
20
- attr_reader :public_id
21
-
22
- def initialize(public_id)
23
- @public_id = public_id
24
- end
25
-
26
- def private_id
27
- "#{ID_VERSION}::#{hash_sid(public_id)}"
28
- end
29
-
30
- alias :cookie_value :public_id
31
-
32
- def empty?; false; end
33
- def to_s; raise; end
34
- def inspect; public_id.inspect; end
35
-
36
- private
37
-
38
- def hash_sid(sid)
39
- Digest::SHA256.hexdigest(sid)
40
- end
41
- end
42
-
43
- module Abstract
44
- # SessionHash is responsible to lazily load the session from store.
45
-
46
- class SessionHash
47
- using Module.new {
48
- refine Hash do
49
- def transform_keys(&block)
50
- hash = {}
51
- each do |key, value|
52
- hash[block.call(key)] = value
53
- end
54
- hash
55
- end
56
- end
57
- } unless {}.respond_to?(:transform_keys)
58
-
59
- def transform_keys(&block)
60
- hash = dup
61
- each do |key, value|
62
- hash[block.call(key)] = value
63
- end
64
- hash
65
- end
66
-
67
- include Enumerable
68
- attr_writer :id
69
-
70
- Unspecified = Object.new
71
-
72
- def self.find(req)
73
- req.get_header RACK_SESSION
74
- end
75
-
76
- def self.set(req, session)
77
- req.set_header RACK_SESSION, session
78
- end
79
-
80
- def self.set_options(req, options)
81
- req.set_header RACK_SESSION_OPTIONS, options.dup
82
- end
83
-
84
- def initialize(store, req)
85
- @store = store
86
- @req = req
87
- @loaded = false
88
- end
89
-
90
- def id
91
- return @id if @loaded or instance_variable_defined?(:@id)
92
- @id = @store.send(:extract_session_id, @req)
93
- end
94
-
95
- def options
96
- @req.session_options
97
- end
98
-
99
- def each(&block)
100
- load_for_read!
101
- @data.each(&block)
102
- end
103
-
104
- def [](key)
105
- load_for_read!
106
- @data[key.to_s]
107
- end
108
-
109
- def fetch(key, default = Unspecified, &block)
110
- load_for_read!
111
- if default == Unspecified
112
- @data.fetch(key.to_s, &block)
113
- else
114
- @data.fetch(key.to_s, default, &block)
115
- end
116
- end
117
-
118
- def has_key?(key)
119
- load_for_read!
120
- @data.has_key?(key.to_s)
121
- end
122
- alias :key? :has_key?
123
- alias :include? :has_key?
124
-
125
- def []=(key, value)
126
- load_for_write!
127
- @data[key.to_s] = value
128
- end
129
- alias :store :[]=
130
-
131
- def clear
132
- load_for_write!
133
- @data.clear
134
- end
135
-
136
- def destroy
137
- clear
138
- @id = @store.send(:delete_session, @req, id, options)
139
- end
140
-
141
- def to_hash
142
- load_for_read!
143
- @data.dup
144
- end
145
-
146
- def update(hash)
147
- load_for_write!
148
- @data.update(stringify_keys(hash))
149
- end
150
- alias :merge! :update
151
-
152
- def replace(hash)
153
- load_for_write!
154
- @data.replace(stringify_keys(hash))
155
- end
156
-
157
- def delete(key)
158
- load_for_write!
159
- @data.delete(key.to_s)
160
- end
161
-
162
- def inspect
163
- if loaded?
164
- @data.inspect
165
- else
166
- "#<#{self.class}:0x#{self.object_id.to_s(16)} not yet loaded>"
167
- end
168
- end
169
-
170
- def exists?
171
- return @exists if instance_variable_defined?(:@exists)
172
- @data = {}
173
- @exists = @store.send(:session_exists?, @req)
174
- end
175
-
176
- def loaded?
177
- @loaded
178
- end
179
-
180
- def empty?
181
- load_for_read!
182
- @data.empty?
183
- end
184
-
185
- def keys
186
- load_for_read!
187
- @data.keys
188
- end
189
-
190
- def values
191
- load_for_read!
192
- @data.values
193
- end
194
-
195
- private
196
-
197
- def load_for_read!
198
- load! if !loaded? && exists?
199
- end
200
-
201
- def load_for_write!
202
- load! unless loaded?
203
- end
204
-
205
- def load!
206
- @id, session = @store.send(:load_session, @req)
207
- @data = stringify_keys(session)
208
- @loaded = true
209
- end
210
-
211
- def stringify_keys(other)
212
- other.transform_keys(&:to_s)
213
- end
214
- end
215
-
216
- # ID sets up a basic framework for implementing an id based sessioning
217
- # service. Cookies sent to the client for maintaining sessions will only
218
- # contain an id reference. Only #find_session and #write_session are
219
- # required to be overwritten.
220
- #
221
- # All parameters are optional.
222
- # * :key determines the name of the cookie, by default it is
223
- # 'rack.session'
224
- # * :path, :domain, :expire_after, :secure, and :httponly set the related
225
- # cookie options as by Rack::Response#set_cookie
226
- # * :skip will not a set a cookie in the response nor update the session state
227
- # * :defer will not set a cookie in the response but still update the session
228
- # state if it is used with a backend
229
- # * :renew (implementation dependent) will prompt the generation of a new
230
- # session id, and migration of data to be referenced at the new id. If
231
- # :defer is set, it will be overridden and the cookie will be set.
232
- # * :sidbits sets the number of bits in length that a generated session
233
- # id will be.
234
- #
235
- # These options can be set on a per request basis, at the location of
236
- # <tt>env['rack.session.options']</tt>. Additionally the id of the
237
- # session can be found within the options hash at the key :id. It is
238
- # highly not recommended to change its value.
239
- #
240
- # Is Rack::Utils::Context compatible.
241
- #
242
- # Not included by default; you must require 'rack/session/abstract/id'
243
- # to use.
244
-
245
- class Persisted
246
- DEFAULT_OPTIONS = {
247
- key: RACK_SESSION,
248
- path: '/',
249
- domain: nil,
250
- expire_after: nil,
251
- secure: false,
252
- httponly: true,
253
- defer: false,
254
- renew: false,
255
- sidbits: 128,
256
- cookie_only: true,
257
- secure_random: ::SecureRandom
258
- }.freeze
259
-
260
- attr_reader :key, :default_options, :sid_secure
261
-
262
- def initialize(app, options = {})
263
- @app = app
264
- @default_options = self.class::DEFAULT_OPTIONS.merge(options)
265
- @key = @default_options.delete(:key)
266
- @cookie_only = @default_options.delete(:cookie_only)
267
- initialize_sid
268
- end
269
-
270
- def call(env)
271
- context(env)
272
- end
273
-
274
- def context(env, app = @app)
275
- req = make_request env
276
- prepare_session(req)
277
- status, headers, body = app.call(req.env)
278
- res = Rack::Response::Raw.new status, headers
279
- commit_session(req, res)
280
- [status, headers, body]
281
- end
282
-
283
- private
284
-
285
- def make_request(env)
286
- Rack::Request.new env
287
- end
288
-
289
- def initialize_sid
290
- @sidbits = @default_options[:sidbits]
291
- @sid_secure = @default_options[:secure_random]
292
- @sid_length = @sidbits / 4
293
- end
294
-
295
- # Generate a new session id using Ruby #rand. The size of the
296
- # session id is controlled by the :sidbits option.
297
- # Monkey patch this to use custom methods for session id generation.
298
-
299
- def generate_sid(secure = @sid_secure)
300
- if secure
301
- secure.hex(@sid_length)
302
- else
303
- "%0#{@sid_length}x" % Kernel.rand(2**@sidbits - 1)
304
- end
305
- rescue NotImplementedError
306
- generate_sid(false)
307
- end
308
-
309
- # Sets the lazy session at 'rack.session' and places options and session
310
- # metadata into 'rack.session.options'.
311
-
312
- def prepare_session(req)
313
- session_was = req.get_header RACK_SESSION
314
- session = session_class.new(self, req)
315
- req.set_header RACK_SESSION, session
316
- req.set_header RACK_SESSION_OPTIONS, @default_options.dup
317
- session.merge! session_was if session_was
318
- end
319
-
320
- # Extracts the session id from provided cookies and passes it and the
321
- # environment to #find_session.
322
-
323
- def load_session(req)
324
- sid = current_session_id(req)
325
- sid, session = find_session(req, sid)
326
- [sid, session || {}]
327
- end
328
-
329
- # Extract session id from request object.
330
-
331
- def extract_session_id(request)
332
- sid = request.cookies[@key]
333
- sid ||= request.params[@key] unless @cookie_only
334
- sid
335
- end
336
-
337
- # Returns the current session id from the SessionHash.
338
-
339
- def current_session_id(req)
340
- req.get_header(RACK_SESSION).id
341
- end
342
-
343
- # Check if the session exists or not.
344
-
345
- def session_exists?(req)
346
- value = current_session_id(req)
347
- value && !value.empty?
348
- end
349
-
350
- # Session should be committed if it was loaded, any of specific options like :renew, :drop
351
- # or :expire_after was given and the security permissions match. Skips if skip is given.
352
-
353
- def commit_session?(req, session, options)
354
- if options[:skip]
355
- false
356
- else
357
- has_session = loaded_session?(session) || forced_session_update?(session, options)
358
- has_session && security_matches?(req, options)
359
- end
360
- end
361
-
362
- def loaded_session?(session)
363
- !session.is_a?(session_class) || session.loaded?
364
- end
365
-
366
- def forced_session_update?(session, options)
367
- force_options?(options) && session && !session.empty?
368
- end
369
-
370
- def force_options?(options)
371
- options.values_at(:max_age, :renew, :drop, :defer, :expire_after).any?
372
- end
373
-
374
- def security_matches?(request, options)
375
- return true unless options[:secure]
376
- request.ssl?
377
- end
378
-
379
- # Acquires the session from the environment and the session id from
380
- # the session options and passes them to #write_session. If successful
381
- # and the :defer option is not true, a cookie will be added to the
382
- # response with the session's id.
383
-
384
- def commit_session(req, res)
385
- session = req.get_header RACK_SESSION
386
- options = session.options
387
-
388
- if options[:drop] || options[:renew]
389
- session_id = delete_session(req, session.id || generate_sid, options)
390
- return unless session_id
391
- end
392
-
393
- return unless commit_session?(req, session, options)
394
-
395
- session.send(:load!) unless loaded_session?(session)
396
- session_id ||= session.id
397
- session_data = session.to_hash.delete_if { |k, v| v.nil? }
398
-
399
- if not data = write_session(req, session_id, session_data, options)
400
- req.get_header(RACK_ERRORS).puts("Warning! #{self.class.name} failed to save session. Content dropped.")
401
- elsif options[:defer] and not options[:renew]
402
- req.get_header(RACK_ERRORS).puts("Deferring cookie for #{session_id}") if $VERBOSE
403
- else
404
- cookie = Hash.new
405
- cookie[:value] = cookie_value(data)
406
- cookie[:expires] = Time.now + options[:expire_after] if options[:expire_after]
407
- cookie[:expires] = Time.now + options[:max_age] if options[:max_age]
408
- set_cookie(req, res, cookie.merge!(options))
409
- end
410
- end
411
- public :commit_session
412
-
413
- def cookie_value(data)
414
- data
415
- end
416
-
417
- # Sets the cookie back to the client with session id. We skip the cookie
418
- # setting if the value didn't change (sid is the same) or expires was given.
419
-
420
- def set_cookie(request, res, cookie)
421
- if request.cookies[@key] != cookie[:value] || cookie[:expires]
422
- res.set_cookie_header =
423
- Utils.add_cookie_to_header(res.set_cookie_header, @key, cookie)
424
- end
425
- end
426
-
427
- # Allow subclasses to prepare_session for different Session classes
428
-
429
- def session_class
430
- SessionHash
431
- end
432
-
433
- # All thread safety and session retrieval procedures should occur here.
434
- # Should return [session_id, session].
435
- # If nil is provided as the session id, generation of a new valid id
436
- # should occur within.
437
-
438
- def find_session(env, sid)
439
- raise '#find_session not implemented.'
440
- end
441
-
442
- # All thread safety and session storage procedures should occur here.
443
- # Must return the session id if the session was saved successfully, or
444
- # false if the session could not be saved.
445
-
446
- def write_session(req, sid, session, options)
447
- raise '#write_session not implemented.'
448
- end
449
-
450
- # All thread safety and session destroy procedures should occur here.
451
- # Should return a new session id or nil if options[:drop]
452
-
453
- def delete_session(req, sid, options)
454
- raise '#delete_session not implemented'
455
- end
456
- end
457
-
458
- class PersistedSecure < Persisted
459
- class SecureSessionHash < SessionHash
460
- def [](key)
461
- if key == "session_id"
462
- load_for_read!
463
- id.public_id
464
- else
465
- super
466
- end
467
- end
468
- end
469
-
470
- def generate_sid(*)
471
- public_id = super
472
-
473
- SessionId.new(public_id)
474
- end
475
-
476
- def extract_session_id(*)
477
- public_id = super
478
- public_id && SessionId.new(public_id)
479
- end
480
-
481
- private
482
-
483
- def session_class
484
- SecureSessionHash
485
- end
486
-
487
- def cookie_value(data)
488
- data.cookie_value
489
- end
490
- end
491
-
492
- class ID < Persisted
493
- def self.inherited(klass)
494
- k = klass.ancestors.find { |kl| kl.respond_to?(:superclass) && kl.superclass == ID }
495
- unless k.instance_variable_defined?(:"@_rack_warned")
496
- warn "#{klass} is inheriting from #{ID}. Inheriting from #{ID} is deprecated, please inherit from #{Persisted} instead" if $VERBOSE
497
- k.instance_variable_set(:"@_rack_warned", true)
498
- end
499
- super
500
- end
501
-
502
- # All thread safety and session retrieval procedures should occur here.
503
- # Should return [session_id, session].
504
- # If nil is provided as the session id, generation of a new valid id
505
- # should occur within.
506
-
507
- def find_session(req, sid)
508
- get_session req.env, sid
509
- end
510
-
511
- # All thread safety and session storage procedures should occur here.
512
- # Must return the session id if the session was saved successfully, or
513
- # false if the session could not be saved.
514
-
515
- def write_session(req, sid, session, options)
516
- set_session req.env, sid, session, options
517
- end
518
-
519
- # All thread safety and session destroy procedures should occur here.
520
- # Should return a new session id or nil if options[:drop]
521
-
522
- def delete_session(req, sid, options)
523
- destroy_session req.env, sid, options
524
- end
525
- end
526
- end
527
- end
528
- end