Companion helper that separates the three independent questions
get_parse_status collapses into one value: did the input
present well-formed URL syntax (layer 1), was the parsed object admitted
under the active policy (layer 2), and what did the Public Suffix List
annotation find (layer 3).
Arguments
- url
A character vector of URLs.
- url_standard
Standard profile governing interpretation:
NULL(default),"rfc3986", or"whatwg". Unlike the other companion helpers this argument does not gate the result.- protocol_handling
A character string specifying how to handle protocols. Defaults to "keep". Regardless of this option, rurl only processes authority-based URLs whose scheme is one of http, https, ftp, or ftps; a scheme-bearing input with any other scheme (e.g.
mailto:,tel:,ws:) yieldsparse_status = "error". Scheme inference (below) also requires the input to be host-shaped: a scheme-less string that is not a host (e.g."asdfghjkl","12345","/path") or is a non-canonical IP literal (integer/hex/octal/short forms, or leading-zero octets like"192.168.010.1") is rejected as"error"rather than having a scheme fabricated for it."keep": If a supported scheme exists (http, https, ftp, ftps), it's used. If no scheme and the input is host-shaped, "http://" is added; otherwise the input is not a URL and yields
"error"."none": If a supported scheme exists, it's used. If no scheme, then no scheme is used (scheme component will be NA).
"strip": Any existing scheme is removed (scheme component will be NA).
"http": The scheme is forced to be "http".
"https": The scheme is forced to be "https".
- scheme_relative_handling
How to handle URLs starting with "//". Defaults to "keep".
"keep": Parse using http but return scheme as NA and set status to "ok-scheme-relative".
"http": Assume http for parsing and output.
"https": Assume https for parsing and output.
"error": Treat scheme-relative URLs as invalid.
- scheme_policy
Controls whether scheme-less, host-shaped input is accepted (an input-acceptance axis, distinct from
protocol_handling, which only controls how the scheme is presented, and fromurl_standard, which controls interpretation). Defaults to "infer"."infer": (Default) Fabricate
http://for scheme-less host-shaped input (e.g.example.comparses ashttp://example.com), a browser-omnibox-style affordance. This is the historical behavior."require": Reject scheme-less input — a scheme-less host-shaped value becomes
parse_status = "error"rather than gaining a fabricated scheme. Use this for a strict, pure-parser posture. Note this governs only bare host input; scheme-relative//hostinput is governed separately byscheme_relative_handling.
- scheme_acceptance
Which scheme tokens may enter parsing (a scheme-acceptance axis, distinct from
scheme_policy, which governs scheme-less input, and fromurl_standard, which governs interpretation). Defaults to "web"."web": (Default) Only the curated web-scheme allowlist (
http/https/ftp/ftps/file) is admitted; a scheme-bearing input outside it isparse_status = "error". This is the historical, byte-for-byte compatible behavior."general": Admit any syntactically valid scheme token and parse opaque (
mailto:x), non-special (foo://host), and RFC-generic URLs. Requires an expliciturl_standard("rfc3986"or"whatwg"), which decides the interpretation;generalwithurl_standard = NULLis an error. Non-special / opaque hosts receive no www-stripping, no domain/TLD derivation, and are never run through the IDNA/punycode helpers. A non-special scheme with no//is an opaque path: it has no authority, sohost,user,portand thedomain/tldcolumns are allNAand the entire remainder is thepath(query/fragmentare still split off). This includesmailto:— the recipient's@never re-triggers authority parsing. To decompose amailto:recipient, use the accessors (get_host()/get_domain()/get_user(), ADR 0012 D7) orget_mailto_recipients(); those deliberately return a recipient's parts where this table presentsNA, because a recipient domain is extraction metadata, not the URL's authority.
- tld_source
Which TLD source to use for TLD extraction: "all", "icann", or "private". Defaults to "all".
Value
A data frame with one row per element of url and three
character columns: layer1_syntax_verdict,
layer2_policy_verdict, and layer3_annotation_state.
Details
The single parse_status value is a lossy projection of these
three. The guaranteed loss is that a structural syntax failure and a policy
rejection both surface as "error": under the default
scheme_acceptance = "web", "mailto:jane@example.com" and
"http://" are both "error", but the first is
layer2_policy_verdict = "rejected-scheme" (rurl declined to accept the
scheme) while the second is layer1_syntax_verdict = "fail" (it did not
parse). Recovering that distinction is what this helper is for.
Like the other companion helpers this never widens the
safe_parse_url frame — the parse table keeps its 18 columns
and the verdicts live here. Unlike get_host_type and
get_scheme_class, it is fully defined at
url_standard = NULL: layers 1 and 2 describe the parse that actually
occurred, which happens with or without a standard selector.
Why this helper is not gated on url_standard
get_host_type and get_scheme_class return
NA unless a selector is passed. That gate is not a house style —
it is a consequence of what those helpers report. Their content is
standard-relative: whether a host is an IPv4 address, or a scheme
is special, is a question only a standard can answer, so without a
selector there is no fact to return.
Verdict layers are not standard-relative in that way. A syntax failure
(layer 1) and an admission rejection (layer 2) are facts about the parse
that this call actually performed, under whatever options were
supplied. Those facts exist at url_standard = NULL exactly as they
do under a selector, so there is nothing to withhold.
Gating anyway would also break the helper's central guarantee. Because
parse_status is the projection of these three layers, projecting
the reported layers must reproduce the reported status. Returning
NA at url_standard = NULL while parse_status still
reports a real value would make the companion contradict the column it
exists to explain — on the most common call, and precisely when a caller
is asking why a default-options parse failed.
Layers
Layer 1 — syntax ("pass" / "fail"). Whether a
syntax failure was observed. "pass" is the absence of an
observed failure, not a proof of conformance — a row the admission gate
rejected before any parse ran reports its rejection in layer 2 and is not
additionally reported as a syntax failure.
Layer 2 — policy ("admitted",
"admitted-scheme-relative", "admitted-ftp",
"rejected-scheme", "warn-userinfo"). Whether the object is
admitted under the active scheme_acceptance /
scheme_relative_handling / userinfo policy, and with what note.
"rejected-scheme" rejects; "warn-userinfo" accepts with a
note; the admitted* values accept.
Layer 3 — annotation ("not-applicable",
"known", "unknown", and the currently unproduced
"not-requested", "invalid-input", "dependency-error").
The PSL registrability fact as a typed state rather than a bare
NA, and never fatal: a host with no public suffix is a
"unknown" annotation, not a parse failure. A host form with no
registrable-domain concept at all — an IP literal, a file: host,
an opaque authority — is "not-applicable", never "unknown".
Examples
# Both are parse_status "error" -- for entirely different reasons.
get_parse_verdicts(c("mailto:jane@example.com", "http://"))
#> layer1_syntax_verdict layer2_policy_verdict layer3_annotation_state
#> 1 pass rejected-scheme not-applicable
#> 2 fail admitted not-applicable
# A PSL miss is an annotation state, never a fatal verdict.
get_parse_verdicts("http://example.invalidtld/")
#> layer1_syntax_verdict layer2_policy_verdict layer3_annotation_state
#> 1 pass admitted unknown