From 3c7da2b5c7d830e699bca5c2611c25fe0f8e2299 Mon Sep 17 00:00:00 2001 From: Taishi Kasuga Date: Sun, 20 Feb 2022 21:59:00 +0900 Subject: [PATCH] Fix a option parsing bug for cluster mode that percent encoded string is passed to server unintended --- lib/redis/cluster/option.rb | 4 +++- test/cluster_client_options_test.rb | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/redis/cluster/option.rb b/lib/redis/cluster/option.rb index f0fdca2f7..a8f1b5624 100644 --- a/lib/redis/cluster/option.rb +++ b/lib/redis/cluster/option.rb @@ -64,8 +64,10 @@ def parse_node_url(addr) raise InvalidClientOptionError, "Invalid uri scheme #{addr}" unless VALID_SCHEMES.include?(uri.scheme) db = uri.path.split('/')[1]&.to_i + username = uri.user ? URI.decode_www_form_component(uri.user) : nil + password = uri.password ? URI.decode_www_form_component(uri.password) : nil - { scheme: uri.scheme, username: uri.user, password: uri.password, host: uri.host, port: uri.port, db: db } + { scheme: uri.scheme, username: username, password: password, host: uri.host, port: uri.port, db: db } .reject { |_, v| v.nil? || v == '' } rescue URI::InvalidURIError => err raise InvalidClientOptionError, err.message diff --git a/test/cluster_client_options_test.rb b/test/cluster_client_options_test.rb index 4a15a1976..76d85bf46 100644 --- a/test/cluster_client_options_test.rb +++ b/test/cluster_client_options_test.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true -require_relative 'helper' +require 'uri' +require 'helper' # ruby -w -Itest test/cluster_client_options_test.rb class TestClusterClientOptions < Minitest::Test @@ -31,6 +32,12 @@ def test_option_class option = Redis::Cluster::Option.new(cluster: %w[redis://:bazzap@127.0.0.1:7000], password: 'foobar') assert_equal({ '127.0.0.1:7000' => { scheme: 'redis', password: 'bazzap', host: '127.0.0.1', port: 7000 } }, option.per_node_key) + option = Redis::Cluster::Option.new(cluster: %W[redis://#{URI.encode_www_form_component('!&<123-abc>')}:@127.0.0.1:7000]) + assert_equal({ '127.0.0.1:7000' => { scheme: 'redis', username: '!&<123-abc>', host: '127.0.0.1', port: 7000 } }, option.per_node_key) + + option = Redis::Cluster::Option.new(cluster: %W[redis://:#{URI.encode_www_form_component('!&<123-abc>')}@127.0.0.1:7000]) + assert_equal({ '127.0.0.1:7000' => { scheme: 'redis', password: '!&<123-abc>', host: '127.0.0.1', port: 7000 } }, option.per_node_key) + option = Redis::Cluster::Option.new(cluster: %w[redis://127.0.0.1:7000/0], db: 1) assert_equal({ '127.0.0.1:7000' => { scheme: 'redis', host: '127.0.0.1', port: 7000, db: 0 } }, option.per_node_key)