Repository navigation
Validate IMAP URL components - #867
Open
danieleggert wants to merge 7 commits into
Open
danieleggert wants to merge 7 commits into
danieleggert wants to merge 7 commits into
Conversation
This was referenced Oct 12, 2026
danieleggert
force-pushed
the
harden-5-url-family
branch
from
October 24, 2026 09:37
eebdd75 to
725ef62
Compare
danieleggert
marked this pull request as ready for review
October 24, 2026 09:39
mdiep
approved these changes
Oct 28, 2026
Comment on lines
+70
to
+73
| func normalizedURLComponent( | ||
| _ characterClass: URLCharacterClass, | ||
| emptiness: URLComponentEmptiness = .rejected | ||
| ) -> String? { |
Collaborator
There was a problem hiding this comment.
Since this can return nil, it seems like it's doing more than normalization.
danieleggert
force-pushed
the
harden-5-url-family
branch
from
October 29, 2026 15:26
725ef62 to
6a292a3
Compare
danieleggert
force-pushed
the
harden-5-url-family
branch
2 times, most recently
from
October 30, 2026 14:48
3c588a1 to
bf278ad
Compare
danieleggert
force-pushed
the
harden-5-url-family
branch
from
October 30, 2026 14:56
bf278ad to
f465654
Compare
`EncodedMailbox(mailbox: "x] x\r\n* BYE")` was written verbatim inside the bare URL of `[REFERRAL …]`, injecting a response; likewise `EncodedUser`, `EncodedAuthenticationType`, `EncodedSearch`, `EncodedSection`. RFC 5092: `enc-user`/`enc-auth-type = 1*achar`, `enc-mailbox`/ `enc-search`/`enc-section = 1*bchar`. Each type's public `var` and labelled init become `init?(_:)`, literals trap, `String.init` reads. One helper validates by character class and `pct-encoded` triplet, and uppercases hex digits as the parser does, so values round-trip.
`EncodedAuthenticatedURL(data: "x\r\n* BYE")` was written verbatim at the end of a URLAUTH URL, injecting a response. RFC 4467: `enc-urlauth = 32*HEXDIG`. `init(data:)` and the public `var` become `init?(_:)`; literals trap; `String.init` reads. The parser read exactly 32 digits, so longer tokens didn't round-trip; it now reads all.
`IMAPServer(host: "h] x\r\n* BYE")` was written verbatim in the bare URL of `[REFERRAL …]`, injecting a response. `imap://[::1]/` parsed as host `::1` and re-encoded as `imap://::1/`. A negative port encoded as `:-1`. RFC 3986: `host = IP-literal / IPv4address / reg-name`. New nested `IMAPServer.Host` replaces the `String`: `init?(_:)` validates IPv6, IPvFuture and reg-name (IPv4 is a subset), literals trap. The parser keeps the brackets, accepts all of reg-name, and validates via `init?`; its unreachable IPv4 branch is gone. `port` is now `UInt16?`.
`.urlFetch([.init(url: "url", data: nil)])` encoded as
`URLFETCH("url" NIL)`, which our parser rejects.
RFC 4467: `urlfetch-data = "URLFETCH" 1*(SP url-full SP nstring)`. Write
each pair after a space, unparenthesized. Fix fixtures that enshrined
the old output.
`writeAuthIMAPURLRump`, `writeAuthIMAPURLFull`, `writeRelativeIMAPURL`, `writeURLFetchType`, `writeInternetMessageDate` and `writeListSelectBaseOptionQuoted` had no callers outside their own encode tests, nor did the writers only they reached (`writeAuthenticatedURL(NetworkMessagePath)`, `writeNetworkPath`, `writeAbsoluteMessagePath`, `writeIUIDOnly`, `writeURLMessageSectionOnly`, `writeMessagePathByteRangeOnly`). Delete them and those tests; parse tests stay.
`imap://h/INBOX/;UID=1/;SECTION=1/` parsed with section `1`, so
`EncodedSection("1/")` didn't round-trip: the parser dropped the `/`
even when no `;PARTIAL=` followed it. Drop it only when one does.
`.type("*")` encoded as `;AUTH=*`, which parses as `.any`; `.type("*x")`
failed to parse, since `*` matched first.
RFC 5092: `iauth = ";AUTH=" ( "*" / enc-auth-type )`. `init?(_:)`
rejects `*`; the parser tries the longer `enc-auth-type` first.
danieleggert
force-pushed
the
harden-5-url-family
branch
from
October 30, 2026 15:16
f465654 to
d6dfbd1
Compare
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.
[5/6] One of the design goals of this library is that the API types can only represent valid state. But that doesn’t hold true today. These 6 stacked PRs are smaller steps towards that goal. #863 #864 #865 #866 #867 #868
Motivation:
[REFERRAL]writes URL parts raw:IMAPServer(host: "h] x\r\n* BYE").Modifications:
Start with
URLCharacterClass(one validator for RFC 5092/3986) andIMAPServer.Host. TheEncoded*conversions are mechanical.Also fixes round-trips:
[::1]lost its brackets,;AUTH=*became.any,portwasInt, and the URLFETCH response was parenthesized.