diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c9ba664..f1ce3b3 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.11.1" + ".": "2.11.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8181a45..6aa9529 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.11.2 (2026-04-01) + +Full Changelog: [v2.11.1...v2.11.2](https://github.com/moderation-api/sdk-ruby/compare/v2.11.1...v2.11.2) + +### Bug Fixes + +* align path encoding with RFC 3986 section 3.3 ([8562b22](https://github.com/moderation-api/sdk-ruby/commit/8562b22361b7f7c6db74a58f8d78f25e435bed3d)) + ## 2.11.1 (2026-04-01) Full Changelog: [v2.11.0...v2.11.1](https://github.com/moderation-api/sdk-ruby/compare/v2.11.0...v2.11.1) diff --git a/Gemfile.lock b/Gemfile.lock index 4c7d6f4..40db1b9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -11,7 +11,7 @@ GIT PATH remote: . specs: - moderation_api (2.11.1) + moderation_api (2.11.2) cgi connection_pool diff --git a/README.md b/README.md index aebc83b..b9e6585 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ To use this gem, install via Bundler by adding the following to your application ```ruby -gem "moderation_api", "~> 2.11.1" +gem "moderation_api", "~> 2.11.2" ``` diff --git a/lib/moderation_api/internal/util.rb b/lib/moderation_api/internal/util.rb index e2f91a9..382526b 100644 --- a/lib/moderation_api/internal/util.rb +++ b/lib/moderation_api/internal/util.rb @@ -237,6 +237,11 @@ def dig(data, pick, &blk) end end + # @type [Regexp] + # + # https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3 + RFC_3986_NOT_PCHARS = /[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/ + class << self # @api private # @@ -247,6 +252,15 @@ def uri_origin(uri) "#{uri.scheme}://#{uri.host}#{":#{uri.port}" unless uri.port == uri.default_port}" end + # @api private + # + # @param path [String, Integer] + # + # @return [String] + def encode_path(path) + path.to_s.gsub(ModerationAPI::Internal::Util::RFC_3986_NOT_PCHARS) { ERB::Util.url_encode(_1) } + end + # @api private # # @param path [String, Array] @@ -259,7 +273,7 @@ def interpolate_path(path) in [] "" in [String => p, *interpolations] - encoded = interpolations.map { ERB::Util.url_encode(_1) } + encoded = interpolations.map { encode_path(_1) } format(p, *encoded) end end @@ -576,10 +590,10 @@ def encode_query_params(query) case val in ModerationAPI::FilePart unless val.filename.nil? - filename = ERB::Util.url_encode(val.filename) + filename = encode_path(val.filename) y << "; filename=\"#{filename}\"" in Pathname | IO - filename = ERB::Util.url_encode(::File.basename(val.to_path)) + filename = encode_path(::File.basename(val.to_path)) y << "; filename=\"#{filename}\"" else end diff --git a/lib/moderation_api/version.rb b/lib/moderation_api/version.rb index 508ede8..86d149a 100644 --- a/lib/moderation_api/version.rb +++ b/lib/moderation_api/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module ModerationAPI - VERSION = "2.11.1" + VERSION = "2.11.2" end diff --git a/rbi/moderation_api/internal/util.rbi b/rbi/moderation_api/internal/util.rbi index 847a249..9acf9e1 100644 --- a/rbi/moderation_api/internal/util.rbi +++ b/rbi/moderation_api/internal/util.rbi @@ -148,12 +148,20 @@ module ModerationAPI end end + # https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3 + RFC_3986_NOT_PCHARS = T.let(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/, Regexp) + class << self # @api private sig { params(uri: URI::Generic).returns(String) } def uri_origin(uri) end + # @api private + sig { params(path: T.any(String, Integer)).returns(String) } + def encode_path(path) + end + # @api private sig { params(path: T.any(String, T::Array[String])).returns(String) } def interpolate_path(path) diff --git a/sig/moderation_api/internal/util.rbs b/sig/moderation_api/internal/util.rbs index cc943cf..4c8bbf9 100644 --- a/sig/moderation_api/internal/util.rbs +++ b/sig/moderation_api/internal/util.rbs @@ -45,8 +45,12 @@ module ModerationAPI -> top? } -> top? + RFC_3986_NOT_PCHARS: Regexp + def self?.uri_origin: (URI::Generic uri) -> String + def self?.encode_path: (String | Integer path) -> String + def self?.interpolate_path: (String | ::Array[String] path) -> String def self?.decode_query: (String? query) -> ::Hash[String, ::Array[String]]