Skip to content

fix: decoded host size for IPv6 zone IDs - #1005

Merged
alandefreitas merged 1 commit into
boostorg:developfrom
alandefreitas:fix/ipv6-zone-id-decoded-size
Oct 13, 2026
Merged

alandefreitas merged 1 commit into
boostorg:developfrom
alandefreitas:fix/ipv6-zone-id-decoded-size

Conversation

@alandefreitas

Copy link
Copy Markdown
Member

The host rule stored the encoded size of an IPv6 literal as its decoded size. A zone ID shrinks when decoded ("%25" becomes "%", and the zone ID itself may contain pct-encoded octets), so the stored size overshot and every accessor that decodes the host produced a string with trailing garbage:

url_view u("http://[fe80::1%25eth0]/");
u.host_address(); // "fe80::1%eth0\0\0", size 14 instead of 12

The ip_literal_rule now forwards the zone ID parsed by ipv6_addrz_rule, and the host rule derives the decoded size from it.

The assertion in encoded_host_address() compared the decoded size with the encoded size, which only holds without a zone ID, and had been relaxed in url_view_base to tolerate the wrong value. It is removed from both url_view_base and authority_view: the invariant is covered by tests, like every other encoded_* accessor. Checking it exposed three more bookkeeping bugs in the same family, fixed here as well:

  • remove_authority() left the decoded sizes of the removed user, password and host behind, so encoded_authority().decoded_size() was non-zero on a URL without an authority.
  • encoded_authority() never counted the "@" separator nor the port, so url_view("http://host:8080/").encoded_authority().decode() returned "host".
  • format() stored the bracketed host size without the closing "]", and counted the ":" delimiter in the password and port sizes, so format("http://[fe80::1]/").host() returned "[fe80::1".

The existing issue #919 regression test is kept as is. New tests cover the parser, authority_view, the url setters, remove_authority and format with zone IDs, pct-encoded zone IDs, userinfo and ports.

Thanks to Sergei Zimmerman for identifying the issue in #1004.

Closes #1004

@cppalliance-bot

cppalliance-bot commented Oct 12, 2026 •

Copy link
Copy Markdown

An automated preview of the documentation is available at https://1005.url.prtest2.cppalliance.org/index.html

If more commits are pushed to the pull request, the docs will rebuild at the same URL.

2026-10-13 02:35:11 UTC

@cppalliance-bot

cppalliance-bot commented Oct 12, 2026 •

Copy link
Copy Markdown

GCOVR code coverage report https://1005.url.prtest2.cppalliance.org/gcovr/index.html
LCOV code coverage report https://1005.url.prtest2.cppalliance.org/genhtml/index.html
Coverage Diff Report https://1005.url.prtest2.cppalliance.org/diff-report/index.html

Build time: 2026-10-13 02:48:04 UTC

@codecov

codecov Bot commented Oct 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.12%. Comparing base (78c30a1) to head (dbac83d).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##           develop    #1005   +/-   ##
========================================
  Coverage    99.12%   99.12%           
========================================
  Files          154      154           
  Lines        10093    10103   +10     
========================================
+ Hits         10005    10015   +10     
  Misses          88       88           
Files with missing lines Coverage Δ
include/boost/url/impl/authority_view.hpp 100.00% <ø> (ø)
include/boost/url/impl/url_base.hpp 99.47% <100.00%> (+<0.01%) ⬆️
include/boost/url/impl/url_view_base.hpp 98.64% <100.00%> (ø)
include/boost/url/rfc/detail/impl/host_rule.hpp 100.00% <100.00%> (ø)
...lude/boost/url/rfc/detail/impl/ip_literal_rule.hpp 94.73% <100.00%> (+0.14%) ⬆️
src/detail/pattern.cpp 100.00% <100.00%> (ø)

... and 1 file with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 78c30a1...dbac83d. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

The host rule stored the encoded size of an IPv6 literal as its
decoded size. A zone ID shrinks when decoded ("%25" becomes "%",
and the zone ID itself may contain pct-encoded octets), so the
stored size overshot and every accessor that decodes the host
produced a string with trailing garbage:

    url_view u("http://[fe80::1%25eth0]/");
    u.host_address(); // "fe80::1%eth0\0\0", size 14 instead of 12

The ip_literal_rule now forwards the zone ID parsed by
ipv6_addrz_rule, and the host rule derives the decoded size from it.

The assertion in encoded_host_address() compared the decoded size
with the encoded size, which only holds without a zone ID, and had
been relaxed in url_view_base to tolerate the wrong value. It is
removed from both url_view_base and authority_view: the invariant
is covered by tests, like every other encoded_* accessor. Checking
it exposed three more bookkeeping bugs in the same family, fixed
here as well:

- remove_authority() left the decoded sizes of the removed user,
  password and host behind, so encoded_authority().decoded_size()
  was non-zero on a URL without an authority.
- encoded_authority() never counted the "@" separator nor the port,
  so url_view("http://host:8080/").encoded_authority().decode()
  returned "host".
- format() stored the bracketed host size without the closing "]",
  and counted the ":" delimiter in the password and port sizes, so
  format("http://[fe80::1]/").host() returned "[fe80::1".

The existing issue boostorg#919 regression test is kept as is. New tests
cover the parser, authority_view, the url setters, remove_authority
and format with zone IDs, pct-encoded zone IDs, userinfo and ports.

Thanks to Sergei Zimmerman for identifying the issue in boostorg#1004.

Closes boostorg#1004
@alandefreitas
alandefreitas force-pushed the fix/ipv6-zone-id-decoded-size branch from dbac83d to 841f0a5 Compare October 13, 2026 02:32
@alandefreitas
alandefreitas merged commit 4dca58d into boostorg:develop Oct 13, 2026
45 of 83 checks passed
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