rack 2.2.18 → 3.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +561 -75
  3. data/CONTRIBUTING.md +63 -55
  4. data/MIT-LICENSE +1 -1
  5. data/README.md +384 -0
  6. data/SPEC.rdoc +243 -277
  7. data/lib/rack/auth/abstract/handler.rb +3 -1
  8. data/lib/rack/auth/abstract/request.rb +5 -1
  9. data/lib/rack/auth/basic.rb +1 -3
  10. data/lib/rack/bad_request.rb +8 -0
  11. data/lib/rack/body_proxy.rb +21 -3
  12. data/lib/rack/builder.rb +108 -69
  13. data/lib/rack/cascade.rb +2 -3
  14. data/lib/rack/common_logger.rb +22 -17
  15. data/lib/rack/conditional_get.rb +20 -16
  16. data/lib/rack/constants.rb +68 -0
  17. data/lib/rack/content_length.rb +12 -16
  18. data/lib/rack/content_type.rb +8 -5
  19. data/lib/rack/deflater.rb +40 -26
  20. data/lib/rack/directory.rb +9 -3
  21. data/lib/rack/etag.rb +17 -23
  22. data/lib/rack/events.rb +25 -6
  23. data/lib/rack/files.rb +15 -17
  24. data/lib/rack/head.rb +8 -8
  25. data/lib/rack/headers.rb +238 -0
  26. data/lib/rack/lint.rb +817 -648
  27. data/lib/rack/lock.rb +2 -5
  28. data/lib/rack/media_type.rb +6 -7
  29. data/lib/rack/method_override.rb +5 -1
  30. data/lib/rack/mime.rb +14 -5
  31. data/lib/rack/mock.rb +1 -300
  32. data/lib/rack/mock_request.rb +161 -0
  33. data/lib/rack/mock_response.rb +147 -0
  34. data/lib/rack/multipart/generator.rb +7 -5
  35. data/lib/rack/multipart/parser.rb +291 -95
  36. data/lib/rack/multipart/uploaded_file.rb +45 -4
  37. data/lib/rack/multipart.rb +53 -40
  38. data/lib/rack/null_logger.rb +9 -0
  39. data/lib/rack/query_parser.rb +118 -121
  40. data/lib/rack/recursive.rb +2 -0
  41. data/lib/rack/reloader.rb +0 -2
  42. data/lib/rack/request.rb +272 -141
  43. data/lib/rack/response.rb +151 -66
  44. data/lib/rack/rewindable_input.rb +27 -5
  45. data/lib/rack/runtime.rb +7 -6
  46. data/lib/rack/sendfile.rb +68 -33
  47. data/lib/rack/show_exceptions.rb +25 -6
  48. data/lib/rack/show_status.rb +17 -9
  49. data/lib/rack/static.rb +8 -8
  50. data/lib/rack/tempfile_reaper.rb +15 -4
  51. data/lib/rack/urlmap.rb +3 -1
  52. data/lib/rack/utils.rb +228 -238
  53. data/lib/rack/version.rb +3 -15
  54. data/lib/rack.rb +13 -90
  55. metadata +14 -40
  56. data/README.rdoc +0 -347
  57. data/Rakefile +0 -130
  58. data/bin/rackup +0 -5
  59. data/contrib/rack.png +0 -0
  60. data/contrib/rack.svg +0 -150
  61. data/contrib/rack_logo.svg +0 -164
  62. data/contrib/rdoc.css +0 -412
  63. data/example/lobster.ru +0 -6
  64. data/example/protectedlobster.rb +0 -16
  65. data/example/protectedlobster.ru +0 -10
  66. data/lib/rack/auth/digest/md5.rb +0 -131
  67. data/lib/rack/auth/digest/nonce.rb +0 -53
  68. data/lib/rack/auth/digest/params.rb +0 -54
  69. data/lib/rack/auth/digest/request.rb +0 -43
  70. data/lib/rack/chunked.rb +0 -117
  71. data/lib/rack/core_ext/regexp.rb +0 -14
  72. data/lib/rack/file.rb +0 -7
  73. data/lib/rack/handler/cgi.rb +0 -59
  74. data/lib/rack/handler/fastcgi.rb +0 -100
  75. data/lib/rack/handler/lsws.rb +0 -61
  76. data/lib/rack/handler/scgi.rb +0 -71
  77. data/lib/rack/handler/thin.rb +0 -34
  78. data/lib/rack/handler/webrick.rb +0 -129
  79. data/lib/rack/handler.rb +0 -104
  80. data/lib/rack/lobster.rb +0 -70
  81. data/lib/rack/logger.rb +0 -20
  82. data/lib/rack/server.rb +0 -466
  83. data/lib/rack/session/abstract/id.rb +0 -523
  84. data/lib/rack/session/cookie.rb +0 -203
  85. data/lib/rack/session/memcache.rb +0 -10
  86. data/lib/rack/session/pool.rb +0 -90
  87. data/rack.gemspec +0 -46
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+
5
+ require_relative 'response'
6
+
7
+ module Rack
8
+ # Rack::MockResponse provides useful helpers for testing your apps.
9
+ # Usually, you don't create the MockResponse on your own, but use
10
+ # MockRequest.
11
+
12
+ class MockResponse < Rack::Response
13
+ class Cookie
14
+ attr_reader :name, :value, :path, :domain, :expires, :secure
15
+
16
+ def initialize(args)
17
+ @name = args["name"]
18
+ @value = args["value"]
19
+ @path = args["path"]
20
+ @domain = args["domain"]
21
+ @expires = args["expires"]
22
+ @secure = args["secure"]
23
+ end
24
+
25
+ def method_missing(method_name, *args, &block)
26
+ @value.send(method_name, *args, &block)
27
+ end
28
+ # :nocov:
29
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
30
+ # :nocov:
31
+
32
+ def respond_to_missing?(method_name, include_all = false)
33
+ @value.respond_to?(method_name, include_all) || super
34
+ end
35
+ end
36
+
37
+ class << self
38
+ alias [] new
39
+ end
40
+
41
+ # Headers
42
+ attr_reader :original_headers, :cookies
43
+
44
+ # Errors
45
+ attr_accessor :errors
46
+
47
+ def initialize(status, headers, body, errors = nil)
48
+ @original_headers = headers
49
+
50
+ if errors
51
+ @errors = errors.string if errors.respond_to?(:string)
52
+ else
53
+ @errors = ""
54
+ end
55
+
56
+ super(body, status, headers)
57
+
58
+ @cookies = parse_cookies_from_header
59
+ buffered_body!
60
+ end
61
+
62
+ def =~(other)
63
+ body =~ other
64
+ end
65
+
66
+ def match(other)
67
+ body.match other
68
+ end
69
+
70
+ def body
71
+ return @buffered_body if defined?(@buffered_body)
72
+
73
+ # FIXME: apparently users of MockResponse expect the return value of
74
+ # MockResponse#body to be a string. However, the real response object
75
+ # returns the body as a list.
76
+ #
77
+ # See spec_showstatus.rb:
78
+ #
79
+ # should "not replace existing messages" do
80
+ # ...
81
+ # res.body.should == "foo!"
82
+ # end
83
+ buffer = @buffered_body = String.new
84
+
85
+ @body.each do |chunk|
86
+ buffer << chunk
87
+ end
88
+
89
+ return buffer
90
+ end
91
+
92
+ def empty?
93
+ [201, 204, 304].include? status
94
+ end
95
+
96
+ def cookie(name)
97
+ cookies.fetch(name, nil)
98
+ end
99
+
100
+ private
101
+
102
+ def parse_cookies_from_header
103
+ cookies = Hash.new
104
+ set_cookie_header = headers['set-cookie']
105
+ if set_cookie_header && !set_cookie_header.empty?
106
+ Array(set_cookie_header).each do |cookie|
107
+ cookie_name, cookie_filling = cookie.split('=', 2)
108
+ cookie_attributes = identify_cookie_attributes cookie_filling
109
+ parsed_cookie = Cookie.new(
110
+ 'name' => cookie_name.strip,
111
+ 'value' => cookie_attributes.fetch('value'),
112
+ 'path' => cookie_attributes.fetch('path', nil),
113
+ 'domain' => cookie_attributes.fetch('domain', nil),
114
+ 'expires' => cookie_attributes.fetch('expires', nil),
115
+ 'secure' => cookie_attributes.fetch('secure', false)
116
+ )
117
+ cookies.store(cookie_name, parsed_cookie)
118
+ end
119
+ end
120
+ cookies
121
+ end
122
+
123
+ def identify_cookie_attributes(cookie_filling)
124
+ cookie_bits = cookie_filling.split(';')
125
+ cookie_attributes = Hash.new
126
+ cookie_attributes.store('value', Array(cookie_bits[0].strip))
127
+ cookie_bits.drop(1).each do |bit|
128
+ if bit.include? '='
129
+ cookie_attribute, attribute_value = bit.split('=', 2)
130
+ cookie_attributes.store(cookie_attribute.strip.downcase, attribute_value.strip)
131
+ end
132
+ if bit.include? 'secure'
133
+ cookie_attributes.store('secure', true)
134
+ end
135
+ end
136
+
137
+ if cookie_attributes.key? 'max-age'
138
+ cookie_attributes.store('expires', Time.now + cookie_attributes['max-age'].to_i)
139
+ elsif cookie_attributes.key? 'expires'
140
+ cookie_attributes.store('expires', Time.httpdate(cookie_attributes['expires']))
141
+ end
142
+
143
+ cookie_attributes
144
+ end
145
+
146
+ end
147
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'uploaded_file'
4
+
3
5
  module Rack
4
6
  module Multipart
5
7
  class Generator
@@ -74,12 +76,12 @@ module Rack
74
76
 
75
77
  def content_for_tempfile(io, file, name)
76
78
  length = ::File.stat(file.path).size if file.path
77
- filename = "; filename=\"#{Utils.escape(file.original_filename)}\"" if file.original_filename
79
+ filename = "; filename=\"#{Utils.escape_path(file.original_filename)}\""
78
80
  <<-EOF
79
81
  --#{MULTIPART_BOUNDARY}\r
80
- Content-Disposition: form-data; name="#{name}"#{filename}\r
81
- Content-Type: #{file.content_type}\r
82
- #{"Content-Length: #{length}\r\n" if length}\r
82
+ content-disposition: form-data; name="#{name}"#{filename}\r
83
+ content-type: #{file.content_type}\r
84
+ #{"content-length: #{length}\r\n" if length}\r
83
85
  #{io.read}\r
84
86
  EOF
85
87
  end
@@ -87,7 +89,7 @@ EOF
87
89
  def content_for_other(file, name)
88
90
  <<-EOF
89
91
  --#{MULTIPART_BOUNDARY}\r
90
- Content-Disposition: form-data; name="#{name}"\r
92
+ content-disposition: form-data; name="#{name}"\r
91
93
  \r
92
94
  #{file}\r
93
95
  EOF