refactor(dpi/ssdp): case-fold header name without allocating#290
Merged
Conversation
The ST/NT header lookup converted each header line into a fresh
lowercased `String` (`line.to_lowercase()`) just to compare the
3-byte prefix "st:" / "nt:". For an SSDP message with N header
lines this allocates N times per packet, and only the prefix actually
needs case-insensitive comparison.
Replace the `to_lowercase` allocation with
`line.get(..3).is_some_and(|p| p.eq_ignore_ascii_case("st:") ||
p.eq_ignore_ascii_case("nt:"))`. The value extraction via
`line.get(3..)` is unchanged.
Add `test_ssdp_mixed_case_st_and_nt_headers` exercising all four
case mixes (`ST`/`St`/`sT`/`st` and the same for `NT`) to
lock the case-insensitivity invariant per HTTP/1.1 §3.2 field-name
rules — a future refactor that drops the case fold will fail this
test rather than silently regress.
Owner
|
@0xghost42 thanks a lot, this lgtm! |
This was referenced May 20, 2026
domcyrus
pushed a commit
that referenced
this pull request
May 21, 2026
The header loop in `analyze_http` lowercased every header line via `to_lowercase()` only to compare the result against the two ASCII literals "host" and "user-agent". That allocates a fresh `String` per header line per packet, on the DPI hot path. HTTP/1.1 §3.2 makes field-names case-insensitive, so compare in place with `str::eq_ignore_ascii_case` — no allocation, behavior preserved. Add `test_http_mixed_case_host_and_user_agent_headers` covering four case mixes per header name so a future refactor that drops the case-insensitive compare fails this test instead of silently regressing — same shape as the regression tests added in #290 (SSDP) and #278 (NetBIOS). Refs #300
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The ST/NT header lookup in
analyze_ssdpconverted each header line into a fresh lowercasedStringjust to compare the 3-byte prefix\"st:\"/\"nt:\". For an SSDP packet with N header lines this allocates N times per packet, and only the prefix actually needs case-insensitive comparison.Replace the per-line
to_lowercase()allocation withline.get(..3).is_some_and(|p| p.eq_ignore_ascii_case(\"st:\") || p.eq_ignore_ascii_case(\"nt:\")). The value extraction vialine.get(3..)is unchanged, since both\"st:\"and\"nt:\"are exactly 3 ASCII bytes.Behavior is unchanged: the field-name check is still case-insensitive (HTTP/1.1 §3.2), and the value is still trimmed and required to be non-empty.
Why a regression test
The existing tests only exercise upper-case
ST:/NT:, so dropping the case-fold would not have failed any test. The newtest_ssdp_mixed_case_st_and_nt_headersexercises all four case mixes per field name (ST,St,sT,standNT,Nt,nT,nt) so a future refactor that drops the case fold will fail this test instead of silently regressing — same shape as the regression test added in #278 fordecode_netbios_name.Verification
cargo test --lib: 360 passed, 0 failed (8 innetwork::dpi::ssdp, incl. the new test).cargo clippy --all-targets -- -D warnings: clean.cargo fmt --check: clean.Notes
Real SSDP traffic from UPnP devices commonly uses mixed-case header names — the Microsoft Windows SSDP stack and the Linux miniupnpd implementation both differ from each other in capitalisation, and HTTP §3.2 explicitly makes the field-name case-insensitive.