Skip to content

[rack] Parse query string with URI.decode_www_form - #1433

Merged
MDA2AV merged 3 commits into
MDA2AV:mainfrom
p8:rack/parse-with-uri
Sep 3, 2026
Merged

[rack] Parse query string with URI.decode_www_form#1433
MDA2AV merged 3 commits into
MDA2AV:mainfrom
p8:rack/parse-with-uri

Conversation

@p8

@p8 p8 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

URI.decode_www_form performs better than Rack::Utils which also supports parsing nested params:

require 'benchmark/ips'
require 'cgi'
require 'uri'
require 'rack'

Benchmark.ips do |x|
  x.config(warmup: 2, time: 5)

  query_string = "?a=14&b=54"

  x.report("CGI") do
    ::CGI.parse(query_string)
  end

  x.report("URI.decode_www_form") do
    URI.decode_www_form(query_string).to_h
  end

  x.report("Rack::Utils.parse_query") do
    ::Rack::Utils.parse_query(query_string)
  end

  x.compare!
end
ruby 3.4.9 (2026-03-11 revision 76cca827ab) +PRISM [arm64-darwin24]
Warming up --------------------------------------
                    CGI    60.058k i/100ms
    URI.decode_www_form    63.568k i/100ms
Rack::Utils.parse_query    40.922k i/100ms
Calculating -------------------------------------
                    CGI    632.535k (± 2.4%) i/s    (1.58 μs/i) -      3.183M in   5.032252s
    URI.decode_www_form    667.942k (± 2.0%) i/s    (1.50 μs/i) -      3.369M in   5.044006s
Rack::Utils.parse_query    417.398k (± 2.5%) i/s    (2.40 μs/i) -      2.087M in   5.000076s

Comparison:
    URI.decode_www_form:   667942.1 i/s
                    CGI:   632534.7 i/s - 1.06x  slower
Rack::Utils.parse_query:   417398.1 i/s - 1.60x  slower

URI.decode_www_form performs better than Rack::Utils which also supports
parsing nested params:

```ruby
require 'benchmark/ips'
require 'cgi'
require 'uri'
require 'rack'

Benchmark.ips do |x|
  x.config(warmup: 2, time: 5)

  query_string = "?a=14&b=54"

  x.report("CGI") do
    ::CGI.parse(query_string)
  end

  x.report("URI.decode_www_form") do
    URI.decode_www_form(query_string).to_h
  end

  x.report("Rack::Utils.parse_query") do
    ::Rack::Utils.parse_query(query_string)
  end

  x.compare!
end
```

    ruby 3.4.9 (2026-03-11 revision 76cca827ab) +PRISM [arm64-darwin24]
    Warming up --------------------------------------
                        CGI    60.058k i/100ms
        URI.decode_www_form    63.568k i/100ms
    Rack::Utils.parse_query    40.922k i/100ms
    Calculating -------------------------------------
                        CGI    632.535k (± 2.4%) i/s    (1.58 μs/i) -      3.183M in   5.032252s
        URI.decode_www_form    667.942k (± 2.0%) i/s    (1.50 μs/i) -      3.369M in   5.044006s
    Rack::Utils.parse_query    417.398k (± 2.5%) i/s    (2.40 μs/i) -      2.087M in   5.000076s

    Comparison:
        URI.decode_www_form:   667942.1 i/s
                        CGI:   632534.7 i/s - 1.06x  slower
    Rack::Utils.parse_query:   417398.1 i/s - 1.60x  slower
@p8

p8 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

/benchmark-multiple --save

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

👋 Benchmark request received. A collaborator will review and approve the run.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results

Frameworks: 2 | Test: all tests

rack-falcon

Test Conn RPS Rate CPU/req p99 p99.9 CPU Mem Δ RPS Δ Mem
baseline 4096 541,466 6562.8% 1.1GiB +3.4% -15.4%
pipelined 4096 801,850 6666.4% 1.0GiB +0.7% ~0%
limited-conn 4096 503,900 6255.5% 894MiB +4.6% -32.8%
latency-1m 1024 569,602 0.5696 ⚠️ 111.96us 10940416.0us 12251136.0us 6544.5% 831MiB +3.7% -26.2%
latency-10k 1024 9,982 0.9982 122.50us 524.0us 12580.0us 118.8% 765MiB ~0% -32.1%

rack-iodine

Test Conn RPS Rate CPU/req p99 p99.9 CPU Mem Δ RPS Δ Mem
baseline 4096 62,831 4829.1% 4.9GiB +0.3% -2.0%
pipelined 4096 2,329,452 6778.4% 4.6GiB -2.2% ~0%
limited-conn 4096 59,158 4812.8% 4.7GiB -0.1% -9.6%
latency-1m 1024 995,562 0.9956 56.06us 837.0us 51472.0us 6083.9% 4.4GiB ~0% -8.3%
latency-10k 1024 9,951 0.9951 72.26us 140.0us 25256.0us 95.5% 4.3GiB -0.2% -10.4%

URI.decode_www_form performs better than Rack::Utils which also supports
parsing nested params:

```ruby
require 'benchmark/ips'
require 'cgi'
require 'uri'
require 'rack'

Benchmark.ips do |x|
  x.config(warmup: 2, time: 5)

  query_string = "?a=14&b=54"

  x.report("CGI") do
    ::CGI.parse(query_string)
  end

  x.report("URI.decode_www_form") do
    URI.decode_www_form(query_string).to_h
  end

  x.report("Rack::Utils.parse_query") do
    ::Rack::Utils.parse_query(query_string)
  end

  x.compare!
end
```

    ruby 3.4.9 (2026-03-11 revision 76cca827ab) +PRISM [arm64-darwin24]
    Warming up --------------------------------------
                        CGI    60.058k i/100ms
        URI.decode_www_form    63.568k i/100ms
    Rack::Utils.parse_query    40.922k i/100ms
    Calculating -------------------------------------
                        CGI    632.535k (± 2.4%) i/s    (1.58 μs/i) -      3.183M in   5.032252s
        URI.decode_www_form    667.942k (± 2.0%) i/s    (1.50 μs/i) -      3.369M in   5.044006s
    Rack::Utils.parse_query    417.398k (± 2.5%) i/s    (2.40 μs/i) -      2.087M in   5.000076s

    Comparison:
        URI.decode_www_form:   667942.1 i/s
                        CGI:   632534.7 i/s - 1.06x  slower
    Rack::Utils.parse_query:   417398.1 i/s - 1.60x  slower
@MDA2AV
MDA2AV merged commit f680ca7 into MDA2AV:main Sep 3, 2026
5 checks passed
@p8
p8 deleted the rack/parse-with-uri branch September 3, 2026 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants