Skip to content

fix: remove repeated default ports from a URL host in linear time - #123

Merged
fredbi merged 1 commit into
go-openapi:masterfrom
fredbi:fix/quadratic-stripping
Sep 25, 2026
Merged

fredbi merged 1 commit into
go-openapi:masterfrom
fredbi:fix/quadratic-stripping

Conversation

@fredbi

@fredbi fredbi commented Sep 25, 2026

Copy link
Copy Markdown
Member

removeDefaultPort stripped one ":80" (or ":443") at a time and re-parsed the whole remaining host after each strip. With lenient colon parsing (Go 1.25, or GODEBUG urlstrictcolons=0 since Go 1.26), url.Parse accepts a host such as ":80:80:...:80", so a single $ref of a few hundred KB kept jsonreference.New busy for tens of seconds: the cost was quadratic in the length of the host.

The trailing repetitions are now counted in one scan and stripped at once. The shortened host is parsed at most twice: if it no longer parses, a single repetition stays, which is where the one-by-one removal stopped. Every shortened host but the last still ends with the default port, which url.Parse already accepted on the original host, so the result is the same as before and normalizing stays idempotent.

With the default strict colon parsing of Go 1.26 such hosts are rejected by url.Parse before normalization, so v1.0.2 and later are only exposed when an application opts out with urlstrictcolons=0. v1.0.1 (go 1.25.0) is exposed by default when built with Go 1.25.

FuzzRemoveDefaultPort checks the new implementation against the former one, and TestRemoveDefaultPortLinear pins the cost on 100 000 repetitions.

Change type

Please select: 🆕 New feature or enhancement|🔧 Bug fix'|📃 Documentation update

Short description

Fixes

Full description

Checklist

  • I have signed all my commits with my name and email (see DCO. This does not require a PGP-signed commit
  • I have rebased and squashed my work, so only one commit remains
  • I have added tests to cover my changes.
  • I have properly enriched go doc comments in code.
  • I have properly documented any breaking change.

@codecov

codecov Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.07%. Comparing base (1461e75) to head (85b93ab).
⚠️ Report is 2 commits behind head on master.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #123      +/-   ##
==========================================
+ Coverage   97.97%   99.07%   +1.09%     
==========================================
  Files           2        2              
  Lines          99      108       +9     
==========================================
+ Hits           97      107      +10     
+ Misses          2        1       -1     

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

removeDefaultPort stripped one ":80" (or ":443") at a time and re-parsed
the whole remaining host after each strip. With lenient colon parsing
(Go 1.25, or GODEBUG urlstrictcolons=0 since Go 1.26), url.Parse accepts
a host such as ":80:80:...:80", so a single $ref of a few hundred KB kept
jsonreference.New busy for tens of seconds: the cost was quadratic in the
length of the host.

The trailing repetitions are now counted in one scan and stripped at once.
The shortened host is parsed at most twice: if it no longer parses, a
single repetition stays, which is where the one-by-one removal stopped.
Every shortened host but the last still ends with the default port, which
url.Parse already accepted on the original host, so the result is the same
as before and normalizing stays idempotent.

With the default strict colon parsing of Go 1.26 such hosts are rejected
by url.Parse before normalization, so v1.0.2 and later are only exposed
when an application opts out with urlstrictcolons=0. v1.0.1 (go 1.25.0)
is exposed by default when built with Go 1.25.

FuzzRemoveDefaultPort checks the new implementation against the former
one, and TestRemoveDefaultPortLinear pins the cost on 100 000 repetitions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Frédéric BIDON <fredbi@yahoo.com>
@fredbi
fredbi force-pushed the fix/quadratic-stripping branch from d84edb8 to 85b93ab Compare September 25, 2026 20:25
@fredbi
fredbi merged commit 01d7aa2 into go-openapi:master Sep 25, 2026
24 checks passed
@fredbi
fredbi deleted the fix/quadratic-stripping branch September 25, 2026 20:38
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.

1 participant