Skip to content

Fix Ruby 4.0 compatibility: replace CGI with URI in DirectFileStore - #330

Merged
Sinjo merged 2 commits into
prometheus:mainfrom
dannote:fix-ruby-4-cgi-removal
Jul 26, 2026
Merged

Fix Ruby 4.0 compatibility: replace CGI with URI in DirectFileStore#330
Sinjo merged 2 commits into
prometheus:mainfrom
dannote:fix-ruby-4-cgi-removal

Conversation

@dannote

@dannote dannote commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

CGI.parse and CGI.escape methods were removed from the cgi gem in Ruby 4.0. The cgi gem now only provides CGI.escape/CGI.unescape for HTML escaping, and CGI.escapeURIComponent/CGI.unescapeURIComponent for URI components.

This PR replaces:

  • CGI::parse(query_string)URI.decode_www_form(query_string).to_h
  • CGI::escape in query string building → URI.encode_www_form

The uri module is part of Ruby's standard library and doesn't require an additional dependency.

Testing:

  • All existing specs pass
  • Tested manually with Ruby 4.0.1 in production environment

@Sinjo

Sinjo commented Jul 26, 2026

Copy link
Copy Markdown
Member

Sorry this has taken me so long to get to.

I definitely like the idea of using URI since it's still part of the Ruby stdlib. It lets us avoid the extra dependency I introduced in #327.

I wanted to be really sure that we weren't going to run into any unintended side-effects with weird Unicode characters. It struck me that computers are fast and there aren't that many characters, so it's easy to exhaustively test the two serialisation/deserialisation approaches:

#!/usr/bin/env ruby

require 'cgi'
require 'uri'

# Encoding differences
(0x0000..0x10FFFF).map { |i|
  begin
    s = i.chr(Encoding::UTF_8)
  rescue RangeError => _
    next
  end

  [
    i,
    s,
    CGI::escape(s),
    URI::encode_www_form([s]),
  ]
}.compact.filter { |a|
  a[2] != a[3]
}.each { |a|
  puts "Encoding differed for codepoint: #{a[0]} CGI: #{a[2]} URI: #{a[3]}"
}

# Round-trip failures
(0x0000..0x10FFFF).map { |i|
  begin
    s = i.chr(Encoding::UTF_8)
  rescue RangeError => _
    next
  end

  [
    i,
    s,
    CGI::parse(CGI::escape(s)).first.first,
    URI::decode_www_form(URI::encode_www_form([s])).first.first,
  ]
}.compact.filter { |a|
  a[1] != a[2] || a[1] != a[3]
}.each { |a|
  puts "Round-trip differed for codepoint: #{a[0]} CGI: #{a[2]} URI: #{a[3]}"
}

which results in:

$ bundle exec ./my_utf8_test.rb
Encoding differed for codepoint: 42 CGI: %2A URI: *
Encoding differed for codepoint: 126 CGI: ~ URI: %7E

Most importantly, round-tripping works equally well in both approaches. I don't think the two characters they encode differently are problematic for our usage.

I'm going to merge this and get a release out.

dannote and others added 2 commits July 26, 2026 01:24
CGI.parse and CGI.escape were removed in Ruby 4.0.
Use URI.decode_www_form and URI.encode_www_form instead.

Signed-off-by: Danila Poyarkov <dev@dannote.net>
This was introduced because `cgi` was moved out of the default gems in
4.0. It turns out we can simply use `uri`, which still ships with Ruby,
for our purposes instead.

Signed-off-by: Chris Sinjakli <chris@sinjakli.co.uk>
@Sinjo
Sinjo force-pushed the fix-ruby-4-cgi-removal branch from eb80d09 to 461b1ce Compare July 26, 2026 00:24
@Sinjo
Sinjo merged commit bdfef21 into prometheus:main Jul 26, 2026
7 checks passed
@dannote
dannote deleted the fix-ruby-4-cgi-removal branch July 26, 2026 09:32
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