Skip to content

fix(asyncio): reject connection URLs missing the scheme separator - #4246

Open
Arunendra21 wants to merge 3 commits into
redis:masterfrom
Arunendra21:fix-async-parse-url-missing-scheme-separator
Open

fix(asyncio): reject connection URLs missing the scheme separator#4246
Arunendra21 wants to merge 3 commits into
redis:masterfrom
Arunendra21:fix-async-parse-url-missing-scheme-separator

Conversation

@Arunendra21

@Arunendra21 Arunendra21 commented Aug 5, 2026

Copy link
Copy Markdown

Summary

The async parse_url in redis/asyncio/connection.py validated the URL scheme with urlparse(url).scheme, which accepts a URL that has a valid scheme name but is missing the :// separator, for example redis:foo.bar.com:12345. In that case urlparse reports the scheme as redis with an empty netloc, so the function returned partial kwargs (no host/port) and the async client silently connected to the default host instead of raising.

The sync parse_url in redis/connection.py already guards against this up front and has a dedicated test (test_invalid_scheme_raises_error_when_double_slash_missing), but the async copy did not, so redis.from_url("redis:foo.bar.com:12345") and redis.asyncio.from_url("redis:foo.bar.com:12345") behaved differently.

Changes

  • Add the same up-front scheme check that the sync version uses, so a URL missing the redis://, rediss://, or unix:// prefix raises ValueError with the same message. The now-unreachable trailing else branch is removed, matching the structure of the sync implementation.
  • Add test_invalid_scheme_raises_error_when_double_slash_missing to the async connection-pool URL-parsing tests, mirroring the existing sync test.

Testing

Verified that async parse_url / ConnectionPool.from_url now raises for redis:foo.bar.com:12345, localhost, and http://localhost, while valid redis://, rediss://, and unix:// URLs (including host, port, db, and querystring options) still parse exactly as before. The sync and async implementations now return matching results for these inputs.


Note

Low Risk
Localized URL validation at pool creation; behavior change only for previously mis-parsed or non-canonical scheme strings.

Overview
Connection URL parsing is tightened in both redis/connection.py and redis/asyncio/connection.py so invalid or ambiguous URLs fail fast with the same ValueError message.

parse_url now requires a case-insensitive redis://, rediss://, or unix:// prefix (RFC 3986 schemes). That rejects strings like redis:foo.bar.com:12345 where urlparse would treat redis as the scheme but leave no host—async previously could return partial kwargs and connect to defaults instead of raising. The async path is aligned with the sync guard and drops the redundant post-parse else branch.

Tests add coverage for the missing-:// case on async (mirroring sync) and for uppercase REDIS://, REDISS://, and UNIX:// on both clients.

Reviewed by Cursor Bugbot for commit 6460ba3. Bugbot is set up for automated code reviews on this repo. Configure here.

Behavior change (for release notes)

While aligning the sync and async parsers and addressing review feedback, the checks are now case-insensitive per RFC 3986. As a result the sync redis.from_url() now also accepts uppercase schemes such as REDIS://, REDISS://, and UNIX:// (the urlparse-based async parser already accepted these). This is a released-behavior change for the sync parser worth noting in the release notes; the missing-separator case (e.g. redis:foo.bar.com:12345) is still rejected.

The async parse_url used urlparse(url).scheme to validate the scheme,
which accepts a URL that has a valid scheme name but no "://" separator,
for example "redis:foo.bar.com:12345". In that case urlparse reports the
scheme as "redis" with an empty netloc, so the function returned partial
kwargs and the client silently connected to the default host instead of
raising.

The sync parse_url already guards against this up front and has a test
for it (test_invalid_scheme_raises_error_when_double_slash_missing), but
the async copy did not. This adds the same up-front check so both behave
identically, and drops the now-unreachable trailing else branch.

Adds the matching async test.

Co-authored-by: eeshsaxena <eeshsaxena@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0debd80e0b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread redis/asyncio/connection.py Outdated
The initial fix used a case-sensitive prefix check, which regressed async
parse_url by rejecting mixed-case schemes like "REDIS://host" that
urlparse() previously normalized and accepted. Normalize the URL with
.lower() before the prefix check so "REDIS://", "Rediss://", and "UNIX://"
are accepted again, while still requiring the "://" separator so
"redis:foo" is rejected. The same change is applied to the sync parse_url
so the two implementations stay consistent.

Adds a test that an uppercase scheme is accepted, for both sync and async.

Co-authored-by: eeshsaxena <eeshsaxena@gmail.com>
@Arunendra21

Copy link
Copy Markdown
Author

Good catch, thanks. Updated the check to normalize the scheme case with url.lower().startswith((...)), so REDIS://, Rediss://, and UNIX:// are accepted again while the missing-separator case (e.g. redis:foo.bar.com:12345) still raises. Applied the same change to the sync parse_url so the two stay consistent, and added an uppercase-scheme test to both.

@petyaslavova petyaslavova left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @Arunendra21, thank you for your contribution!

Two items before merge:

  1. Please extend the uppercase coverage to REDISS:// (asserting SSLConnection) and UNIX:// (asserting UnixDomainSocketConnection) in both tests/test_connection_pool.py and tests/test_asyncio/test_connection_pool.py. Case-insensitive acceptance is new for the sync parser, and the TLS variant is the one worth pinning with a test.
  2. Please mention in the PR description that sync from_url now accepts uppercase schemes — it is a released-behavior change we want captured in the release notes.

@petyaslavova petyaslavova added maintenance Maintenance (CI, Releases, etc) waiting-for-response labels Aug 5, 2026
Per review, cover the TLS and unix-socket variants of the case-insensitive
scheme handling in both the sync and async connection-pool URL-parsing
tests, asserting SSLConnection and UnixDomainSocketConnection respectively.

Co-authored-by: eeshsaxena <eeshsaxena@gmail.com>
@Arunendra21

Copy link
Copy Markdown
Author

Thanks @petyaslavova! Both addressed:

  1. Extended test_uppercase_scheme_is_accepted in both tests/test_connection_pool.py and tests/test_asyncio/test_connection_pool.py to also assert REDISS://SSLConnection and UNIX://UnixDomainSocketConnection.
  2. Added a "Behavior change (for release notes)" section to the PR description noting that sync from_url now accepts uppercase schemes, while the missing-separator case is still rejected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintenance Maintenance (CI, Releases, etc) waiting-for-response

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants