Skip to content

util: avoid quadratic whitespace scan in MIMEType parser - #63916

Open
uwezkhan wants to merge 1 commit into
nodejs:mainfrom
uwezkhan:mime-trailing-ws-scan
Open

util: avoid quadratic whitespace scan in MIMEType parser#63916
uwezkhan wants to merge 1 commit into
nodejs:mainfrom
uwezkhan:mime-trailing-ws-scan

Conversation

@uwezkhan

Copy link
Copy Markdown

The MIME parser trims trailing HTTP whitespace from the subtype, the parameter list, and each parameter value by searching against the unanchored regex /[\r\n\t ]*$/. String.prototype.search restarts that match from every offset, so a long run of internal whitespace makes each trim O(n^2). The run is reachable from untrusted input through the public util.MIMEType API and through data: URL parsing, e.g. new MIMEType('text/plain;x=a' + ' '.repeat(60000) + 'b'), which is a quadratic-blowup ReDoS.

Replacing the three searches with a backward whitespace scan returns the same start-of-trailing-whitespace index in linear time. Keeping the bound in the parser rather than asking callers to pre-trim matters because the constructor, the lazy params parse, and the value parse all funnel through the same trim and consume that index identically. The helper is a few lines longer than the regex constant in exchange for dropping the quadratic factor; parse output is unchanged, verified equivalent to the old regex over 300k random inputs.

Before vs after, same 60k input:

before: util.MIMEType parse blocks the event loop ~8000ms
after:  ~0.03ms, same as a benign 'text/plain;x=ab'

@nodejs-github-bot nodejs-github-bot added the needs-ci PRs that need a full CI run. label Jun 14, 2026
@uwezkhan

uwezkhan commented Jul 8, 2026

Copy link
Copy Markdown
Author

any update?

@MikeMcC399 MikeMcC399 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Your PR hasn't attracted the attention of a reviewer so far, and it is now more than 1000 commits behind the main branch.

If you wish to keep this PR active, I suggest that you rebase according to the Pull requests documentation.

Some issues that caused failures in macOS have been resolved in later commits.

Note that current rules in:

advise you should tackle only one issue at a time and that you should not open any new PRs until your first PR has been approved.

You also have PR #63813 open, which has not been reviewed or approved. The rules were published after your PRs, so this is only to draw your attention to them, in case you were considering opening any other PRs.

@jasnell jasnell left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM once it's rebased and run through CI

Signed-off-by: uwezkhan <uwezkhan053@gmail.com>
@uwezkhan
uwezkhan force-pushed the mime-trailing-ws-scan branch from 998d008 to 2d6972c Compare September 8, 2026 06:38
@uwezkhan

uwezkhan commented Sep 8, 2026

Copy link
Copy Markdown
Author

Rebased onto current main (2987a59). The cherry-pick applied without conflicts because the three trim sites in lib/internal/mime.js are unchanged upstream, so the patch content is identical to the earlier revision.

Before vs after on the rebased build, input text/plain;x=a followed by a long run of spaces and b:

before: regex search, quadratic, ~8000ms at 60k spaces
after:  backward scan, 0.13ms at 60k, 0.77ms at 1M

test-mime-api and test-mime-whatwg pass locally, and old vs new parse output matched over 300k random inputs. The tradeoff is the same as before: a short helper in place of a one-line regex constant. Ready for a CI run.

Noted on the one-PR-at-a-time guidance.

@codecov

codecov Bot commented Sep 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.16%. Comparing base (2987a59) to head (2d6972c).

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #63916      +/-   ##
==========================================
- Coverage   90.16%   90.16%   -0.01%     
==========================================
  Files         771      771              
  Lines      265097   265113      +16     
  Branches    50358    50361       +3     
==========================================
+ Hits       239026   239027       +1     
- Misses      17011    17022      +11     
- Partials     9060     9064       +4     
Files with missing lines Coverage Δ
lib/internal/mime.js 100.00% <100.00%> (ø)

... and 25 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

Labels

needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants