Your message dated Fri, 18 Jul 2025 09:45:17 +0000
with message-id <e1uchex-0069lg...@respighi.debian.org>
and subject line unblock ruby-rack
has caused the Debian Bug report #1109371,
regarding unblock: ruby-rack/3.1.16-0.1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact ow...@bugs.debian.org
immediately.)


-- 
1109371: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1109371
Debian Bug Tracking System
Contact ow...@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
X-Debbugs-Cc: ruby-r...@packages.debian.org
Control: affects -1 + src:ruby-rack
User: release.debian....@packages.debian.org
Usertags: unblock

Please unblock package ruby-rack.

[ Reason ]
Fixes for RC bugs #1104927 and #1109027.

[ Impact ]
autopkgtests fail, CVE-2025-46727 is exploitable (DoS).

[ Tests ]
autopkgtests pass in unstable.

[ Risks ]
The minor version update also includes other changes including one other
CVE fix. I do not think they pose a significant risk as they also come
with additional unit tests.

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing

[ Other info ]
I have fixed the bugs via a NMU.

unblock ruby-rack/3.1.16-0.1
diff -Nru ruby-rack-3.1.12/CHANGELOG.md ruby-rack-3.1.16/CHANGELOG.md
--- ruby-rack-3.1.12/CHANGELOG.md       2025-03-10 22:21:44.000000000 +0100
+++ ruby-rack-3.1.16/CHANGELOG.md       2025-06-05 00:27:50.000000000 +0200
@@ -2,6 +2,20 @@
 
 All notable changes to this project will be documented in this file. For info 
on how to format all future additions to this file please reference [Keep A 
Changelog](https://keepachangelog.com/en/1.0.0/).
 
+## [3.1.15] - 2025-05-18
+
+- Optional support for `CGI::Cookie` if not available. 
([#2327](https://github.com/rack/rack/pull/2327), 
[#2333](https://github.com/rack/rack/pull/2333), [@earlopain])
+
+## [3.1.14] - 2025-05-06
+
+### Security
+
+- 
[CVE-2025-46727](https://github.com/rack/rack/security/advisories/GHSA-gjh7-p2fx-99vx)
 Unbounded parameter parsing in `Rack::QueryParser` can lead to memory 
exhaustion.
+
+## [3.1.13] - 2025-04-13
+
+- Ensure `Rack::ETag` correctly updates response body. 
([#2324](https://github.com/rack/rack/pull/2324), [@ioquatix])
+
 ## [3.1.12] - 2025-03-11
 
 ### Security
@@ -129,6 +143,24 @@
 
 - In `Rack::Files`, ignore the `Range` header if served file is 0 bytes. 
([#2159](https://github.com/rack/rack/pull/2159), [@zarqman])
 
+## [3.0.18] - 2025-05-22
+
+- Fix incorrect backport of optional `CGI::Cookie` support. 
([#2335](https://github.com/rack/rack/pull/2335), [@jeremyevans])
+
+## [3.0.17] - 2025-05-18
+
+- Optional support for `CGI::Cookie` if not available. 
([#2327](https://github.com/rack/rack/pull/2327), 
[#2333](https://github.com/rack/rack/pull/2333), [@earlopain])
+
+## [3.0.16] - 2025-05-06
+
+### Security
+
+- 
[CVE-2025-46727](https://github.com/rack/rack/security/advisories/GHSA-gjh7-p2fx-99vx)
 Unbounded parameter parsing in `Rack::QueryParser` can lead to memory 
exhaustion.
+
+## [3.0.15] - 2025-04-13
+
+- Ensure `Rack::ETag` correctly updates response body. 
([#2324](https://github.com/rack/rack/pull/2324), [@ioquatix])
+
 ## [3.0.14] - 2025-03-11
 
 ### Security
@@ -141,6 +173,10 @@
 
 - 
[CVE-2025-27111](https://github.com/rack/rack/security/advisories/GHSA-8cgq-6mh2-7j6v)
 Possible Log Injection in `Rack::Sendfile`.
 
+### Fixed
+
+- Remove autoloads for constants no longer shipped with Rack. 
([#2269](https://github.com/rack/rack/pull/2269), 
[@ccutrer](https://github.com/ccutrer))
+
 ## [3.0.12] - 2025-02-12
 
 ### Security
@@ -275,7 +311,7 @@
 - Remove deprecated Rack::Request::SCHEME_WHITELIST. ([@jeremyevans])
 - Remove internal cookie deletion using pattern matching, there are very few 
practical cases where it would be useful and browsers handle it correctly 
without us doing anything special. 
([#1844](https://github.com/rack/rack/pull/1844), [@ioquatix])
 - Remove `rack.version` as it comes too late to be useful. 
([#1938](https://github.com/rack/rack/pull/1938), [@ioquatix])
-- Extract `rackup` command, `Rack::Server`, `Rack::Handler`, `Rack::Lobster` 
and related code into a separate gem. 
([#1937](https://github.com/rack/rack/pull/1937), [@ioquatix])
+- Extract `rackup` command, `Rack::Server`, `Rack::Handler` and related code 
into a separate gem. ([#1937](https://github.com/rack/rack/pull/1937), 
[@ioquatix])
 
 ### Added
 
@@ -323,6 +359,20 @@
 - Fix multipart filename generation for filenames that contain spaces. Encode 
spaces as "%20" instead of "+" which will be decoded properly by the multipart 
parser. ([#1736](https://github.com/rack/rack/pull/1645), 
[@muirdm](https://github.com/muirdm))
 - `Rack::Request#scheme` returns `ws` or `wss` when one of the 
`X-Forwarded-Scheme` / `X-Forwarded-Proto` headers is set to `ws` or `wss`, 
respectively. ([#1730](https://github.com/rack/rack/issues/1730), 
[@erwanst](https://github.com/erwanst))
 
+## [2.2.16] - 2025-05-22
+
+- Fix incorrect backport of optional `CGI::Cookie` support. 
([#2335](https://github.com/rack/rack/pull/2335), [@jeremyevans])
+
+## [2.2.15] - 2025-05-18
+
+- Optional support for `CGI::Cookie` if not available. 
([#2327](https://github.com/rack/rack/pull/2327), 
[#2333](https://github.com/rack/rack/pull/2333), [@earlopain])
+
+## [2.2.14] - 2025-05-06
+
+### Security
+
+- 
[CVE-2025-46727](https://github.com/rack/rack/security/advisories/GHSA-gjh7-p2fx-99vx)
 Unbounded parameter parsing in `Rack::QueryParser` can lead to memory 
exhaustion.
+
 ## [2.2.13] - 2025-03-11
 
 ### Security
@@ -1104,3 +1154,4 @@
 [@wjordan]: https://github.com/wjordan "Will Jordan"
 [@BlakeWilliams]: https://github.com/BlakeWilliams "Blake Williams"
 [@davidstosik]: https://github.com/davidstosik "David Stosik"
+[@earlopain]: https://github.com/earlopain "Earlopain"
diff -Nru ruby-rack-3.1.12/debian/changelog ruby-rack-3.1.16/debian/changelog
--- ruby-rack-3.1.12/debian/changelog   2025-03-19 16:53:01.000000000 +0100
+++ ruby-rack-3.1.16/debian/changelog   2025-07-15 18:00:20.000000000 +0200
@@ -1,3 +1,12 @@
+ruby-rack (3.1.16-0.1) unstable; urgency=medium
+
+  * Non-maintainer upload
+  * New upstream version 3.1.16 (Closes: #1104927, #1107363),
+    fixes CVE-2025-46727, CVE-2025-49007
+  * Remove ruby-bacon from autopkgtests (Closes: #1109027)
+
+ -- Bastian Germann <b...@debian.org>  Tue, 15 Jul 2025 18:00:20 +0200
+
 ruby-rack (3.1.12-1) unstable; urgency=medium
 
   * Team upload
diff -Nru ruby-rack-3.1.12/debian/tests/control 
ruby-rack-3.1.16/debian/tests/control
--- ruby-rack-3.1.12/debian/tests/control       2025-03-16 18:51:46.000000000 
+0100
+++ ruby-rack-3.1.16/debian/tests/control       2025-07-15 18:00:20.000000000 
+0200
@@ -2,5 +2,5 @@
 Depends: @, curl, ruby-rackup, ruby-webrick
 
 Test-Command: gem2deb-test-runner
-Depends: @, gem2deb-test-runner, rake, ruby-bacon, 
ruby-minitest-global-expectations, ruby-webrick
+Depends: @, gem2deb-test-runner, rake, ruby-minitest-global-expectations, 
ruby-webrick
 Restrictions: allow-stderr
diff -Nru ruby-rack-3.1.12/.github/workflows/test.yaml 
ruby-rack-3.1.16/.github/workflows/test.yaml
--- ruby-rack-3.1.12/.github/workflows/test.yaml        2025-03-10 
22:21:44.000000000 +0100
+++ ruby-rack-3.1.16/.github/workflows/test.yaml        2025-06-05 
00:27:50.000000000 +0200
@@ -21,6 +21,7 @@
           - '3.1'
           - '3.2'
           - '3.3'
+          - '3.4'
           - jruby-head
           - truffleruby-head
         include:
diff -Nru ruby-rack-3.1.12/lib/rack/etag.rb ruby-rack-3.1.16/lib/rack/etag.rb
--- ruby-rack-3.1.12/lib/rack/etag.rb   2025-03-10 22:21:44.000000000 +0100
+++ ruby-rack-3.1.16/lib/rack/etag.rb   2025-06-05 00:27:50.000000000 +0200
@@ -32,6 +32,9 @@
         body = body.to_ary
         digest = digest_body(body)
         headers[ETAG_STRING] = %(W/"#{digest}") if digest
+
+        # Body was modified, so we need to re-assign it:
+        response[2] = body
       end
 
       unless headers[CACHE_CONTROL]
diff -Nru ruby-rack-3.1.12/lib/rack/mock_response.rb 
ruby-rack-3.1.16/lib/rack/mock_response.rb
--- ruby-rack-3.1.12/lib/rack/mock_response.rb  2025-03-10 22:21:44.000000000 
+0100
+++ ruby-rack-3.1.16/lib/rack/mock_response.rb  2025-06-05 00:27:50.000000000 
+0200
@@ -1,6 +1,5 @@
 # frozen_string_literal: true
 
-require 'cgi/cookie'
 require 'time'
 
 require_relative 'response'
@@ -11,6 +10,36 @@
   # MockRequest.
 
   class MockResponse < Rack::Response
+    begin
+      # Recent versions of the CGI gem may not provide `CGI::Cookie`.
+      require 'cgi/cookie'
+      Cookie = CGI::Cookie
+    rescue LoadError
+      class Cookie
+        attr_reader :name, :value, :path, :domain, :expires, :secure
+
+        def initialize(args)
+          @name = args["name"]
+          @value = args["value"]
+          @path = args["path"]
+          @domain = args["domain"]
+          @expires = args["expires"]
+          @secure = args["secure"]
+        end
+
+        def method_missing(method_name, *args, &block)
+          @value.send(method_name, *args, &block)
+        end
+        # :nocov:
+        ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
+        # :nocov:
+
+        def respond_to_missing?(method_name, include_all = false)
+          @value.respond_to?(method_name, include_all) || super
+        end
+      end
+    end
+
     class << self
       alias [] new
     end
@@ -83,7 +112,7 @@
         Array(set_cookie_header).each do |cookie|
           cookie_name, cookie_filling = cookie.split('=', 2)
           cookie_attributes = identify_cookie_attributes cookie_filling
-          parsed_cookie = CGI::Cookie.new(
+          parsed_cookie = Cookie.new(
             'name' => cookie_name.strip,
             'value' => cookie_attributes.fetch('value'),
             'path' => cookie_attributes.fetch('path', nil),
@@ -100,7 +129,7 @@
     def identify_cookie_attributes(cookie_filling)
       cookie_bits = cookie_filling.split(';')
       cookie_attributes = Hash.new
-      cookie_attributes.store('value', cookie_bits[0].strip)
+      cookie_attributes.store('value', Array(cookie_bits[0].strip))
       cookie_bits.drop(1).each do |bit|
         if bit.include? '='
           cookie_attribute, attribute_value = bit.split('=', 2)
diff -Nru ruby-rack-3.1.12/lib/rack/multipart/parser.rb 
ruby-rack-3.1.16/lib/rack/multipart/parser.rb
--- ruby-rack-3.1.12/lib/rack/multipart/parser.rb       2025-03-10 
22:21:44.000000000 +0100
+++ ruby-rack-3.1.16/lib/rack/multipart/parser.rb       2025-06-05 
00:27:50.000000000 +0200
@@ -31,10 +31,12 @@
     Error = BoundaryTooLongError
 
     EOL = "\r\n"
+    FWS = /[ \t]+(?:\r\n[ \t]+)?/ # whitespace with optional folding
+    HEADER_VALUE = "(?:[^\r\n]|\r\n[ \t])*" # anything but a non-folding CRLF
     MULTIPART = %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|ni
-    MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{EOL}/ni
-    MULTIPART_CONTENT_DISPOSITION = 
/Content-Disposition:(.*)(?=#{EOL}(\S|\z))/ni
-    MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{EOL}]*)/ni
+    MULTIPART_CONTENT_TYPE = /^Content-Type:#{FWS}?(#{HEADER_VALUE})/ni
+    MULTIPART_CONTENT_DISPOSITION = 
/^Content-Disposition:#{FWS}?(#{HEADER_VALUE})/ni
+    MULTIPART_CONTENT_ID = /^Content-ID:#{FWS}?(#{HEADER_VALUE})/ni
 
     class Parser
       BUFSIZE = 1_048_576
diff -Nru ruby-rack-3.1.12/lib/rack/query_parser.rb 
ruby-rack-3.1.16/lib/rack/query_parser.rb
--- ruby-rack-3.1.12/lib/rack/query_parser.rb   2025-03-10 22:21:44.000000000 
+0100
+++ ruby-rack-3.1.16/lib/rack/query_parser.rb   2025-06-05 00:27:50.000000000 
+0200
@@ -21,21 +21,47 @@
       include BadRequest
     end
 
-    # ParamsTooDeepError is the error that is raised when params are 
recursively
-    # nested over the specified limit.
-    class ParamsTooDeepError < RangeError
+    # QueryLimitError is for errors raised when the query provided exceeds one
+    # of the query parser limits.
+    class QueryLimitError < RangeError
       include BadRequest
     end
 
-    def self.make_default(param_depth_limit)
-      new Params, param_depth_limit
+    # ParamsTooDeepError is the old name for the error that is raised when 
params
+    # are recursively nested over the specified limit. Make it the same as
+    # as QueryLimitError, so that code that rescues ParamsTooDeepError error
+    # to handle bad query strings also now handles other limits.
+    ParamsTooDeepError = QueryLimitError
+
+    def self.make_default(param_depth_limit, **options)
+      new(Params, param_depth_limit, **options)
     end
 
     attr_reader :param_depth_limit
 
-    def initialize(params_class, param_depth_limit)
+    env_int = lambda do |key, val|
+      if str_val = ENV[key]
+        begin
+          val = Integer(str_val, 10)
+        rescue ArgumentError
+          raise ArgumentError, "non-integer value provided for environment 
variable #{key}"
+        end
+      end
+
+      val
+    end
+
+    BYTESIZE_LIMIT = env_int.call("RACK_QUERY_PARSER_BYTESIZE_LIMIT", 4194304)
+    private_constant :BYTESIZE_LIMIT
+
+    PARAMS_LIMIT = env_int.call("RACK_QUERY_PARSER_PARAMS_LIMIT", 4096)
+    private_constant :PARAMS_LIMIT
+
+    def initialize(params_class, param_depth_limit, bytesize_limit: 
BYTESIZE_LIMIT, params_limit: PARAMS_LIMIT)
       @params_class = params_class
       @param_depth_limit = param_depth_limit
+      @bytesize_limit = bytesize_limit
+      @params_limit = params_limit
     end
 
     # Stolen from Mongrel, with some small modifications:
@@ -47,7 +73,7 @@
 
       params = make_params
 
-      (qs || '').split(separator ? (COMMON_SEP[separator] || /[#{separator}] 
*/n) : DEFAULT_SEP).each do |p|
+      check_query_string(qs, separator).split(separator ? 
(COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p|
         next if p.empty?
         k, v = p.split('=', 2).map!(&unescaper)
 
@@ -74,7 +100,7 @@
       params = make_params
 
       unless qs.nil? || qs.empty?
-        (qs || '').split(separator ? (COMMON_SEP[separator] || /[#{separator}] 
*/n) : DEFAULT_SEP).each do |p|
+        check_query_string(qs, separator).split(separator ? 
(COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p|
           k, v = p.split('=', 2).map! { |s| unescape(s) }
 
           _normalize_params(params, k, v, 0)
@@ -189,6 +215,22 @@
       true
     end
 
+    def check_query_string(qs, sep)
+      if qs
+        if qs.bytesize > @bytesize_limit
+          raise QueryLimitError, "total query size (#{qs.bytesize}) exceeds 
limit (#{@bytesize_limit})"
+        end
+
+        if (param_count = qs.count(sep.is_a?(String) ? sep : '&')) >= 
@params_limit
+          raise QueryLimitError, "total number of query parameters 
(#{param_count+1}) exceeds limit (#{@params_limit})"
+        end
+
+        qs
+      else
+        ''
+      end
+    end
+
     def unescape(string, encoding = Encoding::UTF_8)
       URI.decode_www_form_component(string, encoding)
     end
diff -Nru ruby-rack-3.1.12/lib/rack/version.rb 
ruby-rack-3.1.16/lib/rack/version.rb
--- ruby-rack-3.1.12/lib/rack/version.rb        2025-03-10 22:21:44.000000000 
+0100
+++ ruby-rack-3.1.16/lib/rack/version.rb        2025-06-05 00:27:50.000000000 
+0200
@@ -12,7 +12,7 @@
 # so it should be enough just to <tt>require 'rack'</tt> in your code.
 
 module Rack
-  RELEASE = "3.1.12"
+  RELEASE = "3.1.16"
 
   # Return the Rack release as a dotted string.
   def self.release
diff -Nru ruby-rack-3.1.12/README.md ruby-rack-3.1.16/README.md
--- ruby-rack-3.1.12/README.md  2025-03-10 22:21:44.000000000 +0100
+++ ruby-rack-3.1.16/README.md  2025-06-05 00:27:50.000000000 +0200
@@ -183,6 +183,33 @@
 Rack exposes several configuration parameters to control various features of 
the
 implementation.
 
+### `RACK_QUERY_PARSER_BYTESIZE_LIMIT`
+
+This environment variable sets the default for the maximum query string 
bytesize
+that `Rack::QueryParser` will attempt to parse.  Attempts to use a query string
+that exceeds this number of bytes will result in a
+`Rack::QueryParser::QueryLimitError` exception. If this enviroment variable is
+provided, it must be an integer, or `Rack::QueryParser` will raise an 
exception.
+
+The default limit can be overridden on a per-`Rack::QueryParser` basis using
+the `bytesize_limit` keyword argument when creating the `Rack::QueryParser`.
+
+### `RACK_QUERY_PARSER_PARAMS_LIMIT`
+
+This environment variable sets the default for the maximum number of query
+parameters that `Rack::QueryParser` will attempt to parse.  Attempts to use a
+query string with more than this many query parameters will result in a
+`Rack::QueryParser::QueryLimitError` exception. If this enviroment variable is
+provided, it must be an integer, or `Rack::QueryParser` will raise an 
exception.
+
+The default limit can be overridden on a per-`Rack::QueryParser` basis using
+the `params_limit` keyword argument when creating the `Rack::QueryParser`.
+
+This is implemented by counting the number of parameter separators in the
+query string, before attempting parsing, so if the same parameter key is
+used multiple times in the query, each counts as a separate parameter for
+this check.
+
 ### `param_depth_limit`
 
 ```ruby
diff -Nru ruby-rack-3.1.12/test/spec_etag.rb ruby-rack-3.1.16/test/spec_etag.rb
--- ruby-rack-3.1.12/test/spec_etag.rb  2025-03-10 22:21:44.000000000 +0100
+++ ruby-rack-3.1.16/test/spec_etag.rb  2025-06-05 00:27:50.000000000 +0200
@@ -28,6 +28,16 @@
     response[1]['etag'].must_equal "W/\"dffd6021bb2bd5b0af676290809ec3a5\""
   end
 
+  it "returns a valid response body when using a linted app" do
+    app = lambda { |env| [200, { 'content-type' => 'text/plain' }, ["Hello, 
World!"]] }
+    response = etag(Rack::Lint.new(app)).call(request)
+    response[1]['etag'].must_equal "W/\"dffd6021bb2bd5b0af676290809ec3a5\""
+
+    response[2].each do |chunk|
+      chunk.must_equal "Hello, World!"
+    end
+  end
+
   it "set etag if none is set if status is 201" do
     app = lambda { |env| [201, { 'content-type' => 'text/plain' }, ["Hello, 
World!"]] }
     response = etag(app).call(request)
diff -Nru ruby-rack-3.1.12/test/spec_headers.rb 
ruby-rack-3.1.16/test/spec_headers.rb
--- ruby-rack-3.1.12/test/spec_headers.rb       2025-03-10 22:21:44.000000000 
+0100
+++ ruby-rack-3.1.16/test/spec_headers.rb       2025-06-05 00:27:50.000000000 
+0200
@@ -220,8 +220,8 @@
 
   def test_inspect
     %i'inspect to_s'.each do |meth|
-      assert_equal '{}', @h.send(meth)
-      assert_equal '{"ab"=>"1", "cd"=>"2", "3"=>"4"}', @fh.send(meth)
+      assert_equal({}.inspect, @h.send(meth))
+      assert_equal({"ab"=>"1", "cd"=>"2", "3"=>"4"}.inspect, @fh.send(meth))
     end
   end
 
diff -Nru ruby-rack-3.1.12/test/spec_mock_response.rb 
ruby-rack-3.1.16/test/spec_mock_response.rb
--- ruby-rack-3.1.12/test/spec_mock_response.rb 2025-03-10 22:21:44.000000000 
+0100
+++ ruby-rack-3.1.16/test/spec_mock_response.rb 2025-06-05 00:27:50.000000000 
+0200
@@ -84,6 +84,7 @@
   it "provides access to session cookies" do
     res = Rack::MockRequest.new(app).get("")
     session_cookie = res.cookie("session_test")
+    session_cookie[0].must_equal "session_test"
     session_cookie.value[0].must_equal "session_test"
     session_cookie.domain.must_equal "test.com"
     session_cookie.path.must_equal "/"
diff -Nru ruby-rack-3.1.12/test/spec_multipart.rb 
ruby-rack-3.1.16/test/spec_multipart.rb
--- ruby-rack-3.1.12/test/spec_multipart.rb     2025-03-10 22:21:44.000000000 
+0100
+++ ruby-rack-3.1.16/test/spec_multipart.rb     2025-06-05 00:27:50.000000000 
+0200
@@ -334,7 +334,7 @@
 
   it "ignores content-disposition values over to 1536 bytes" do
     x = content_disposition_parse.call("a=#{'a'*1510}; filename=\"bar\"; 
name=\"file\"")
-    x.must_equal "text/plain"=>[""]
+    x.must_equal "application/pdf"=>[""]
   end
 
   it 'raises an EOF error on content-length mismatch' do
@@ -955,7 +955,7 @@
     data = <<-EOF
 --AaB03x\r
 content-type: text/plain\r
-content-disposition: attachment; name="quoted\\\\chars\\"in\rname"\r
+content-disposition: attachment; name="quoted\\\\chars\\"in\tname"\r
 \r
 true\r
 --AaB03x--\r
@@ -968,7 +968,7 @@
     }
     env = Rack::MockRequest.env_for("/", options)
     params = Rack::Multipart.parse_multipart(env)
-    params["quoted\\chars\"in\rname"].must_equal 'true'
+    params["quoted\\chars\"in\tname"].must_equal 'true'
   end
 
   it "supports mixed case metadata" do
diff -Nru ruby-rack-3.1.12/test/spec_query_parser.rb 
ruby-rack-3.1.16/test/spec_query_parser.rb
--- ruby-rack-3.1.12/test/spec_query_parser.rb  2025-03-10 22:21:44.000000000 
+0100
+++ ruby-rack-3.1.16/test/spec_query_parser.rb  2025-06-05 00:27:50.000000000 
+0200
@@ -7,11 +7,30 @@
 end
 
 describe Rack::QueryParser do
-  query_parser ||= Rack::QueryParser.make_default(8)
-
   it "can normalize values with missing values" do
+    query_parser = Rack::QueryParser.make_default(8)
     query_parser.parse_nested_query("a=a").must_equal({"a" => "a"})
     query_parser.parse_nested_query("a=").must_equal({"a" => ""})
     query_parser.parse_nested_query("a").must_equal({"a" => nil})
   end
+
+  it "accepts bytesize_limit to specify maximum size of query string to parse" 
do
+    query_parser = Rack::QueryParser.make_default(32, bytesize_limit: 3)
+    query_parser.parse_query("a=a").must_equal({"a" => "a"})
+    query_parser.parse_nested_query("a=a").must_equal({"a" => "a"})
+    query_parser.parse_nested_query("a=a", '&').must_equal({"a" => "a"})
+    proc { query_parser.parse_query("a=aa") }.must_raise 
Rack::QueryParser::QueryLimitError
+    proc { query_parser.parse_nested_query("a=aa") }.must_raise 
Rack::QueryParser::QueryLimitError
+    proc { query_parser.parse_nested_query("a=aa", '&') }.must_raise 
Rack::QueryParser::QueryLimitError
+  end
+
+  it "accepts params_limit to specify maximum number of query parameters to 
parse" do
+    query_parser = Rack::QueryParser.make_default(32, params_limit: 2)
+    query_parser.parse_query("a=a&b=b").must_equal({"a" => "a", "b" => "b"})
+    query_parser.parse_nested_query("a=a&b=b").must_equal({"a" => "a", "b" => 
"b"})
+    query_parser.parse_nested_query("a=a&b=b", '&').must_equal({"a" => "a", 
"b" => "b"})
+    proc { query_parser.parse_query("a=a&b=b&c=c") }.must_raise 
Rack::QueryParser::QueryLimitError
+    proc { query_parser.parse_nested_query("a=a&b=b&c=c", '&') }.must_raise 
Rack::QueryParser::QueryLimitError
+    proc { query_parser.parse_query("b[]=a&b[]=b&b[]=c") }.must_raise 
Rack::QueryParser::QueryLimitError
+  end
 end
diff -Nru ruby-rack-3.1.12/test/spec_request.rb 
ruby-rack-3.1.16/test/spec_request.rb
--- ruby-rack-3.1.12/test/spec_request.rb       2025-03-10 22:21:44.000000000 
+0100
+++ ruby-rack-3.1.16/test/spec_request.rb       2025-06-05 00:27:50.000000000 
+0200
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 require_relative 'helper'
-require 'cgi'
+require 'cgi/escape'
 require 'forwardable'
 require 'securerandom'
 
@@ -1910,6 +1910,9 @@
 
   class NonDelegate < Rack::Request
     def delegate?; false; end
+    def query_parser
+      Rack::QueryParser.make_default(Rack::Utils.param_depth_limit, 
bytesize_limit: 2**30)
+    end
   end
 
   def make_request(env)
@@ -1931,6 +1934,10 @@
       end
 
       def delegate?; true; end
+
+      def query_parser
+        Rack::QueryParser.make_default(Rack::Utils.param_depth_limit, 
bytesize_limit: 2**30)
+      end
     end
 
     def make_request(env)

--- End Message ---
--- Begin Message ---
Unblocked ruby-rack.

--- End Message ---

Reply via email to