A pure-Rust implementation of the Content Security Policy Level 3
directive grammar — parses a serialized CSP (or a comma-separated list of
policies, as sent in the Content-Security-Policy HTTP header) and
reports whether it is syntactically valid, with structured access to its
directives and their values.
Generic and standalone — not tied to HTML, a specific host language, or
any particular consumer. Nothing in the API assumes a particular caller:
it's equally usable for validating/linting a CSP header or <meta> tag,
building a CSP config editor or security scanner, checking a policy in
CI, or any other tool that needs to know whether a CSP string is
well-formed and what it actually says.
use csp_parse::{parse_policy_list, DirectiveValue};
let list = parse_policy_list("default-src 'self'; script-src 'self' 'nonce-abc123'");
for directive in &list.policies[0].directives {
match directive.value() {
DirectiveValue::SourceList(source_list) => println!("{}: {source_list:?}", directive.name),
other => println!("{}: {other:?}", directive.name),
}
}See examples/parse.rs (cargo run --example parse) for a fuller, runnable example.
Parsing is deliberately lenient/infallible, matching CSP's own
forward-compatible design: an unrecognized directive name, an
unrecognized source-expression token, or a byte outside a
production's allowed character class does not fail the whole parse —
it's still reported structurally, with per-item validity queryable
separately (Directive::name_is_valid/value_is_valid,
DirectiveValue::Unknown, SourceListEntry::expression: None, …). See
plan/DECISIONS.md for the reasoning.
The directive → value-grammar registry (registry_lookup) is a
snapshot of CSP3's directive set at the time this crate was written,
not a permanent guarantee of completeness — new directives get added to
the spec over time faster than the rest of the grammar changes. An
unregistered directive name is not an error (CSP3 itself treats unknown
directives as forward-compatible, not invalid); it just doesn't get a
structured DirectiveValue (falls back to DirectiveValue::Unknown,
with its raw name/value still available via Directive).
parse_hash_expression parses exactly the hash-algorithm "-" base64-value grammar shared between CSP's hash-source (used inside
a source-list, quoted: 'sha256-...') and Subresource Integrity's
unquoted integrity="" hash tokens (sha256-..., no quotes). It's
exported as its own building block so callers that only need to
validate/parse SRI hash expressions can use it directly, without
depending on the rest of this crate's CSP-specific parsing (one such
caller: html-conform's
w:integrity-metadata datatype).
Phases 02–07 implemented (generic directive splitting, source-list
grammar, directive registry, spec-example/edge-case sweep, public API
docs, licensing/compliance) — see plan/00-STATUS.md (not tracked in
git, local working document; see plan/README.md for why). Not yet
published to crates.io (Phase 08). No official CSP grammar-only
testsuite exists to vendor (web-platform-tests' CSP tests are
browser-enforcement tests, not syntax tests); conformance confidence
instead comes from the per-phase test matrices plus
tests/spec_examples.rs.
Intended crates.io name: csp-parse. Not yet published.
0.1.0 is a pre-release working version with no semver stability
guarantee — breaking changes are expected before the first crates.io
publish (Phase 08). Normal semver applies afterwards.
MIT — see LICENSE.