fix infinite loop parsing the Forwarded header - #13229
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #13229 +/- ##
==========================================
+ Coverage 98.98% 98.99% +0.01%
==========================================
Files 131 132 +1
Lines 48993 49296 +303
Branches 2550 2567 +17
==========================================
+ Hits 48496 48801 +305
+ Misses 373 371 -2
Partials 124 124
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
Merging this PR will not alter performance
Comparing Footnotes
|
8b5fd88 to
7cbe0aa
Compare
Co-authored-by: Sam Bull <aa6bs0@sambull.org>
| pos = semi + 1 | ||
| else: | ||
| # bad syntax here, skip to next field value | ||
| break |
There was a problem hiding this comment.
No test covers this line now.
There was a problem hiding this comment.
Good catch, the new break stole the inputs that used to land here. Added a "bad; for=_real" case to the parametrized test so the bad-syntax break is exercised again.
What do these changes do?
BaseRequest.forwardedwalks eachForwardedheader with a hand-written cursor loop. When a segment neither matches_FORWARDED_PAIR_REnor has a following;,field_value.find(";", pos)returns-1, so the empty-value branch setspos = -1 + 1 = 0and the cursor jumps back to the start. The loop then never makes progress and spins at 100% CPU on the event loop thread. A single header such asForwarded: a(alsofor=1.2.3.4; a,for=_; x,; a) is enough to hang the worker permanently. Readingrequest.forwardedis common in reverse-proxy setups, so any middleware or handler that touches it exposes this.The loop now breaks when there is no further
;to consume, since a trailing empty-or-malformed value ends the field-value either way. That also drops the off-by-one where the old[pos : field_value.find(";", pos)]slice quietly cut the last character when no;was present.Are there changes in behavior for the user?
No API change. Well-formed and previously-terminating headers parse exactly as before; the only difference is that the pathological inputs now terminate and return the valid prefix instead of hanging.
Is it a substantial burden for the maintainers to support this?
No. It touches the one parse loop and adds a parametrized regression test next to the existing
Forwardedtests.Related issue number
None.
Checklist
CONTRIBUTORS.txtCHANGES/folder