Package {pslr}


Type: Package
Title: Public Suffix List Engine
Version: 1.2.1
Description: A focused implementation of the Public Suffix List (PSL). Bundles a reproducible, pinned PSL snapshot and implements the official prevailing-rule algorithm to answer public-suffix (eTLD) and registrable-domain (eTLD+1) queries. Distinguishes ICANN and PRIVATE rule sections, accepts Unicode and ASCII hostnames via 'punycoder' canonicalization, and supports an explicit, validated offline refresh path. The matcher is compiled with 'cpp11' and requires no external system library. Used as the PSL engine by the 'rurl' package.
License: MIT + file LICENSE
Language: en-US
URL: https://bart-turczynski.gitlab.io/pslr/, https://gitlab.com/bart-turczynski/pslr, https://CRAN.R-project.org/package=pslr, https://bart-turczynski.r-universe.dev
BugReports: https://gitlab.com/bart-turczynski/pslr/-/issues
Encoding: UTF-8
Depends: R (≥ 4.1.0)
Imports: digest, punycoder (≥ 1.1.0), tools, utils
LinkingTo: cpp11
Suggests: cucumber (≥ 2.0.0), curl, knitr, oysteR, rmarkdown, rosv, testthat (≥ 3.0.0), withr
Config/testthat/edition: 3
VignetteBuilder: knitr
Config/roxygen2/version: 8.0.0
X-schema.org-keywords: public suffix list, PSL, eTLD, eTLD+1, registrable domain, ICANN, domain parsing, domain extraction, domain names, TLD, cookie domains, IDNA, public suffix
NeedsCompilation: yes
Packaged: 2026-09-12 23:11:39 UTC; bartturczynski
Author: Bart Turczynski ORCID iD [aut, cre]
Maintainer: Bart Turczynski <bartek@turczynski.pl>
Repository: CRAN
Date/Publication: 2026-09-14 07:40:24 UTC

pslr: Public Suffix List Engine

Description

A focused implementation of the Public Suffix List (PSL). Bundles a reproducible, pinned PSL snapshot and implements the official prevailing-rule algorithm to answer public-suffix (eTLD) and registrable-domain (eTLD+1) queries. Distinguishes ICANN and PRIVATE rule sections, accepts Unicode and ASCII hostnames via 'punycoder' canonicalization, and supports an explicit, validated offline refresh path. The matcher is compiled with 'cpp11' and requires no external system library. Used as the PSL engine by the 'rurl' package.

Author(s)

Maintainer: Bart Turczynski bartek@turczynski.pl (ORCID)

Authors:

See Also

Core queries: public_suffix(), registrable_domain(), is_public_suffix(), suffix_extract(), public_suffix_rule(). List management and provenance: psl_use(), psl_refresh(), psl_version(), psl_rules().

The introduction vignette is a full tour: vignette("introduction", package = "pslr").

Examples

# The two core queries: public suffix (eTLD) and registrable domain (eTLD+1).
public_suffix("www.example.co.uk")
registrable_domain("www.example.co.uk")

# Every query is vectorized over a character vector of hostnames.
suffix_extract(c("shop.example.com", "www.example.co.uk"))

# Rule sections are selected explicitly, so a private registry only widens
# the answer when you ask it to.
public_suffix("mysite.blogspot.com", section = "icann")
public_suffix("mysite.blogspot.com", section = "private")

# Hosts are canonicalized before matching; A-labels in, Unicode back out.
registrable_domain("www.xn--bcher-kva.de", output = "unicode")

# Which rule decided the answer, and which list produced it.
public_suffix_rule("www.example.co.uk")
psl_version()[, c("source", "list_date", "unicode_version")]

Is a host itself a public suffix?

Description

TRUE exactly when the valid canonical host equals its own public suffix under the selected policy. Returns NA whenever public_suffix() would return NA (missing or invalid input, or an unresolved host under unknown = "na"). Under the default unknown = "default", an unlisted single label such as "madeuptld" is TRUE via the implicit * rule; ask unknown = "na" to test explicit membership instead.

Usage

is_public_suffix(
  domain,
  section = "all",
  unknown = "default",
  invalid = "na",
  engine = psl_default_engine()
)

Arguments

domain

Character vector of DNS hostnames (not URLs). Each element may be a mixed-case ASCII, Unicode, or A-label hostname, a single label, or a hostname with exactly one terminal root dot. See Input contract.

section

Which rule sections are eligible: "all" (default; ICANN and PRIVATE), "icann", or "private". Section filtering happens before prevailing-rule selection, so "private" does not silently add ICANN rules; a host matching no rule in the section falls through to the implicit default rule unless unknown = "na".

unknown

"default" (default) applies the spec's implicit * rule, so an unlisted single label is its own public suffix; "na" returns NA when no explicit rule in the selected section matches.

invalid

"na" (default) returns NA for each invalid element without a warning; "error" aborts on the first invalid element, reporting its 1-based index.

engine

The psl_engine to query against; defaults to the session-global engine selected by psl_use(), so most callers never set it. Pass an engine from psl_engine() to resolve hosts against a specific snapshot in isolation.

Value

A logical vector with length(domain), preserving the names of domain.

Input contract

NA is treated as missing (returns NA), not invalid. Invalid elements include empty or whitespace-only strings, leading or consecutive dots, URL syntax, IPv6 addresses, canonical dotted-decimal IPv4 literals, and labels that fail hostname/IDNA validation. Wrong argument types and non-scalar or unknown option values always abort regardless of invalid.

See Also

public_suffix()

Examples

is_public_suffix("com")
is_public_suffix("example.com")
is_public_suffix("madeuptld")
is_public_suffix("madeuptld", unknown = "na")

Prune unreferenced local Public Suffix List snapshots

Description

Reclaims cached snapshots that nothing points at any more. The call is explicit, strictly offline, and destructive by design: it deletes snapshot files. It never changes which list is active, and every reference that could still be followed survives it.

Usage

psl_cache_prune(keep = 1L)

Arguments

keep

Number of unreferenced snapshots to retain in addition to every referenced one, as a single non-negative whole number. The default 1 keeps one snapshot of history beyond what is still referenced; 0 keeps only referenced snapshots.

Details

A snapshot is protected, and therefore never removed, when it is any of:

Retention is ordered by when a snapshot's bytes were first retrieved, as recorded in its descriptor when it was published, rather than by file modification time. A copy, a restore from backup, or any tool that rewrites timestamps changes mtime but not the fact of when the bytes were received, so first retrieval is the only stable order for history.

Pruning runs under the cache's publication lock and removes only complete .dat/.rds snapshot pairs, so it can never leave a reference pointing at bytes that are gone. Snapshot state pslr cannot fully read is treated as a reference it cannot see: if any source or selection stream is damaged, nothing is collected at all, and the damage is left visible rather than quietly erased. psl_cache_prune() is an explicit mutator, so it also performs the one-time migration of a pre-v2 cache before pruning; it never deletes legacy files, and it never reads or writes the reminder preference, which is configuration and lives outside the cache.

One honest limitation: pruning cannot discover engines held by other R processes, which already hold their parsed rules in memory. It therefore guarantees persistent referential integrity – no stored reference is ever left dangling – and not continued on-disk availability for another process's detached engine descriptor.

This is distinct from psl_cache_clear(), which only flushes this session's in-memory match-result cache and deletes nothing from disk.

Value

Invisibly, a data.frame with one row per removed snapshot and the columns checksum (character, the "sha256:<hex>" identity), bytes_path and descriptor_path (character paths removed, NA when that half was already absent), and bytes_reclaimed (numeric). The frame has zero rows when nothing was pruned, including when there is no cache at all. A prune that removes only part of what it selected signals an error of class pslr_prune_partial_error whose result field is this same frame, describing what was removed before the failure.

See Also

psl_snapshots(), which lists what a prune would consider; psl_refresh(), which publishes the snapshots this reclaims; psl_use().

Examples

# Deleting cached snapshots is never a side effect of running an example:
if (interactive()) {
  psl_cache_prune() # keep referenced snapshots plus one more
  psl_cache_prune(keep = 0) # keep only referenced snapshots
}

Compare two Public Suffix List snapshots

Description

Reports which rules were added, removed, or changed between two Public Suffix List snapshots that are already available locally. The comparison is canonical rather than textual: both sides are parsed and canonicalized first, so comments, blank lines, whitespace, letter case, source ordering, and raw Unicode spelling are never reported as changes.

Usage

psl_diff(old, new, ...)

Arguments

old, new

The two snapshots to compare. Each accepts, independently, one of: "bundled" (the snapshot installed with the package), "cache" (the snapshot psl_use() would resolve, i.e. the current cache selection), a path to a local PSL source file, a psl_engine from psl_engine(), or a rule table with the psl_rules() schema. "bundled" and "cache" are reserved names, so a file with either of those names must be given as a path carrying a directory component.

...

These dots are for future extension and must be empty.

Details

The call is strictly offline. No input form triggers a request, and neither side changes the session-global list that psl_use() controls, so diffing the cache leaves the next query answering from exactly the list it did before.

Value

A base data.frame with one row per changed logical identity, ordered by that identity, and columns, in order: change ("added", "removed", or "changed"), rule (the logical identity), old_rule and new_rule (canonical rule text including any ⁠*.⁠ or ! marker), old_kind and new_kind ("normal", "wildcard", or "exception"), and old_section and new_section ("icann" or "private"). Every field belonging to a side the identity is absent from is NA. Two snapshots that agree return the same columns and types with zero rows.

Provenance is attached as the attributes old_version and new_version, each a one-row psl_version() frame describing that side's snapshot, or NULL when the input was a rule table and therefore carries no provenance.

Which snapshots are available

The upstream endpoint publishes only the current list, and the list itself asks callers not to depend on version-control URLs, so psl_diff() resolves no dates and downloads no history. Installing the package performs no request and provides only the bundled snapshot; local collection begins at the first explicit psl_refresh(), after which each distinct validated download is retained as an immutable file until psl_cache_prune() collects it. psl_snapshots() lists what is resolvable, with a path for each set of stored bytes; any of those paths, or any historical revision the caller materializes as a file by other means, can be passed here directly.

Change semantics

A rule's logical identity is its canonical labels with the leading ⁠*.⁠ or ! marker removed, so ⁠*.example.com⁠ and example.com are the same identity in two different states. change is:

added

The identity exists only in new.

removed

The identity exists only in old.

changed

The identity exists in both, but its canonical rule kind or its ICANN/PRIVATE section differs.

Identities that exist in both snapshots in the same state are not reported. Section membership is a compared attribute rather than part of the identity, so a rule moving between the ICANN and PRIVATE sections is one changed row rather than an unrelated removed/added pair. A list may legally carry the same labels once in each section; such rules collapse into the single row for their identity, with the values of that side joined in ICANN-then-PRIVATE order.

See Also

psl_snapshots(), psl_refresh(), psl_rules(), psl_version()

Examples

# Two small lists on disk, written offline.
write_list <- function(private) {
  path <- tempfile(fileext = ".dat")
  writeLines(
    c(
      "// ===BEGIN ICANN DOMAINS===",
      "com",
      "// ===END ICANN DOMAINS===",
      "// ===BEGIN PRIVATE DOMAINS===",
      private,
      "// ===END PRIVATE DOMAINS==="
    ),
    path
  )
  path
}
old <- write_list(c("a.example.com", "*.b.example.com"))
new <- write_list(c("b.example.com", "c.example.com"))

# One row each: a.example.com removed, b.example.com changed kind,
# c.example.com added.
psl_diff(old, new)

# Agreeing snapshots return the same columns with zero rows.
psl_diff("bundled", "bundled")

# Provenance travels with the result when the input form carries it.
attr(psl_diff("bundled", old), "old_version")$checksum

Construct a self-contained PSL engine

Description

Builds a process-local Public Suffix List engine bound to a specific snapshot, without switching the session-global active list that psl_use() controls.

Usage

psl_engine(source = "bundled", path = NULL)

## S3 method for class 'psl_snapshot'
print(x, ...)

## S3 method for class 'psl_engine'
print(x, ...)

Arguments

source

Where to load the list from: "bundled" (the pinned package snapshot) or "path" (a custom file).

path

For source = "path", a single readable PSL-format UTF-8 file containing one complete ICANN section and one complete PRIVATE section, using official markers. Must be NULL for any other source.

Details

The engine is process-local: its compiled matcher is a C++ external pointer that does not serialize across R sessions or parallel workers. Saving and reloading an engine, or sending one to a worker, does not carry the matcher. To persist an engine, serialize its snapshot descriptor and rebuild the engine from it in the target process.

Value

An engine object that the query functions can be pointed at (via their ⁠engine=⁠ argument) to resolve hosts against the chosen snapshot in isolation from the session-global list.

See Also

psl_use(), psl_version()

Examples

engine <- psl_engine("bundled")
engine

# A custom list from a file, entirely offline.
dat <- tempfile(fileext = ".dat")
writeLines(
  c(
    "// ===BEGIN ICANN DOMAINS===",
    "com",
    "// ===END ICANN DOMAINS===",
    "// ===BEGIN PRIVATE DOMAINS===",
    "example.com",
    "// ===END PRIVATE DOMAINS==="
  ),
  dat
)
psl_engine("path", path = dat)

Refresh the cached Public Suffix List from upstream

Description

Revalidates the Public Suffix List against its source and publishes any changed bytes into the user cache. This is the only function in the package that accesses the network, and only when you call it explicitly.

Usage

psl_refresh(
  url = "https://publicsuffix.org/list/public_suffix_list.dat",
  ...,
  activate = FALSE,
  force = FALSE
)

Arguments

url

Absolute https URL of the list source. Defaults to the official list. URLs with another scheme, embedded credentials, a query string, or a fragment are rejected, and a redirect that leaves https or the original origin is refused.

...

These dots are for future extensions and must be empty. They also make activate and force named-only. The two flags are easy to confuse – both logical, both about doing more than a bare check – so psl_refresh(url, TRUE) is unreadable whichever order it means. Naming them makes every call self-documenting, and the old positional form is now a clear error instead of a silent change of meaning.

activate

When TRUE, the snapshot the source now points at becomes the active list for the session, exactly as psl_use() would activate it – after every successful outcome, including a skip and a 304. When FALSE (default), the cache is updated but the active list is unchanged.

force

When FALSE (default), a check whose courtesy window has not elapsed makes no request at all, respecting upstream download guidance. TRUE bypasses that local window only; the request it then makes still carries a validator when one is available.

Details

A refresh has exactly four successful outcomes:

skipped_recently

No request: the last successful check is still inside its courtesy window (at least 24 hours).

not_modified

One conditional request answered 304; the local bytes were verified and remain current.

downloaded_unchanged

One 200 whose validated bytes hash to the snapshot already held, so no new snapshot is created.

updated

One 200 whose validated bytes are a new snapshot.

Downloaded bytes are fully validated – size ceiling, UTF-8, official section markers, rule grammar, and canonicalization of every rule – before anything references them, and exact same-section duplicates warn once and are deduplicated. Publication is append-only: snapshot bytes and their descriptor are written before any reference to them, so an interrupted refresh never exposes a dangling reference. Refreshes of one source are serialized across processes; a second concurrent refresh of the same source makes no request and signals a busy error. A failed refresh records only a coarse attempt and leaves the cache, the selected snapshot, and the active matcher untouched.

Value

Invisibly, a psl_refresh_result with stable fields outcome, request_url, effective_url, http_status, checked_at, previous_checksum, checksum, activated, validator, bytes_downloaded, and snapshot. Operational failures signal a classed error rooted at pslr_refresh_error instead.

See Also

psl_use(), psl_version()

Examples

if (interactive()) {
  psl_refresh()
  psl_refresh(force = TRUE, activate = TRUE)
}

Persistent opt-in freshness reminder

Description

Queries or sets whether attaching pslr with library(pslr) may print one offline freshness reminder per R session, and how many days of unconfirmed freshness it takes before that reminder applies.

Usage

psl_reminder(enable = NULL, every = NULL)

## S3 method for class 'psl_reminder'
format(x, ...)

## S3 method for class 'psl_reminder'
print(x, ...)

Arguments

enable

Whether attach reminders are on: TRUE to enable, FALSE to disable, or NULL (the default) to report the current preference without writing anything.

every

The reminder interval in whole days, at least one. NULL (the default) reuses the stored interval, or 7 days when no preference has been stored yet. Only meaningful together with enable.

x

A psl_reminder preference, as returned by psl_reminder().

...

Passed on to the data frame methods when x no longer carries the full preference contract.

Details

Reminders are off until you turn them on. The preference is configuration rather than cache: it is stored under tools::R_user_dir()⁠("pslr", "config")⁠, so refreshing, pruning, or deleting the snapshot cache never changes it. Disabling retains the interval, so a later psl_reminder(enable = TRUE) restores the schedule you chose.

Querying, enabling, and disabling are all strictly offline; no part of the reminder path makes a network request.

When reminders are enabled, a direct library(pslr) attachment evaluates psl_status() offline and may emit a single packageStartupMessage(). A package that merely imports the namespace, as in pslr::public_suffix(), never triggers it, suppressPackageStartupMessages() suppresses it as usual, and it is emitted at most once per session – detaching and reattaching does not repeat it.

The message appears only for the three states where local evidence supports advice: "never_checked", "check_due", and "update_available". For "update_available" the newer snapshot is already stored locally, so the message suggests activating it with psl_use("cache") rather than fetching anything again. Any failure while evaluating the reminder – damaged cache state included – degrades to silence, so attaching the package cannot break.

Value

A one-row base data.frame of class psl_reminder with the columns enabled (logical), interval (integer days), and stored (logical, whether the value came from a stored preference rather than the defaults). Returned visibly when querying and invisibly when writing.

format() returns a character vector of display lines and print() returns x invisibly.

See Also

psl_status(), psl_refresh(), psl_use()

Examples

# Query the current preference; this writes nothing.
psl_reminder()

# Enabling writes to your config directory, so this example points that
# seam at a temporary directory instead.
old <- options(pslr.config_dir = file.path(tempdir(), "pslr-reminder"))

psl_reminder(enable = TRUE, every = 14)
psl_reminder()

# Disabling retains the interval for a later re-enable.
psl_reminder(enable = FALSE)$interval

options(old)

Rules of the active Public Suffix List

Description

Returns the explicit rules of the active list as a base data.frame, one row per rule. The implicit default * rule is not included.

Usage

psl_rules(section = "all")

Arguments

section

Which rule sections to return: "all" (default), "icann", or "private".

Value

A base data.frame with columns, in order: rule (original source rule text), canonical_rule (the canonicalized rule, including the ⁠*.⁠ or ! marker), kind ("normal", "wildcard", or "exception"), section ("icann" or "private"), and labels (integer rule depth, counting a wildcard label). Rows are ordered first by section (ICANN before PRIVATE) and then by source-file order.

See Also

psl_version(), public_suffix_rule(), psl_diff()

Examples

head(psl_rules("icann"))
nrow(psl_rules("private"))

Inventory of the locally available Public Suffix List snapshots

Description

Lists every set of Public Suffix List bytes this installation can resolve: the snapshot installed with the package plus every snapshot published into the user cache. There is exactly one row per distinct SHA-256 checksum, so bytes stored in more than one place collapse into a single row with one preferred path.

Usage

psl_snapshots(..., verify = FALSE)

## S3 method for class 'psl_snapshots'
format(x, ...)

## S3 method for class 'psl_snapshots'
print(x, ...)

Arguments

...

These dots are for future extension and must be empty.

verify

Whether to rehash every snapshot's bytes to detect corruption that preserves the byte count. FALSE (the default) classifies rows from metadata alone; TRUE reads every stored snapshot in full.

x

A psl_snapshots inventory, as returned by psl_snapshots().

Details

The call is strictly offline and read-only. It makes no request, writes nothing, repairs nothing, and performs no cache migration; a snapshot whose local storage is damaged is reported through integrity rather than raised as an error.

integrity is one of:

ok

Bytes and a readable descriptor are both present and agree.

missing

The bytes or the descriptor are not stored, which is also what a reference to an already pruned snapshot reports.

checksum_mismatch

The stored bytes cannot be the bytes the checksum names.

unknown_schema

The descriptor is unreadable, or was written by a release whose schema this one does not support.

Descriptors are checked structurally; no list is reparsed, so an ordinary call is cheap enough to make casually. By default checksum_mismatch is derived from metadata alone – a stored file whose size differs from the size its descriptor recorded cannot hold the bytes the checksum names. That misses corruption that preserves the byte count; verify = TRUE rehashes every snapshot's bytes and catches it, at the cost of reading every stored file in full.

Request URLs of custom sources may be private, so association with sources is reported only as the count source_count. The inventory never returns a source URL; origin_url is immutable provenance recorded in the snapshot's own descriptor.

Value

A base data.frame of class psl_snapshots, one row per distinct checksum, ordered by checksum, with the columns, in order: checksum (character, the "sha256:<hex>" identity), path (character, the preferred storage location, NA when the bytes are not stored), size (integer bytes), content_date (POSIXct upstream provenance date), first_retrieved_at (POSIXct, when these bytes were first received), origin_url (character immutable origin recorded at publication), first_normalization_profile (character, the normalization profile in use when these bytes were first published to the preferred location; it is first-publication provenance, not the profile this session queries under – for that, see psl_version()), bundled (logical, installed with the package), selected_cache (logical, the snapshot psl_use("cache") would resolve to), active (logical, the snapshot active in this session), current_for_any_source (logical, named by at least one source's current record), source_count (integer number of sources associated with these bytes), and integrity (character, see Details). Unavailable values are a typed NA. The bundled snapshot is always inventoried, so the result is never empty on a working installation.

format() returns a character vector of display lines and print() returns x invisibly.

See Also

psl_status(), psl_refresh(), psl_diff(), psl_cache_prune()

Examples

# Every snapshot this installation can resolve, without any network access:
snapshots <- psl_snapshots()
snapshots[c("checksum", "bundled", "size", "integrity")]

# The snapshot installed with the package is always inventoried:
snapshots[snapshots$bundled, ]$integrity

# Rehash every stored snapshot instead of trusting recorded sizes:
psl_snapshots(verify = TRUE)$integrity

Offline freshness status of a Public Suffix List snapshot

Description

Reports the strongest freshness claim the locally available evidence supports about one snapshot: whether it is confirmed current against its source, whether a check is merely due, whether a newer snapshot has actually been observed, or whether the local state cannot support any claim at all.

Usage

psl_status(snapshot = "active", ..., now = psl_now())

## S3 method for class 'psl_status'
format(x, ...)

## S3 method for class 'psl_status'
print(x, ...)

Arguments

snapshot

Which snapshot to inspect: "active" (the list active in this session), "cache" (the snapshot psl_use("cache") would resolve to), or "bundled" (the snapshot installed with the package).

...

These dots are for future extension and must be empty.

now

The instant to evaluate freshness against, as a single POSIXct time. Defaults to the current time, read once per call. Mainly useful for testing.

x

A psl_status row, as returned by psl_status().

Details

The call is strictly offline and read-only. It makes no request, writes nothing, and performs no cache migration; unreadable local state is reported as "unknown" with remediation rather than raised as an error, so a usable active list always stays inspectable.

state is one of, in precedence order:

missing

The requested cache selection does not exist.

unknown

Required local state is corrupt, ambiguous, or affected by clock skew; message carries the remediation.

untracked

The snapshot has no applicable remote source, so no freshness claim can be made about it.

update_available

A successful earlier check observed a different checksum for the source. This is an observation, never an inference from age.

never_checked

The source is known but nothing has ever confirmed the snapshot against it.

check_due

The snapshot was confirmed current, but the retained reminder interval (7 days by default) has since elapsed. This is offline advice, not evidence that anything upstream changed.

confirmed_current

The snapshot was confirmed current and the interval has not elapsed.

Elapsed time alone never produces "update_available": an interval that has passed is "check_due" and nothing more.

Value

A one-row base data.frame of class psl_status with the columns, in order: state (character), snapshot (character, the requested selector), source_kind (character: "bundled", "cache", "path", or "missing"), request_url (character), checksum (character, the inspected snapshot's identity), source_checksum (character, the newest checksum observed for the source), content_date (POSIXct upstream provenance date), retrieved_at (POSIXct), checked_at (POSIXct), next_check_at (POSIXct courtesy boundary), snapshot_age_days (double), check_age_days (double), check_due (logical), and message (character remediation for "missing" and "unknown"). Unavailable values are a typed NA; ages are NA when the local clock is behind a recorded time.

format() returns a character vector of display lines and print() returns x invisibly.

See Also

psl_refresh(), psl_use(), psl_version()

Examples

# The snapshot installed with the package:
psl_status("bundled")

# The list active in this session:
psl_status()

# A cache that was never populated is a status, not an error:
psl_status("cache")$state

Choose the active Public Suffix List for this session

Description

Switches the list backing every query in the current R session. The change is session-only and is validated before any session state changes; a failure leaves the previously active list usable. A successful switch invalidates the match-result cache.

Usage

psl_use(source = "bundled", path = NULL)

Arguments

source

Where to load the list from: "bundled" (the pinned package snapshot), "cache" (the latest successfully validated snapshot from psl_refresh()), or "path" (a custom file).

path

For source = "path", a single readable PSL-format UTF-8 file containing one complete ICANN section and one complete PRIVATE section, using official markers. Must be NULL for any other source.

Details

A custom path is held to the same runtime duplicate policy as psl_refresh(): exact same-section duplicates warn once and are deduplicated, while conflicting rule kinds for the same labels are fatal. Cache and custom-path sources are read in source form and indexed under the runtime normalizer; they never reuse the bundled generated index.

Value

Invisibly, the psl_version() row for the newly active list.

See Also

psl_refresh(), psl_version(), psl_rules()

Examples

psl_use("bundled")
if (interactive()) {
  psl_use("cache")
  psl_use("path", path = "my_list.dat")
}

Identity of the active Public Suffix List

Description

Returns a one-row data.frame describing the list currently active in this R session: its source-snapshot provenance and the normalization identifiers actually used to index the active matcher. Reproducing a query result requires both the active-list identity and these normalization identifiers (PRD s10), so a reproducibility-sensitive workflow should record this row.

Usage

psl_version()

Details

The columns, in order, are:

source

"bundled", "cache", or "path".

url

Source URL of the active snapshot: the upstream download URL for the bundled list; NA for a "cache" or "path" source.

path

File path of a "cache" or "path" source; NA otherwise.

retrieved_at

Network retrieval timestamp, or NA.

list_date

Upstream list date, or NA when unknown.

commit

Upstream commit SHA, or NA when unknown.

size

Source byte size (integer).

checksum

Source checksum, including its algorithm prefix (e.g. "sha256:...").

normalizer

The dependency providing canonicalization, currently "punycoder".

normalizer_version

Its installed package version.

normalization_profile

Its stable case-mapping / IDNA / validation profile identifier.

unicode_version

The Unicode data version used by that profile.

Unavailable metadata is a typed NA, never omitted. The normalization identifiers describe the implementation used by the current session, whether the active list came from the bundled snapshot, the user cache, or a custom path; an in-memory compatibility rebuild (PRD s8.3) updates them without altering the shipped source identity or checksum.

Value

A one-row base data.frame with the columns described in Details.

See Also

psl_use(), psl_refresh(), psl_rules()

Examples

psl_version()

Public suffix of a host

Description

Returns the public suffix (effective top-level domain, eTLD) of each host under the selected Public Suffix List policy, following the official prevailing-rule algorithm.

Usage

public_suffix(
  domain,
  section = "all",
  output = "ascii",
  unknown = "default",
  invalid = "na",
  engine = psl_default_engine()
)

Arguments

domain

Character vector of DNS hostnames (not URLs). Each element may be a mixed-case ASCII, Unicode, or A-label hostname, a single label, or a hostname with exactly one terminal root dot. See Input contract.

section

Which rule sections are eligible: "all" (default; ICANN and PRIVATE), "icann", or "private". Section filtering happens before prevailing-rule selection, so "private" does not silently add ICANN rules; a host matching no rule in the section falls through to the implicit default rule unless unknown = "na".

output

"ascii" (default) returns lowercase A-labels; "unicode" decodes them after matching. A terminal root dot is preserved either way.

unknown

"default" (default) applies the spec's implicit * rule, so an unlisted single label is its own public suffix; "na" returns NA when no explicit rule in the selected section matches.

invalid

"na" (default) returns NA for each invalid element without a warning; "error" aborts on the first invalid element, reporting its 1-based index.

engine

The psl_engine to query against; defaults to the session-global engine selected by psl_use(), so most callers never set it. Pass an engine from psl_engine() to resolve hosts against a specific snapshot in isolation.

Value

A character vector with length(domain), preserving the names of domain. Other attributes are dropped.

Input contract

NA is treated as missing (returns NA), not invalid. Invalid elements include empty or whitespace-only strings, leading or consecutive dots, URL syntax, IPv6 addresses, canonical dotted-decimal IPv4 literals, and labels that fail hostname/IDNA validation. Wrong argument types and non-scalar or unknown option values always abort regardless of invalid.

See Also

registrable_domain(), is_public_suffix(), suffix_extract(), public_suffix_rule()

Examples

public_suffix("www.example.com")
public_suffix("example.co.uk")
public_suffix("example.com.")
public_suffix("madeuptld", unknown = "na")

Inspect the prevailing PSL rule for each host

Description

Inspect the prevailing PSL rule for each host

Usage

public_suffix_rule(
  domain,
  section = "all",
  unknown = "default",
  invalid = "na",
  engine = psl_default_engine()
)

Arguments

domain

Character vector of DNS hostnames (not URLs). Each element may be a mixed-case ASCII, Unicode, or A-label hostname, a single label, or a hostname with exactly one terminal root dot. See Input contract.

section

Which rule sections are eligible: "all" (default; ICANN and PRIVATE), "icann", or "private". Section filtering happens before prevailing-rule selection, so "private" does not silently add ICANN rules; a host matching no rule in the section falls through to the implicit default rule unless unknown = "na".

unknown

"default" (default) applies the spec's implicit * rule, so an unlisted single label is its own public suffix; "na" returns NA when no explicit rule in the selected section matches.

invalid

"na" (default) returns NA for each invalid element without a warning; "error" aborts on the first invalid element, reporting its 1-based index.

engine

The psl_engine to query against; defaults to the session-global engine selected by psl_use(), so most callers never set it. Pass an engine from psl_engine() to resolve hosts against a specific snapshot in isolation.

Value

A base data.frame with one row per input and columns, in order: input (original), host_ascii (canonical A-label host), rule (the canonical rule including ⁠*.⁠ or !, "*" for the implicit default), kind ("normal", "wildcard", "exception", or "default"), rule_section ("icann", "private", or NA for the default/no result), and public_suffix_ascii (the derived A-label public suffix). Invalid rows are NA in every derived column. A valid host left unresolved by unknown = "na" keeps host_ascii while the rule and suffix columns are NA. An exception rule retains its ! for auditability. Zero-length input returns a zero-row frame; all-invalid input keeps one row per input.

Input contract

NA is treated as missing (returns NA), not invalid. Invalid elements include empty or whitespace-only strings, leading or consecutive dots, URL syntax, IPv6 addresses, canonical dotted-decimal IPv4 literals, and labels that fail hostname/IDNA validation. Wrong argument types and non-scalar or unknown option values always abort regardless of invalid.

See Also

public_suffix(), suffix_extract()

Examples

public_suffix_rule("www.example.co.uk")
public_suffix_rule("madeuptld")

Registrable domain of a host

Description

Returns the registrable domain (eTLD+1) of each host: its public suffix plus one host label to the left. It is NA when no such label exists (the host is itself a public suffix) or when the public suffix is NA.

Usage

registrable_domain(
  domain,
  section = "all",
  output = "ascii",
  unknown = "default",
  invalid = "na",
  engine = psl_default_engine()
)

Arguments

domain

Character vector of DNS hostnames (not URLs). Each element may be a mixed-case ASCII, Unicode, or A-label hostname, a single label, or a hostname with exactly one terminal root dot. See Input contract.

section

Which rule sections are eligible: "all" (default; ICANN and PRIVATE), "icann", or "private". Section filtering happens before prevailing-rule selection, so "private" does not silently add ICANN rules; a host matching no rule in the section falls through to the implicit default rule unless unknown = "na".

output

"ascii" (default) returns lowercase A-labels; "unicode" decodes them after matching. A terminal root dot is preserved either way.

unknown

"default" (default) applies the spec's implicit * rule, so an unlisted single label is its own public suffix; "na" returns NA when no explicit rule in the selected section matches.

invalid

"na" (default) returns NA for each invalid element without a warning; "error" aborts on the first invalid element, reporting its 1-based index.

engine

The psl_engine to query against; defaults to the session-global engine selected by psl_use(), so most callers never set it. Pass an engine from psl_engine() to resolve hosts against a specific snapshot in isolation.

Value

A character vector with length(domain), preserving the names of domain. Other attributes are dropped.

Input contract

NA is treated as missing (returns NA), not invalid. Invalid elements include empty or whitespace-only strings, leading or consecutive dots, URL syntax, IPv6 addresses, canonical dotted-decimal IPv4 literals, and labels that fail hostname/IDNA validation. Wrong argument types and non-scalar or unknown option values always abort regardless of invalid.

See Also

public_suffix(), is_public_suffix(), suffix_extract()

Examples

registrable_domain("www.example.co.uk")
registrable_domain("com")
registrable_domain("foo.madeuptld", unknown = "na")

Split hosts into subdomain, registrant label, and public suffix

Description

Split hosts into subdomain, registrant label, and public suffix

Usage

suffix_extract(
  domain,
  section = "all",
  output = "ascii",
  unknown = "default",
  invalid = "na",
  engine = psl_default_engine()
)

Arguments

domain

Character vector of DNS hostnames (not URLs). Each element may be a mixed-case ASCII, Unicode, or A-label hostname, a single label, or a hostname with exactly one terminal root dot. See Input contract.

section

Which rule sections are eligible: "all" (default; ICANN and PRIVATE), "icann", or "private". Section filtering happens before prevailing-rule selection, so "private" does not silently add ICANN rules; a host matching no rule in the section falls through to the implicit default rule unless unknown = "na".

output

"ascii" (default) returns lowercase A-labels; "unicode" decodes them after matching. A terminal root dot is preserved either way.

unknown

"default" (default) applies the spec's implicit * rule, so an unlisted single label is its own public suffix; "na" returns NA when no explicit rule in the selected section matches.

invalid

"na" (default) returns NA for each invalid element without a warning; "error" aborts on the first invalid element, reporting its 1-based index.

engine

The psl_engine to query against; defaults to the session-global engine selected by psl_use(), so most callers never set it. Pass an engine from psl_engine() to resolve hosts against a specific snapshot in isolation.

Value

A base data.frame with one row per input and columns, in order: input (original, unchanged), host (canonical host in output form), subdomain (labels left of the registrable domain; "" when none), domain (the single registrant label left of the suffix), suffix (the public suffix), and registrable_domain (eTLD+1). domain, subdomain, and registrable_domain are NA when the host is itself a public suffix. If public-suffix resolution is NA, every derived column except input and a successfully normalized host is NA. Zero-length input returns a zero-row frame; all-invalid input keeps one row per input. Root dots are preserved on host, suffix, and registrable_domain only.

Input contract

NA is treated as missing (returns NA), not invalid. Invalid elements include empty or whitespace-only strings, leading or consecutive dots, URL syntax, IPv6 addresses, canonical dotted-decimal IPv4 literals, and labels that fail hostname/IDNA validation. Wrong argument types and non-scalar or unknown option values always abort regardless of invalid.

See Also

public_suffix(), public_suffix_rule()

Examples

suffix_extract("www.example.co.uk")
suffix_extract(c("example.com", "com", NA))