Skip to content

Match domain sub-applications on every spelling of the registered host - #13693

Open
rodrigobnogueira wants to merge 2 commits into
aio-libs:masterfrom
rodrigobnogueira:domain-host-normalization
Open

Match domain sub-applications on every spelling of the registered host#13693
rodrigobnogueira wants to merge 2 commits into
aio-libs:masterfrom
rodrigobnogueira:domain-host-normalization

Conversation

@rodrigobnogueira

@rodrigobnogueira rodrigobnogueira commented Sep 12, 2026

Copy link
Copy Markdown
Member

What do these changes do?

add_domain() stores the domain lowercased, without a trailing dot and without the default port, but matched a request against the raw Host header with nothing more than lower(). A Host of example.com. or example.com:80 therefore never matched a domain registered as example.com, and the request fell through to the parent application's routes.

The request side now applies the same normalization before comparing, for both Domain and MaskDomain. Only ASCII digits count as a port: "٨٠".isdigit() is true and int("٨٠") is 80, so a plain isdigit() check would have let a Host with a port in other digits match the domain, which the registration side never accepts.

Are there changes in behavior for the user?

A domain application now receives requests whose Host spells its domain with a trailing dot, an explicit :80, or uppercase letters. Previously those reached the parent application instead. A different port, including :443, or a port that is not a number, still does not match.

MaskDomain matching becomes case-insensitive as a result, matching Domain: it previously ran its regex against the raw Host, so A.EXAMPLE.COM did not match *.example.com while it did match a plain Domain.

Is it a substantial burden for the maintainers to support this?

No. One helper on Domain, shared with MaskDomain.

Related issue number

None.

Checklist

  • I think the code is well written
  • Unit tests for the changes exist
  • Documentation reflects the changes (no API change)
  • If you provide code modification, please add yourself to CONTRIBUTORS.txt
  • Add a new news fragment into the CHANGES/ folder

@psf-chronographer psf-chronographer Bot added the bot:chronographer:provided There is a change note present in this PR label Sep 12, 2026
@codecov

codecov Bot commented Sep 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.03%. Comparing base (5da6d53) to head (4712a95).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #13693   +/-   ##
=======================================
  Coverage   99.03%   99.03%           
=======================================
  Files         135      135           
  Lines       50940    50960   +20     
  Branches     2677     2678    +1     
=======================================
+ Hits        50446    50466   +20     
  Misses        370      370           
  Partials      124      124           
Flag Coverage Δ
Autobahn 21.94% <18.18%> (-0.01%) ⬇️
CI-GHA 98.92% <100.00%> (+<0.01%) ⬆️
OS-Linux 98.69% <100.00%> (-0.01%) ⬇️
OS-Windows 97.31% <100.00%> (+<0.01%) ⬆️
OS-macOS 98.18% <100.00%> (+<0.01%) ⬆️
Py-3.10 98.12% <100.00%> (+<0.01%) ⬆️
Py-3.11 98.35% <100.00%> (+<0.01%) ⬆️
Py-3.12 98.44% <100.00%> (+<0.01%) ⬆️
Py-3.13 98.43% <100.00%> (-0.01%) ⬇️
Py-3.14 98.10% <100.00%> (-0.36%) ⬇️
Py-3.14t 97.83% <100.00%> (-0.01%) ⬇️
Py-pypy-3.11 97.39% <100.00%> (-0.02%) ⬇️
VM-macos 98.18% <100.00%> (+<0.01%) ⬆️
VM-ubuntu 98.69% <100.00%> (-0.01%) ⬇️
VM-windows 97.31% <100.00%> (+<0.01%) ⬆️
cython-coverage 83.16% <18.18%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@codspeed-hq

codspeed-hq Bot commented Sep 12, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 14.07%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 1 improved benchmark
✅ 96 untouched benchmarks
⏩ 83 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
test_link_param_pattern_redos_payload[embedded_newlines] 40 µs 35.1 µs +14.07%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing rodrigobnogueira:domain-host-normalization (4712a95) with master (5da6d53)

Open in CodSpeed

Footnotes

  1. 83 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@rodrigobnogueira
rodrigobnogueira force-pushed the domain-host-normalization branch from f570b51 to c22594e Compare September 12, 2026 22:11
add_domain() stores the domain lowercased, without a trailing dot and
without the default port, but matched a request against the raw Host
header with nothing more than lower(). A Host of example.com. or
example.com:80 therefore never matched example.com and the request fell
through to the parent application's routes, which is not what a domain
application is for.

The request side now applies the same normalization before comparing,
for both Domain and MaskDomain. Only ASCII digits count as a port, since
that is all the registration side accepts, so a Host with a port spelled
in other digits stays unmatched rather than widening the domain.
@rodrigobnogueira
rodrigobnogueira force-pushed the domain-host-normalization branch from c22594e to 4712a95 Compare September 12, 2026 23:02
@rodrigobnogueira
rodrigobnogueira marked this pull request as ready for review September 13, 2026 04:47
@greptile-apps

greptile-apps Bot commented Sep 13, 2026

Copy link
Copy Markdown

Confidence Score: 4/5

Not safe to merge until oversized numeric Host ports no longer interrupt domain route resolution.

A reproduced routing failure remains in the changed host-normalization path.

Files Needing Attention: aiohttp/web_urldispatcher.py

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex produced a finding-comment-proof for a posted P1 finding.
  • T-Rex produced another finding-comment-proof for a posted P1 finding.
  • T-Rex performed general contract validation by authoring a Python reproduction script and capturing pre- and post-run logs, then verified the ValueError propagation on re-run.

View all artifacts

T-Rex Ran code and verified through T-Rex

Comments Outside Diff (1)

  1. General comment

    P1 Oversized numeric Host port raises during domain-subapplication matching

    • Bug
      • A Host header ending in 4,301 ASCII digits reaches Domain._normalize_host() through both Domain and MaskDomain route matching. Python 3.11 rejects conversion beyond its 4,300-digit limit, so matching raises ValueError instead of treating the host as unmatched and returning HTTP 404 Not Found.
    • Cause
      • Domain._normalize_host() accepts any ASCII digit suffix and invokes int(port) without bounding its length or catching ValueError.
    • Fix
      • Avoid integer conversion for arbitrary-length ports. Normalize only a bounded port representation, or catch ValueError around int(port) and return a nonmatching normalized host value so domain resolution falls through to 404.

    T-Rex Ran code and verified through T-Rex

Reviews (1): Last reviewed commit: "Add change note" | Re-trigger Greptile

name, sep, port = host.rpartition(":")
if sep and port.isascii() and port.isdigit():
name = name.rstrip(".")
port_number = int(port)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Oversized Host Port Crashes

A client can send a valid-sized Host header with a numeric port longer than Python's integer-string limit. This unbounded int(port) conversion raises ValueError while exact and wildcard domain sub-applications resolve the request. The exception prevents the normal unmatched-host fallback, causing routing to fail rather than return a 404 response.

Knowledge Base Used: Server routing, responses, and static files

Artifacts

Evidence from the check

  • This executable script builds exact and wildcard domain subapplications and resolves a request whose numeric Host port is one digit beyond Python's conversion limit, exercising the affected path.

Command output from the check

  • This captured execution runs the reproducer against pre-PR commit 5da6d53 and shows both domain forms return HTTP 404 Not Found, establishing the no-match baseline.

Command output from the check

  • This captured execution runs the reproducer against the PR implementation with the 4,301-digit numeric port and records the focused runtime invocation.

View artifacts

T-Rex Ran code and verified through T-Rex

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

Labels

bot:chronographer:provided There is a change note present in this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant