rules

package
v0.41.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 7, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

README

internal/publisher/rules

The pure rules that a publisher's own OVDB manifest is held to. This package is the base of ovdb publisher check, the command that checks what a publisher keeps in their repository (see the README of the module); the ovdb binary links it.

"Pure" means no file, no network, no clock and no YAML: strings in, a verdict out. Reading the manifest, the repository and the Directory's records comes in later changes and calls these functions.

The rules

Function Accepts
PublicHTTPSURL https://host/path and nothing else: no userinfo, port (not even :443), query, fragment or percent escape; a lower-case host of letters, digits and hyphens in dot-separated labels (1 to 63 bytes, none starting or ending with a hyphen, at least two labels, at most 253 bytes in all, no trailing dot); no IP address or name that could be read as one (a last label of digits, or 0x and hex digits), no single-label name, no local, internal or reserved suffix; a path of only A-Z a-z 0-9 . _ ~ / -, starting with /, with no // and no . or .. segment; one canonical spelling.
PublicHTTPSURLTemplate The same, with the literal {name} exactly once, in the path only.
Homepage PublicHTTPSURL and at most 200 bytes.
IsID ^[a-z0-9]+(-[a-z0-9]+)*$, at most 80 bytes.
IsCommit 40 lower-case hex digits.
RepositoryKey, CompareKey https://github.com/{org}/{repo}: an allow-listed host (today only github.com) with exactly its number of path segments (2), each of A-Z a-z 0-9 . _ -, none of them . or .., the last not ending in .git in any case, no trailing slash. The key is host/org/repo as written; CompareKey is its lower case, the key to compare two repositories by.
IsRepositoryPath A path to a file in a repository: relative, only A-Z a-z 0-9 . _ / - (so no backslash, glob or space), no //, no . or .. segment, no trailing /.
IsPublishEntry An entry of an OVDB.md publish list: the explicit form ./ followed by an IsRepositoryPath.
IsLocalID The localId of a database descriptor, ^[a-z][a-z0-9-]{0,39}$ (the Directory's localIdPattern): unlike IsID it allows a hyphen at the end and two in a row.
IsEngine ^[A-Za-z][A-Za-z0-9_.+-]{0,39}$.
IsLicenceID The shape of an SPDX licence id, ^[A-Za-z0-9][A-Za-z0-9.+-]{0,63}$; it does not know which ids SPDX has assigned.
IsBlank Whether a text is empty or only white space as JavaScript's trim() sees it (it strips U+FEFF and not U+0085; Go's strings.TrimSpace does the reverse). Every "is required" check must use it, never strings.TrimSpace.
GlobalDatabaseID A database's canonical url as the Directory takes it since it published global identities: every rule of PublicHTTPSURL (a trailing slash is fine; one path segment or several), and two differences. A path segment may hold percent escapes when it is the canonical encoding of its text (see EncodePathSegment) and the text, decoded again and again, never becomes ., .., a slash, a backslash or a control character; and a host under .example is allowed.
RecordsetName A recordset name as the Directory takes it since it took native names: text that is not blank by JavaScript's trim(), at most 256 UTF-16 code units (an astral character counts for two), not . or .., with no /, \ or control character (U+0000 to U+001F, U+007F). A space, a dot and any non-ASCII letter are allowed: dbo.DatabaseLog, Order Details.
EncodePathSegment JavaScript's encodeURIComponent, with ! ' ( ) * encoded too: everything except A-Z a-z 0-9 - _ . ~ as %XX, in upper case.
RecordsetPage The page of a recordset: the deployment.recordset_page template with {name} replaced by the encoded name. A name that needs no encoding makes an ordinary public https URL. One that does is accepted only as one whole path segment of the template's path (nothing else shares it), when nothing in the name, decoded again and again, can become ., .., a slash, a backslash or a control character, and the rest of the URL passes the ordinary rules. The page has no length bound of its own, as the Directory has none: the name is bounded (256 UTF-16 code units, 2304 characters at most once encoded) and the template is a URL of at most 2048, so a page is judged in one pass however long.
Compare, ClaimedForm How one claimed address stands to another: Same when they are equal, Under when the first sits under the second at a path-segment boundary (/dbs/chinook2 is not under /dbs/chinook), Over when the second sits under the first, Apart otherwise, all case-insensitively with trailing slashes set aside. A caller asks Relation.Conflicts() (true for everything but Apart, and for Incomparable, which is also the zero value), and never compares with Same or Under itself.

A refused URL comes back as a *Problem with a stable Rule (match on that, never on the message) and a detail in words. ParsePublicHTTPSURL and ParsePublicHTTPSURLTemplate also return the parts of an accepted URL (Host, Path, and for a template the offset of {name} in the path), so a rule that looks at the host or the path never splits the text again. A piece of the input reaches a message only through one function that cuts it to 40 bytes, quotes it and escapes it to printable ASCII, so no message holds a control character or a line break (a forged log line); a test holds every refusal of the matrix to that.

Limits on input

Every function bounds its input before it reads it, then reads it once, left to right. An input over the bound is refused (Compare says Incomparable, which a caller looking for conflicts must treat as one).

Bound Bytes Where it comes from
MaxHostLength, MaxLabelLength 253, 63 the references
MaxHomepageLength 200 the references
MaxIDLength 80 the references
MaxEngineLength, MaxLicenceLength 40, 64 the references' patterns
MaxURLLength 2048 this package; the references have no bound
MaxPathLength 1024 this package; the references have no bound
MaxRepositoryLength 255 this package; the references have no bound
MaxClaimLength 2048 this package

Why the URL rules are written on the text

The URL functions are a hand-written reader of the plain subset above. They do not give the string to net/url and inspect the result, because Go's parser and the WHATWG parser that JavaScript has disagree on hosts whose last label is numeric, on punycode, on backslashes and on control characters. The rule here is that a Go function never accepts a string that the JavaScript refuses. net/url is used in the tests, as a judge: the fuzz targets check that what is accepted, parsed again by it, has scheme https, no user, no port, no query and no fragment.

The references and the proof that Go never accepts more

The rules are those of the OVDB Directory, and of the Chinook database's port of them (both in JavaScript, which is where a publisher's check meets them today):

Reference Repository Commit Files
directory openvaultdb/directory (CC0-1.0) 087067483686865b13cb76511ff86f7364ea47ff scripts/lib/urls.mjs, git.mjs, directory.mjs
chinookdb demo-db/chinook (MIT) 8b904298d0c3bba20c12dfbc29bb75bf5c37f683 scripts/lib/directory-rules.mjs

testdata/reference/generate.mjs fetches those files at exactly those commits, imports them as they are, runs their functions over a generated matrix and writes the verdicts to testdata/reference/matrix.golden.json (Node v24.19.0 made the committed one). go test reads the golden and judges every verdict of the Go functions against it; it starts no process and needs no network. The matrix is 2599599 verdicts:

  • every character U+0000 to U+FFFF, placed in the host (first, middle, last, last label), after the host, in the path, before the scheme and after the end of a valid URL, for URLs, templates and homepages, and in the middle, first and last position of ids, repositories, paths, publish entries, engines and licences (the smaller rules sweep U+0000 to U+024F and the surrogate and full-width edges);
  • every string of a small alphabet up to a length, for the shapes that have structure: hosts ending in numeric, hex-looking and odd last labels, xn-- labels, path shapes, ids, repositories, engines, licences;
  • every string literal written as a URL in the two JavaScript test suites (openvaultdb/directory scripts/test.mjs, datatug/chinookdb scripts/test-model.mjs), and hand-written cases: ports, userinfo, %2F, //, dot segments, trailing dots, upper-case hosts, numeric last labels, punycode labels spelled by Node's own encoder, reserved suffixes, templates, and the length of every limit and one over;
  • every character U+0000 to U+FFFF alone, led, trailed and between spaces, for the blank-text check, and every white-space and format character in a list;
  • xn-- labels whose decoded text begins with xn-- or has hyphens in its third and fourth positions, with every Latin-1 letter;
  • every pair of a list of claimed addresses, for Compare (apart, same, under and over, as the Directory's own claim check reports them in each direction).

TestReferenceMatrix fails if any Go function accepts where a reference refuses, if a Go function is stricter in a way that is not recorded below, or if a recorded difference never happens in the matrix. go test -v -run TestReferenceMatrix ./internal/publisher/rules prints the counts.

Recorded differences: where Go is stricter

Go may refuse what the JavaScript accepts. Each kind is recorded here with its number of cases in the matrix, and a test proves it is real and nothing else: with the one limit named taken away, Go accepts the same input.

Kind Cases Why
url-length 11 A URL over 2048 bytes. The references have no bound; a published URL is text that people and tools read, and an unbounded input is a way to make a check slow.
punycode-decoded-hyphens 376 An xn-- label that is valid punycode of Latin-1 letters but decodes to text that begins with xn-- or has hyphens in its third and fourth positions. As UTS #46 reads it (15.1 on), such a label is invalid when hyphens are not checked, so a later Node may refuse it; Node v24.19.0 accepts it. One comparison makes the rule independent of the Node version.
punycode-other-text 3442 An xn-- label that is valid punycode of text other than Latin-1 lower-case letters (Cyrillic, CJK, control characters, ...). Which code points UTS #46 accepts changes with every Unicode release and Go has no copy of its tables, so a label is accepted only when it spells Latin-1 letters (U+00E0 to U+00FF without U+00F7), which have always been valid. xn--bcher-kva.de passes; xn--80ak6aa92e.com does not, though Node accepts it. The message says which letters a label may spell, that other scripts and letters are not accepted yet, and to use an ASCII host name; whether to accept more is a product decision.
punycode-malformed 50 An xn-- label that is not punycode of any text (truncated, ASCII only, a number too large). Node's URL parser takes such labels as written; a hostile publisher could use one to name a host no client can resolve the same way. The message says it is not valid punycode and to write the host name in ASCII.
repository-length 4 A repository URL over 255 bytes. The references have no bound; GitHub names are far shorter.
path-length 3 A path inside a repository over 1024 bytes. The references have no bound.
claim-incomparable 640 Compare of an address that is not ASCII or is over 2048 bytes. JavaScript folds case by Unicode rules (U+212A KELVIN SIGN lowers to k), which this package does not copy; addresses that reach a comparison have already passed PublicHTTPSURL, so this never happens to a valid one, and Incomparable.Conflicts() is true.

The references agree with each other on every verdict of the matrix: where the Chinook port has drifted from the Directory it is in message text only.

Regenerating the golden

Only when a reference changes (a new pinned commit) or the matrix does:

node internal/publisher/rules/testdata/reference/generate.mjs           # rewrite the golden
node internal/publisher/rules/testdata/reference/generate.mjs --check   # fail if it is stale

Needs Node 24 or later, git, npm and network access. The two commits are pinned in internal/publisher/references.mjs (which reference_test.go reads, and fails if the golden was made from other ones); to use clones you already have, pass `--directory

` and `--chinookdb `, which must be at those commits. The golden is kept small by storing, for the exhaustive families, only the accepted characters or strings (or the refused ones, when fewer). The test also fails when this README states another size, count, commit or Node version than the golden. The generator also asserts that the two rules the Directory keeps inline (the `isText` test and the publish-entry expression) are still in `directory.mjs` at the pinned commit as copied, and says to run `npm ci` in a `--directory` clone that has no `yaml`.

Fuzzing

go test -run '^$' -fuzz FuzzPublicHTTPSURL -fuzztime 60s ./internal/publisher/rules
go test -run '^$' -fuzz FuzzRepositoryKey  -fuzztime 60s ./internal/publisher/rules
go test -run '^$' -fuzz FuzzRepositoryPath -fuzztime 60s ./internal/publisher/rules

They assert no panic and the guarantees above (for a URL, re-parsed by net/url: scheme https, no user, no port, no query, no fragment, and the same text back). Under plain go test they run only their seed inputs.

Exact coverage

The packages of the publisher check are held to exactly 100% statement coverage by a gate scoped to them, cmd/covergate (the exact gate of modelspec-org/cli and meaninggraph/cli, cut down to a list of packages). The module as a whole cannot be gated this way: some of its packages have a TestMain, and some have files for one operating system, and the gate refuses both. The list is in .github/workflows/ci.yml (job publisher-coverage), and a test keeps it equal to every package below internal/publisher, internal/covergate and cmd/covergate.

The gate also refuses whatever lets the build leave a file out of the profile: a build constraint in any spelling that Go reads (//go:build, // +build, //+build, extra spaces or a tab, judged by go/build/constraint on the header before the package clause), a GOOS or GOARCH file name, and import "C" (left out when cgo is off). It refuses //line and /*line*/ directives in any file (found with the scanner's comments, so the same text in a string is not one): the profile names a block by the file a directive gives and the physical line and column, so a block that never ran could take the location of a covered one of another file and be merged into it as covered. A profile with the same location listed with two statement counts is refused. And it closes the class by a file-set rule: every non-test file of a gated package that has a statement must have a block in the profile, so a file left out for any other reason fails the gate by name. To run it locally:

go test -covermode=atomic -coverprofile=/tmp/cover.out ./internal/publisher/... ./internal/covergate/... ./cmd/covergate/...
go run ./cmd/covergate /tmp/cover.out ./internal/publisher/exitcode ./internal/publisher/rules ./internal/covergate ./cmd/covergate

Not part of the parity matrix

ovdb publisher check is not a CLI, TUI, web and API feature of a running database, so it stays outside internal/parity.

Decision: internationalised host names (2026-10-04)

Internationalised host names are refused for now: a host is accepted only when it is ASCII, or spells Latin-1 letters through xn-- (what the matrix above shows rules accepts, and nothing more). The Unicode tables that UTS #46 needs change with every release and Go has no copy; until there is a reason to carry them, a publisher writes the ASCII host name. Accepting more is a product decision, and the kinds punycode-other-text and punycode-malformed are its record.

Current canonical checker references: Directory 087067483686865b13cb76511ff86f7364ea47ff and demo-db/chinook 8b904298d0c3bba20c12dfbc29bb75bf5c37f683. The prior exact datatug/chinookdb 79e7bb0b1d6f0666dce465874990dec64348331f supplies only frozen corpus documents and mined literal inputs; its code is not imported as a reference validator.

Documentation

Overview

Package rules holds the pure rules that a publisher's OVDB manifest is held to: what a published URL, a homepage, a database id, a commit, a repository, a path inside a repository, an engine name and a licence id may look like, and how two claimed addresses compare.

The rules are the OVDB Directory's (github.com/openvaultdb/directory, scripts/lib/urls.mjs, git.mjs and directory.mjs, CC0-1.0) as the Chinook database's own pre-check ports them (github.com/datatug/chinookdb, scripts/lib/directory-rules.mjs, MIT). Both are JavaScript. The rule of this package is that a function here never accepts a string either of them refuses; it may refuse more, and every way it does is recorded in README.md and proved by the reference matrix (see the tests).

Every function is pure: no file, no network, no clock, no YAML. Every function bounds its input first (see the Max constants) and then reads it once, left to right. The URL rules are written on the text, as a reader of a plain subset, and never hand the string to net/url: Go's parser and the WHATWG parser that the JavaScript relies on disagree on hosts whose last label is numeric, on punycode, on backslashes and on control characters.

Two traps for the code that uses this package. A text field is "required" when it is not blank by JavaScript's trim(), which is not Go's strings.TrimSpace (it strips U+FEFF and not U+0085, Go the reverse): use IsBlank, never strings.TrimSpace, for those checks. And claims conflict when Relation.Conflicts says so; never compare a Relation with Same or Under by hand, because an address that cannot be compared is a conflict.

Limits on input are part of the rules: an input longer than the bound of its function is refused (or, for Compare, reported as Incomparable) without being read further.

Index

Constants

View Source
const (
	// MaxURLLength bounds every URL. The references have no bound on a URL.
	MaxURLLength = 2048
	// MaxHostLength is the longest host of a URL, dots included.
	MaxHostLength = 253
	// MaxLabelLength is the longest label of a host.
	MaxLabelLength = 63
	// MaxHomepageLength is the longest homepage.
	MaxHomepageLength = 200
	// MaxIDLength is the longest database id.
	MaxIDLength = 80
	// MaxEngineLength is the longest engine name.
	MaxEngineLength = 40
	// MaxLicenceLength is the longest licence id.
	MaxLicenceLength = 64
	// MaxPathLength bounds a path inside a repository. The references have no
	// bound on one.
	MaxPathLength = 1024
	// MaxRepositoryLength bounds a repository URL. The references have no bound
	// on one.
	MaxRepositoryLength = 255
	// MaxClaimLength bounds an address that is compared with another.
	MaxClaimLength = MaxURLLength
)

Bounds on input, in bytes. The bounds that the references state themselves (a host of at most 253 characters, a label of at most 63, an id of at most 80, a homepage of at most 200) are the references' rules; the others are this package's own and only ever refuse more.

View Source
const MaxLocalIDLength = 40

MaxLocalIDLength is the longest descriptor localId.

View Source
const MaxRecordsetNameLength = 256

MaxRecordsetNameLength is the longest recordset name, in UTF-16 code units, as JavaScript's String.length counts them: the Directory's bound.

Variables

This section is empty.

Functions

func ClaimedForm

func ClaimedForm(address string) (string, bool)

ClaimedForm is the form of an address that claims are compared in: ASCII lower case, trailing slashes removed. It returns false for an address that is longer than MaxClaimLength or not ASCII (the JavaScript reference folds case by Unicode rules, which this package does not copy, and the addresses that reach a comparison have already passed PublicHTTPSURL).

func CompareKey

func CompareKey(s string) (string, bool)

CompareKey is the key to compare two repositories by: RepositoryKey in lower case, since a host names one repository whatever the case it is written in. It returns false when s is not a repository.

func EncodePathSegment added in v0.30.0

func EncodePathSegment(s string) string

EncodePathSegment is JavaScript's encodeURIComponent with the five characters ! ' ( ) * encoded too (as the Directory's encodePathSegment does): every byte of the UTF-8 text except A-Z a-z 0-9 - _ . ~ is written as %XX in upper case.

func GlobalDatabaseID added in v0.32.0

func GlobalDatabaseID(s string) error

GlobalDatabaseID reports why s is not a global database identity, or nil: the canonical url of a database as the Directory takes it since it published global identities (globalDatabaseIdProblem in urls.mjs, 574a7ad and d089fa8). It is a public https URL under every rule of PublicHTTPSURL (a trailing slash is fine, a path of one segment or of several), with two differences. A path segment may hold percent escapes, when the segment is the canonical encoding of its text (encodeURIComponent, and the five characters ! ' ( ) * encoded too, in upper case; see EncodePathSegment) and the text, decoded again and again, never becomes ".", "..", a slash, a backslash or a control character. And a host under .example is allowed.

func Homepage

func Homepage(s string) error

Homepage reports why s is not a manifest's homepage: a public https URL of at most 200 bytes.

func IsBlank

func IsBlank(s string) bool

IsBlank reports whether s is empty or only white space, the way JavaScript's String.prototype.trim() sees it: a manifest field is "required" when `typeof v === 'string' && v.trim() !== ”`, and the references refuse a blank one. White space there is the ECMAScript WhiteSpace and LineTerminator characters: tab, line feed, vertical tab, form feed, carriage return, space, U+00A0, U+1680, U+2000 to U+200A, U+2028, U+2029, U+202F, U+205F, U+3000 and the byte order mark U+FEFF. It is not Go's: strings.TrimSpace strips U+0085 (which JavaScript does not) and not U+FEFF (which JavaScript does), so a check of "is required" written with strings.TrimSpace would accept "\uFEFF" where both references refuse it. Use IsBlank for those checks.

It reads up to the first character that is not white space and stops, so it needs no bound of its own; a byte that is not valid UTF-8 is not white space.

func IsCommit

func IsCommit(s string) bool

IsCommit reports whether s is a full commit id: 40 lower-case hex digits.

func IsEngine

func IsEngine(s string) bool

IsEngine reports whether s is a deployment engine name: a letter, then up to 39 letters, digits and _ . + - (^[A-Za-z][A-Za-z0-9_.+-]{0,39}$).

func IsID

func IsID(s string) bool

IsID reports whether s is a database id: lower-case letters and digits in words joined by single hyphens, at most 80 bytes (^[a-z0-9]+(-[a-z0-9]+)*$).

func IsLicenceID

func IsLicenceID(s string) bool

IsLicenceID reports whether s has the shape of an SPDX licence id: a letter or digit, then up to 63 letters, digits and . + - (^[A-Za-z0-9][A-Za-z0-9.+-]{0,63}$). It does not know which ids SPDX has assigned.

func IsLocalID added in v0.33.0

func IsLocalID(s string) bool

IsLocalID reports whether s is the localId of a database descriptor, as the Directory has it (localIdPattern): a lower-case letter, then up to 39 lower-case letters, digits and hyphens (^[a-z][a-z0-9-]{0,39}$). Unlike IsID it allows a hyphen at the end and two in a row.

func IsPublishEntry

func IsPublishEntry(s string) bool

IsPublishEntry reports whether s is an entry of an OVDB.md publish list: an explicit path, ./ followed by a repository path (the explicit form is what says the publisher meant a file of this repository and not a pattern).

func IsRepositoryPath

func IsRepositoryPath(s string) bool

IsRepositoryPath reports whether s is a path to a file inside a repository, as a manifest names one: relative (no leading /), only A-Z a-z 0-9 . _ / and -, no //, no . or .. segment, no trailing /, at most 1024 bytes. A backslash, a glob character and a space are not in the set, so none passes.

func PublicHTTPSURL

func PublicHTTPSURL(s string) error

PublicHTTPSURL reports why s is not a public https URL, or nil.

A public https URL is written exactly like this: https://, a host, a path.

  • https only; no userinfo, no port (not even :443), no query, no fragment, no percent escape, no whitespace, control character or backslash;
  • the host is lower-case letters, digits and hyphens in dot-separated labels of 1 to 63 bytes (none starting or ending with a hyphen), at least two labels, at most 253 bytes, no trailing dot; no IP address, nothing a reader could take for one (a last label of digits, or 0x and hex digits), no single-label name, no local, internal or reserved suffix; an xn-- label only when it is the canonical punycode of Latin-1 letters;
  • the path starts with / and holds only A-Z a-z 0-9 . _ ~ / and -, no //, no . or .. segment;
  • the spelling is the canonical one: there is exactly one way to write a URL that passes.

It does not check that anything exists, and it cannot see the address a name resolves to: a public-looking name can resolve to a private address, which only the party that connects can check.

func PublicHTTPSURLTemplate

func PublicHTTPSURLTemplate(s string) error

PublicHTTPSURLTemplate is PublicHTTPSURL for a template: the literal {name} must appear exactly once, in the path.

func Quote added in v0.23.0

func Quote(s string) string

Quote is [show] for other packages: the one way a piece of input goes into a message, cut to a short length, quoted and escaped to printable ASCII.

func RecordsetName added in v0.30.0

func RecordsetName(s string) error

RecordsetName reports why s is not a recordset name, or nil: text that is not blank by JavaScript's trim(), at most 256 UTF-16 code units, not "." or "..", and with no slash, backslash or control character (U+0000 to U+001F, U+007F). Any other character is allowed, a space, a dot and a non-ASCII letter among them.

func RecordsetPage added in v0.30.0

func RecordsetPage(template, name string) error

RecordsetPage reports why the page of the recordset called name is not an acceptable public URL, or nil. The page is the template of deployment.recordset_page with {name} replaced by the name as one encoded path segment. A name that needs no encoding makes an ordinary public https URL. One that does is accepted only when the segment is all that the {name} makes (nothing of the template shares its path segment), the template holds {name} in its path, the name is neither "." nor "..", has no slash, backslash or control character, and nothing inside it, decoded again and again, becomes one of those: a router that decodes a second time must not find a path separator or a dot segment. The rest of the URL is held to the ordinary rules; the page has no length bound of its own, as the Directory has none: the name is bounded here, and the template is bounded by the template rule (PublicHTTPSURLTemplate, 2048 bytes) that a caller runs on it first, so a caller that skips that rule has no bound on the page.

func RepositoryKey

func RepositoryKey(s string) (string, bool)

RepositoryKey returns the canonical key of the repository that s names, and whether s is one: an https URL on an allow-listed host with exactly the host's number of path segments, each of A-Z a-z 0-9 . _ - and none of them . or .., the last not ending in .git in any case; no trailing slash, port, user, query or fragment. The key is host/org/repo, as written.

Types

type Problem

type Problem struct {
	Rule   Rule
	Detail string
}

Problem is why a URL is refused.

func (*Problem) Error

func (p *Problem) Error() string

Error returns the detail.

type Relation

type Relation int

Relation is how one claimed address stands to another. Its zero value is Incomparable, not "apart": a Relation that nobody set, or that a caller did not think about, is read as a conflict. Callers that look for conflicts use Relation.Conflicts and never compare with Same or Under themselves.

const (
	// Incomparable means an address is not plain ASCII or is longer than
	// MaxClaimLength, so it cannot be compared faithfully. It is a conflict.
	Incomparable Relation = iota
	// Apart means the two addresses are different and neither is under the other.
	Apart
	// Same means the addresses are the same once case and trailing slashes are
	// set aside.
	Same
	// Under means the first address sits under the second: the second followed
	// by a slash is a prefix of the first, so the boundary is a path segment
	// (/dbs/chinook2 is not under /dbs/chinook).
	Under
	// Over means the second address sits under the first.
	Over
)

func Compare

func Compare(address, other string) Relation

Compare says how address stands to other, case-insensitively and with trailing slashes set aside. Use Conflicts on the result.

func (Relation) Conflicts

func (r Relation) Conflicts() bool

Conflicts reports whether two claims in this relation conflict: they are the same, one is under the other, or they cannot be compared. Only Apart does not.

type Rule

type Rule string

Rule names the rule that a refused input broke. It is stable: callers and tests match on it, never on the message.

const (
	RuleLength          Rule = "length"          // longer than the bound of the function
	RuleNotURL          Rule = "not-a-url"       // empty, or not https://host/path at all
	RuleCharacter       Rule = "character"       // whitespace, a control character, a backslash or a non-ASCII byte
	RuleScheme          Rule = "scheme"          // a scheme other than https
	RuleUserinfo        Rule = "userinfo"        // credentials in the authority
	RulePort            Rule = "port"            // a port, even :443
	RuleQuery           Rule = "query"           // a ? in the URL
	RuleFragment        Rule = "fragment"        // a # in the URL
	RulePercent         Rule = "percent-escape"  // a % in the URL
	RuleHostCharacter   Rule = "host-character"  // a character outside a-z 0-9 hyphen and dot in the host
	RuleHostCase        Rule = "host-case"       // an upper-case letter in the host
	RuleHostLabel       Rule = "host-label"      // an empty label, a label over 63 bytes, a hyphen at either end of a label
	RuleHostLength      Rule = "host-length"     // a host over 253 bytes
	RuleHostSingleLabel Rule = "host-single"     // a host of one label
	RuleHostNumeric     Rule = "host-numeric"    // a host that is, or could be read as, an IP address
	RuleHostReserved    Rule = "host-reserved"   // a local, internal or reserved name
	RuleHostPunycode    Rule = "host-punycode"   // an xn-- label that is not valid punycode for a host name
	RuleHostIDN         Rule = "host-idn"        // an xn-- label of letters this tool does not accept yet
	RuleNoPath          Rule = "no-path"         // no path: write https://host/
	RulePathCharacter   Rule = "path-character"  // a character outside A-Z a-z 0-9 . _ ~ / and - in the path
	RulePathEmptySeg    Rule = "path-empty"      // //
	RulePathDotSegment  Rule = "path-dot"        // a . or .. segment
	RulePlaceholder     Rule = "placeholder"     // {name} missing, repeated, or outside the path
	RuleHomepageLength  Rule = "homepage-length" // a homepage over 200 bytes
)

The rules a URL can break.

const RuleRecordsetName Rule = "recordset-name"

RuleRecordsetName is the rule a refused recordset name broke. Like every Rule of this package it names the kind for callers and tests of the rules; a finding of the check carries its own code (manifest-recordsets).

type URL

type URL struct {
	Host        string // lower-case labels joined by dots
	Path        string // starts with /; for a template, {name} as written
	Placeholder int    // for a template, the offset of {name} in Path; otherwise -1
}

URL is an accepted URL in its parts, so that the rules that look at a host or a path (the marker of a canonical url, the same-origin rule, a publisher url) never split the text again. The scheme is always https and there is no port, userinfo, query or fragment.

func ParseGlobalDatabaseID added in v0.32.0

func ParseGlobalDatabaseID(s string) (URL, error)

ParseGlobalDatabaseID is GlobalDatabaseID that returns the parts of an accepted identity.

func ParsePublicHTTPSURL

func ParsePublicHTTPSURL(s string) (URL, error)

ParsePublicHTTPSURL is PublicHTTPSURL that returns the parts of an accepted URL.

func ParsePublicHTTPSURLTemplate

func ParsePublicHTTPSURLTemplate(s string) (URL, error)

ParsePublicHTTPSURLTemplate is PublicHTTPSURLTemplate that returns the parts of an accepted URL.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL