rack-test 2.0.2 → 2.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c4264ddd984ab1b662efcc68423ca74bc65927f4751cc8ac68a0f1cfe94375c
4
- data.tar.gz: 7f4af2a9203533fae754b99db4e577cae6be7170fab447a238a2f266a8183e1b
3
+ metadata.gz: 2c648ce9c6c053f9168116fa0ff70ac3ce4d6944326cca519fc2f7f1bb3c4f1d
4
+ data.tar.gz: 8c8d8c7b5c41facc400a1f95533af2e94c7c6eb42ed55ba92b5e38689134e3d9
5
5
  SHA512:
6
- metadata.gz: 7b4986db539c73a5776e15941a7393b14ebb31afe79068756c2b561211907e013b66a1a7a9980864431b029b71ec0c8180e2dbfe7b4942987ca6d59f01877cb5
7
- data.tar.gz: f1c7d0733a7ed4d64e0a9ad51c753485c0472233667181c6fbf2ba09be40936de9a411558be90a49ef9aa5e4804c44dfc3d5c90deda05a22286916e6c7d16e90
6
+ metadata.gz: 5414edd21a3f105513f6068d799fd25fd61672dcd50d0eedbb04b8e05e5224f62f9fcd5014456c99b17ae02c86e38e16077cce27b2c04bcc285214bb49213d45
7
+ data.tar.gz: 5f21ac1f5f8ee2f82d6c3ce65e0cb88ed66e055178c120b935be24a838ee1fc126d1a6070ea4833626e314d631c052748eccdce66db801bfafda01d7bc9c2b42
data/History.md CHANGED
@@ -1,3 +1,43 @@
1
+ ## 2.2.0 / 2024-12-23
2
+
3
+ * Bug fixes:
4
+ * `Rack::Test::Cookie` now parses cookie parameters using a
5
+ case-insensitive approach (Guillaume Malette #349)
6
+
7
+ * Minor enhancements:
8
+ * Arrays of cookies containing a blank cookie are now handled
9
+ correctly when processing responses. (Martin Emde #343)
10
+ * `Rack::Test::UploadedFile` no longer uses a finalizer for named
11
+ paths to close and unlink the created Tempfile. Tempfile itself
12
+ uses a finalizer to close and unlink itself, so there is no
13
+ reason for `Rack::Test::UploadedFile` to do so (Jeremy Evans #338)
14
+
15
+ ## 2.1.0 / 2023-03-14
16
+
17
+ * Breaking changes:
18
+ * Digest authentication support, deprecated in 2.0.0, has been
19
+ removed (Jeremy Evans #307)
20
+ * requiring rack/mock_session, deprecated in 2.0.0, has been removed
21
+ (Jeremy Evans #307)
22
+
23
+ * Minor enhancements:
24
+ * The `original_filename` for `Rack::Test::UploadedFile` can now be
25
+ set even if the content of the file comes from a file path
26
+ (Stuart Chinery #314)
27
+ * Add `Rack::Test::Session#restore_state`, for executing a block
28
+ and restoring current state (last request, last response, and
29
+ cookies) after the block (Jeremy Evans #316)
30
+ * Make `Rack::Test::Methods` support `default_host` method similar to
31
+ `app`, which will set the default host used for requests to the app
32
+ (Jeremy Evans #317 #318)
33
+ * Allow responses to set cookie paths not matching the current
34
+ request URI. Such cookies will only be sent for paths matching
35
+ the cookie path (Chris Waters #322)
36
+ * Ignore leading dot for cookie domains, per RFC 6265 (Stephen Crosby
37
+ #329)
38
+ * Avoid creating empty multipart body if params is empty in
39
+ `Rack::Test::Session#env_for` (Ryunosuke Sato #331)
40
+
1
41
  ## 2.0.2 / 2022-06-28
2
42
 
3
43
  * Bug fixes:
data/README.md CHANGED
@@ -41,7 +41,7 @@ class HomepageTest < Test::Unit::TestCase
41
41
  get '/'
42
42
 
43
43
  assert last_response.ok?
44
- assert_equal last_response.body, 'All responses are OK'
44
+ assert_equal 'All responses are OK', last_response.body
45
45
  end
46
46
 
47
47
  def delete_with_url_params_and_body
@@ -12,7 +12,7 @@ module Rack
12
12
 
13
13
  # The name of the cookie, will be a string
14
14
  attr_reader :name
15
-
15
+
16
16
  # The value of the cookie, will be a string or nil if there is no value.
17
17
  attr_reader :value
18
18
 
@@ -28,10 +28,11 @@ module Rack
28
28
  @raw, options = raw.split(/[;,] */n, 2)
29
29
 
30
30
  @name, @value = parse_query(@raw, ';').to_a.first
31
- @options = parse_query(options, ';')
31
+ @options = Hash[parse_query(options, ';').map { |k, v| [k.downcase, v] }]
32
32
 
33
- if @options['domain']
33
+ if domain = @options['domain']
34
34
  @exact_domain_match = false
35
+ domain[0] = '' if domain[0] == '.'
35
36
  else
36
37
  # If the domain attribute is not present in the cookie,
37
38
  # the domain must match exactly.
@@ -68,7 +69,7 @@ module Rack
68
69
  # Whether the cookie has the httponly flag, indicating it is not available via
69
70
  # a javascript API.
70
71
  def http_only?
71
- @options.key?('HttpOnly') || @options.key?('httponly')
72
+ @options.key?('httponly')
72
73
  end
73
74
 
74
75
  # The explicit or implicit path for the cookie.
@@ -92,15 +93,13 @@ module Rack
92
93
 
93
94
  uri.host = @default_host if uri.host.nil?
94
95
 
95
- real_domain = domain =~ /^\./ ? domain[1..-1] : domain
96
96
  !!((!secure? || (secure? && uri.scheme == 'https')) &&
97
- uri.host =~ Regexp.new("#{'^' if @exact_domain_match}#{Regexp.escape(real_domain)}$", Regexp::IGNORECASE) &&
98
- uri.path =~ Regexp.new("^#{Regexp.escape(path)}"))
97
+ uri.host =~ Regexp.new("#{'^' if @exact_domain_match}#{Regexp.escape(domain)}$", Regexp::IGNORECASE))
99
98
  end
100
99
 
101
100
  # Cookies that do not match the URI will not be sent in requests to the URI.
102
101
  def matches?(uri)
103
- !expired? && valid?(uri)
102
+ !expired? && valid?(uri) && uri.path.start_with?(path)
104
103
  end
105
104
 
106
105
  # Order cookies by name, path, and domain.
@@ -110,11 +109,13 @@ module Rack
110
109
 
111
110
  # A hash of cookie options, including the cookie value, but excluding the cookie name.
112
111
  def to_h
113
- @options.merge(
112
+ hash = @options.merge(
114
113
  'value' => @value,
115
114
  'HttpOnly' => http_only?,
116
115
  'secure' => secure?
117
116
  )
117
+ hash.delete('httponly')
118
+ hash
118
119
  end
119
120
  alias to_hash to_h
120
121
 
@@ -138,6 +139,12 @@ module Rack
138
139
  @cookies = cookies.sort!
139
140
  end
140
141
 
142
+ # Ensure the copy uses a distinct cookies array.
143
+ def initialize_copy(other)
144
+ super
145
+ @cookies = @cookies.dup
146
+ end
147
+
141
148
  # Return the value for first cookie with the given name, or nil
142
149
  # if no such cookie exists.
143
150
  def [](name)
@@ -177,12 +184,10 @@ module Rack
177
184
  def merge(raw_cookies, uri = nil)
178
185
  return unless raw_cookies
179
186
 
180
- if raw_cookies.is_a? String
181
- raw_cookies = raw_cookies.split("\n")
182
- raw_cookies.reject!(&:empty?)
183
- end
187
+ raw_cookies = raw_cookies.split("\n") if raw_cookies.is_a? String
184
188
 
185
189
  raw_cookies.each do |raw_cookie|
190
+ next if raw_cookie.empty?
186
191
  cookie = Cookie.new(raw_cookie, uri, @default_host)
187
192
  self << cookie if cookie.valid?(uri)
188
193
  end
@@ -42,7 +42,11 @@ module Rack
42
42
  # Backwards compatibility for capybara
43
43
  build_rack_mock_session
44
44
  else
45
- Session.new(app)
45
+ if respond_to?(:default_host)
46
+ Session.new(app, default_host)
47
+ else
48
+ Session.new(app)
49
+ end
46
50
  end
47
51
  end
48
52
 
@@ -61,11 +65,6 @@ module Rack
61
65
  @_rack_test_current_session = session
62
66
  end
63
67
 
64
- def digest_authorize(username, password) # :nodoc:
65
- warn 'digest authentication support will be removed in rack-test 2.1', uplevel: 1
66
- current_session._digest_authorize(username, password)
67
- end
68
-
69
68
  def_delegators(:current_session,
70
69
  :request,
71
70
  :get,
@@ -27,16 +27,18 @@ module Rack
27
27
  # content :: is a path to a file, or an {IO} or {StringIO} object representing the content.
28
28
  # content_type :: MIME type of the file
29
29
  # binary :: Whether the file should be set to binmode (content treated as binary).
30
- # original_filename :: The filename to use for the file if +content+ is a StringIO.
30
+ # original_filename :: The filename to use for the file. Required if content is StringIO, optional override if not
31
31
  def initialize(content, content_type = 'text/plain', binary = false, original_filename: nil)
32
+ @content_type = content_type
33
+ @original_filename = original_filename
34
+
32
35
  case content
33
36
  when StringIO
34
- initialize_from_stringio(content, original_filename)
37
+ initialize_from_stringio(content)
35
38
  else
36
39
  initialize_from_file_path(content)
37
40
  end
38
41
 
39
- @content_type = content_type
40
42
  @tempfile.binmode if binary
41
43
  end
42
44
 
@@ -70,38 +72,26 @@ module Rack
70
72
  tempfile.respond_to?(method_name, include_private) || super
71
73
  end
72
74
 
73
- # A proc that can be used as a finalizer to close and unlink the tempfile.
74
- def self.finalize(file)
75
- proc { actually_finalize file }
76
- end
77
-
78
- # Close and unlink the given file, used as a finalizer for the tempfile,
79
- # if the tempfile is backed by a file in the filesystem.
80
- def self.actually_finalize(file)
81
- file.close
82
- file.unlink
83
- end
84
-
85
75
  private
86
76
 
87
77
  # Use the StringIO as the tempfile.
88
- def initialize_from_stringio(stringio, original_filename)
78
+ def initialize_from_stringio(stringio)
79
+ raise(ArgumentError, 'Missing `original_filename` for StringIO object') unless @original_filename
80
+
89
81
  @tempfile = stringio
90
- @original_filename = original_filename || raise(ArgumentError, 'Missing `original_filename` for StringIO object')
91
82
  end
92
83
 
93
- # Create a tempfile and copy the content from the given path into the tempfile.
84
+ # Create a tempfile and copy the content from the given path into the tempfile, optionally renaming if
85
+ # original_filename has been set.
94
86
  def initialize_from_file_path(path)
95
87
  raise "#{path} file does not exist" unless ::File.exist?(path)
96
88
 
97
- @original_filename = ::File.basename(path)
89
+ @original_filename ||= ::File.basename(path)
98
90
  extension = ::File.extname(@original_filename)
99
91
 
100
92
  @tempfile = Tempfile.new([::File.basename(@original_filename, extension), extension])
101
93
  @tempfile.set_encoding(Encoding::BINARY)
102
94
 
103
- ObjectSpace.define_finalizer(self, self.class.finalize(@tempfile))
104
-
105
95
  FileUtils.copy_file(path, @tempfile.path)
106
96
  end
107
97
  end
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  module Test
3
- VERSION = '2.0.2'.freeze
3
+ VERSION = '2.2.0'.freeze
4
4
  end
5
5
  end
data/lib/rack/test.rb CHANGED
@@ -98,8 +98,6 @@ module Rack
98
98
  # If a block is given, #last_response is also yielded to the block.
99
99
  def initialize(app, default_host = DEFAULT_HOST)
100
100
  @env = {}
101
- @digest_username = nil
102
- @digest_password = nil
103
101
  @app = app
104
102
  @after_request = []
105
103
  @default_host = default_host
@@ -204,21 +202,6 @@ module Rack
204
202
 
205
203
  alias authorize basic_authorize
206
204
 
207
- # Set the username and password for HTTP Digest authorization, to be
208
- # included in subsequent requests in the HTTP_AUTHORIZATION header.
209
- # This method is deprecated and will be removed in rack-test 2.1
210
- #
211
- # Example:
212
- # digest_authorize "bryan", "secret"
213
- def digest_authorize(username, password)
214
- warn 'digest authentication support will be removed in rack-test 2.1', uplevel: 1
215
- _digest_authorize(username, password)
216
- end
217
- def _digest_authorize(username, password) # :nodoc:
218
- @digest_username = username
219
- @digest_password = password
220
- end
221
-
222
205
  # Rack::Test will not follow any redirects automatically. This method
223
206
  # will follow the redirect returned (including setting the Referer header
224
207
  # on the new request) in the last response. If the last response was not
@@ -251,6 +234,25 @@ module Rack
251
234
  )
252
235
  end
253
236
 
237
+ # Yield to the block, and restore the last request, last response, and
238
+ # cookie jar to the state they were prior to block execution upon
239
+ # exiting the block.
240
+ def restore_state
241
+ request = @last_request
242
+ response = @last_response
243
+ cookie_jar = @cookie_jar.dup
244
+ after_request = @after_request.dup
245
+
246
+ begin
247
+ yield
248
+ ensure
249
+ @last_request = request
250
+ @last_response = response
251
+ @cookie_jar = cookie_jar
252
+ @after_request = after_request
253
+ end
254
+ end
255
+
254
256
  private
255
257
 
256
258
  # :nocov:
@@ -310,7 +312,7 @@ module Rack
310
312
  multipart = env.has_key?(:multipart) ? env.delete(:multipart) : env['CONTENT_TYPE'].start_with?('multipart/')
311
313
 
312
314
  if params.is_a?(Hash)
313
- if data = build_multipart(params, false, multipart)
315
+ if !params.empty? && data = build_multipart(params, false, multipart)
314
316
  env[:input] = data
315
317
  env['CONTENT_LENGTH'] ||= data.length.to_s
316
318
  env['CONTENT_TYPE'] = "#{multipart_content_type(env)}; boundary=#{MULTIPART_BOUNDARY}"
@@ -363,43 +365,9 @@ module Rack
363
365
  @after_request.each(&:call)
364
366
  @last_response.finish
365
367
 
366
- if retry_with_digest_auth?(env)
367
- auth_env = env.merge('HTTP_AUTHORIZATION' => digest_auth_header,
368
- 'rack-test.digest_auth_retry' => true)
369
- auth_env.delete('rack.request')
370
- process_request(uri, auth_env)
371
- else
372
- yield last_response if block_given?
373
-
374
- last_response
375
- end
376
- end
377
-
378
- def digest_auth_header
379
- require_relative 'test/mock_digest_request'
380
-
381
- challenge = last_response['WWW-Authenticate'].split(' ', 2).last
382
- params = Rack::Auth::Digest::Params.parse(challenge)
383
-
384
- params.merge!('username' => @digest_username,
385
- 'nc' => '00000001',
386
- 'cnonce' => 'nonsensenonce',
387
- 'uri' => last_request.fullpath,
388
- 'method' => last_request.env['REQUEST_METHOD'])
389
-
390
- params['response'] = MockDigestRequest_.new(params).response(@digest_password)
368
+ yield @last_response if block_given?
391
369
 
392
- "Digest #{params}"
393
- end
394
-
395
- def retry_with_digest_auth?(env)
396
- last_response.status == 401 &&
397
- digest_auth_configured? &&
398
- !env['rack-test.digest_auth_retry']
399
- end
400
-
401
- def digest_auth_configured?
402
- @digest_username
370
+ @last_response
403
371
  end
404
372
  end
405
373
 
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-test
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  - Bryan Helmkamp
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-06-28 00:00:00.000000000 Z
12
+ date: 2024-12-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -81,11 +81,9 @@ files:
81
81
  - History.md
82
82
  - MIT-LICENSE.txt
83
83
  - README.md
84
- - lib/rack/mock_session.rb
85
84
  - lib/rack/test.rb
86
85
  - lib/rack/test/cookie_jar.rb
87
86
  - lib/rack/test/methods.rb
88
- - lib/rack/test/mock_digest_request.rb
89
87
  - lib/rack/test/uploaded_file.rb
90
88
  - lib/rack/test/utils.rb
91
89
  - lib/rack/test/version.rb
@@ -97,7 +95,7 @@ metadata:
97
95
  bug_tracker_uri: https://github.com/rack/rack-test/issues
98
96
  mailing_list_uri: https://github.com/rack/rack-test/discussions
99
97
  changelog_uri: https://github.com/rack/rack-test/blob/main/History.md
100
- post_install_message:
98
+ post_install_message:
101
99
  rdoc_options: []
102
100
  require_paths:
103
101
  - lib
@@ -112,8 +110,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
110
  - !ruby/object:Gem::Version
113
111
  version: '0'
114
112
  requirements: []
115
- rubygems_version: 3.3.7
116
- signing_key:
113
+ rubygems_version: 3.5.22
114
+ signing_key:
117
115
  specification_version: 4
118
116
  summary: Simple testing API built on Rack
119
117
  test_files: []
@@ -1,2 +0,0 @@
1
- warn("requiring rack/mock_session is deprecated, require rack/test and use Rack::Test::Session", uplevel: 1)
2
- require_relative 'test'
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # :nocov:
4
- require 'rack/auth/digest' unless defined?(Rack::Auth::Digest)
5
- # :nocov:
6
-
7
- module Rack
8
- module Test
9
- class MockDigestRequest_ # :nodoc:
10
- def initialize(params)
11
- @params = params
12
- end
13
-
14
- def method_missing(sym)
15
- if @params.key? k = sym.to_s
16
- return @params[k]
17
- end
18
-
19
- super
20
- end
21
-
22
- def method
23
- @params['method']
24
- end
25
-
26
- def response(password)
27
- Rack::Auth::Digest::MD5.new(nil).send :digest, self, password
28
- end
29
- end
30
- MockDigestRequest = MockDigestRequest_
31
- # :nocov:
32
- deprecate_constant :MockDigestRequest if respond_to?(:deprecate_constant, true)
33
- # :nocov:
34
- end
35
- end