Skip to content

About

Fast WHATWG-compliant URL parser for .NET, built on Ada

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

9 stars

Watchers

1 watching

Forks

Latest commit

 

History

109 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ada.Url

NuGet Downloads CI License

WHATWG compliant URL parsing for .NET, built on Ada, the C++ URL parser behind Node.js. It parses URLs the way browsers do, allocates nothing on the UTF-8 path, and is up to 1.9x faster than System.Uri.

using var url = AdaUrl.Parse("https://example.org/path/../file.txt"u8);
Encoding.UTF8.GetString(url.Href);      // https://example.org/file.txt
Encoding.UTF8.GetString(url.Hostname);  // example.org

Status: 0.x. The conformance suite passes in full on every supported platform and the public API has not changed since the first beta, but under SemVer a minor version may still break it.

Install

dotnet add package Ada.Url

Requires .NET 10. Native binaries for win-x64, win-arm64, linux-x64, linux-arm64, linux-musl-x64, linux-musl-arm64, osx-x64 and osx-arm64 ship inside the package.

Usage

One shot checks. Parse, answer and free inside the call. Nothing allocates.

AdaUrl.CanParse("https://example.com/"u8);                        // true

Span<byte> buffer = stackalloc byte[256];
AdaUrl.TryNormalize(input, buffer, out int written);
AdaUrl.TryGetHostname(input, buffer, out written);                // for an allow list

Several properties from one URL. AdaUrl is a ref struct, so it stays on the stack and cannot outlive the block.

using var url = AdaUrl.Parse("https://user:pass@example.com:8443/a/b?q=1#frag"u8);

url.Hostname;        // example.com
url.Port;            // 8443
url.Search;          // ?q=1
url.HasCredentials;  // true

ReadOnlySpan<byte> (UTF-8) is the primary API. string overloads exist and pay a transcode.

Query strings (AdaSearchParams), internationalised domains (AdaIdna) and every other public type are in the API reference, with examples.

Why not System.Uri

System.Uri implements RFC 3986 and 3987 plus .NET specific behaviour. It is not WHATWG compliant, so it disagrees with browsers and with the Node, Go and Python parsers. Across 538 absolute URLs from the WHATWG test corpus:

Count
Same result 352
Accepted by Ada, rejected by System.Uri 64
Rejected by Ada, accepted by System.Uri 32
Both parsed, different serialisation 90

The bold row matters for security. Each of those 32 is an input that browsers, Node, Go and Python all refuse and System.Uri accepts. Code that validates a URL with one parser and fetches it with another has a gap exactly there. All 186 differences are listed in docs/system-uri-differences.md, generated from the corpus by a test.

Performance

Platform Parse and read three properties Allocated
Linux x64 1.9x faster 0 B against 288 B
Linux arm64 1.9x faster 0 B against 288 B
macOS arm64 1.4x faster 0 B against 288 B
Windows x64 about level 0 B against 288 B

Zero allocation holds on every platform. Speed depends on it: Windows is level because its heap makes Ada's two internal allocations per parse about 4x more expensive than on Linux. Measured on 0.1.0. Details, per-call numbers and a pattern for high volume loops on Windows are in docs/performance.md.

Limits

  • Zero allocation means span in, span out. Any string result allocates.
  • A borrowed span is invalidated by any setter. Documented and tested, not enforced. Copy what you need before mutating. See ADR-0004.
  • net10.0 only. No .NET Framework, Mono or Unity. See ADR-0001.
  • Handles are not thread safe. Concurrent reads are fine; a concurrent setter makes every outstanding span a use after free.

Security

A URL parser usually decides whether a URL is safe to fetch.

  1. Compare the parsed Hostname, never a prefix of the raw input. Prefix checks are the classic SSRF bypass.
  2. Compare against the post IDNA ASCII form. Confusable Unicode domains normalise to different ASCII.

The library never logs a URL. Neither should you: URLs routinely carry credentials.

Report vulnerabilities as described in SECURITY.md.

Conformance

Tested on every commit against the web-platform-tests URL corpus, the suite browsers are held to, on Linux x64 and arm64, macOS arm64, and Windows x64 and arm64.

Cases Result
URLs that must parse 607 all pass
URLs that must be rejected 267 all rejected
Setter behaviour 278 all pass
Total 1,152 all pass

Documentation

Link Contents
API reference Every public type and method, with examples
docs/performance.md Benchmarks and what they mean
docs/system-uri-differences.md Every disagreement with System.Uri
docs/adr/ Architecture decision records
docs/ADA_PLAN.md Original design plan
docs/runbooks/release.md Releasing and rolling back
CHANGELOG.md Release history
CONTRIBUTING.md Building from source, including the native library, and pull request rules

License

MIT, see LICENSE. Ada is dual licensed Apache-2.0 or MIT and is redistributed under the MIT option. See THIRD-PARTY-NOTICES.txt.

Unofficial, not affiliated with the Ada project.

About

Fast WHATWG-compliant URL parser for .NET, built on Ada

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

9 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages