Skip to content

Unescape quoted-pairs inside quoted-strings - #140

Open
gaoflow wants to merge 1 commit into
staktrace:masterfrom
gaoflow:fix-quoted-pair-unescaping
Open

Unescape quoted-pairs inside quoted-strings#140
gaoflow wants to merge 1 commit into
staktrace:masterfrom
gaoflow:fix-quoted-pair-unescaping

Conversation

@gaoflow

@gaoflow gaoflow commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

parse_content_disposition(r#"attachment; filename="a\"b.txt""#) returns the filename as a\"b.txt instead of a"b.txt — the quotes around a parameter value get stripped but the quoted-pairs inside them are never undone. Two neighbouring spots have the same gap: Display for SingleInfo/GroupInfo escapes " in a display name but not \, so the name Foo\Bar renders as "Foo\Bar" <x@y.com> and addrparse reads that straight back as FooBar — the crate emits something its own parser silently corrupts; and the comment state ends on an escaped \), so x@y.com (a\)b) parses to the address x@y.com b). The quoted display-name reader is the one place that already gets this right, which is why the round-trip loses data rather than erroring.

In display names I kept RFC 5322 §3.2.1 quoted-pair in full (backslash before anything, obs-qp included) since that is what the quoted-name reader already does. In MIME parameter values I only undo \" and \\ and leave every other \x alone, so filename="C:\dev\go\foo.txt" still comes out intact — that is where Python's email and Go's mime both draw the line, and I checked each row of the change against both (the only case they disagree on is \;, which I left untouched). A backslash outside quotes stays literal either way; the existing parse_backslashes test fails if that gets widened.

cargo test --all goes from 54 to 56 unit tests plus 25 doctests, all green; cargo fmt -- --check is clean and cargo clippy shows no new warnings.

Parameter values in Content-Type/Content-Disposition had their surrounding
quotes stripped but the \" and \\ pairs inside them left as-is, so
filename="a\"b.txt" came back as a\"b.txt. Two related spots: Display for
SingleInfo/GroupInfo escaped " in a display name but not \, so a name holding
a backslash round-tripped through addrparse with the backslash dropped; and
the comment state ended on an escaped \), leaking the rest of the comment
into the parsed address.

Display names use the full RFC 5322 quoted-pair, matching what the quoted-name
reader already does. Parameter values only undo \" and \\, which keeps the
unescaped Windows paths that show up in real filename= parameters intact, the
same line Python's email and Go's mime draw.
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