Namespace NetPdf
Namespaces
Classes
- CachePolicy
Controls per-document and process-level caching of fetched resources, parsed fonts, and shaped glyph runs. Defaults are tuned for typical document workloads.
- FontFaceData
Raw font-file bytes plus optional metadata. NetPdf parses the bytes to extract metrics, glyph outlines, and OpenType tables. Accepted formats in v1: bare sfnt TTF / OTF. Wrapped WOFF / WOFF2 are currently REJECTED at load (NetPdf.Text.Fonts.FontFace) pending safe decompression wiring (decoder infrastructure exists under
NetPdf.Text.Fonts.Woff; see security task SEC-7).
- HtmlPdf
The public entry point. Convert an HTML+CSS string to a PDF byte stream.
- HtmlPdfException
Thrown when conversion fails or, in strict mode, when an unsupported feature is encountered. Carries the diagnostic code that triggered the failure.
- HtmlPdfOptions
All options that control conversion. The default-constructed instance produces sensible behavior for a US Letter / A4 print document with print media stylesheets, backgrounds on, and exact colors honored.
- LayoutMetrics
Metrics describing how the document was laid out. Surfaced via LayoutMetrics; useful for diagnostics dashboards and regression detection.
- PdfRenderResult
Detailed result returned by ConvertDetailed(string, HtmlPdfOptions?). Pair with the simple Convert(string, HtmlPdfOptions?) overload when you don't care about metrics; this is the dashboard / observability surface.
- ResourceFailure
A resource load that did not produce content. Surfaced via ResourceFailures.
- ResourceFetchContext
Per Phase D D-1 — per-render state threaded through every SafeResourceLoader fetch. Tracks the cumulative byte + fetch counts that MaxResourcesPerRender + MaxTotalResourceBytes bound.
One instance lives per
HtmlPdf.ConvertAsyncinvocation; sharing across renders would let attacker-A's traffic exhaust attacker-B's budget. The pipeline allocates this inHtmlParsingHost.ParseAsync(or whoever owns the conversion's top-level entry point) + passes it down through every CSS / image / font resource lookup.Per PR #18 review #6 — concurrency-safe. Reservations use Interlocked so a future Phase 5 implementation can fan out parallel image/font/style fetches without races. Pre-fix concurrent callers could each read a stale
FetchedCount, find it under the cap, increment from that stale value, and collectively exceed the cap. Post-fix the count + byte ledger maintain their invariants under concurrent reservation.
- SafeHttpResourceLoader
Per PR #18 review #1 — built-in HTTP / HTTPS resource loader that closes the SSRF gap left by the bare IResourceLoader contract. The pre-fix flow:
SafeResourceLoader → UriSafetyValidator.Validate (scheme + IP if literal) → user IResourceLoader (HttpClient default) ↓ DNS resolution + auto-follow redirects (NEITHER seen by SafeResourceLoader)Symbolic hosts (e.g.,
attacker.com) deferred IP validation until after DNS, but the user loader was a black box: it could resolve to a private / loopback / cloud-metadata IP + connect. Auto-redirect could step through hostileLocation:headers without the wrapper's ValidateRedirect(Uri, Uri, SecurityPolicy, int) running.What this loader does instead.
- Resolve the host via GetHostAddressesAsync(string, CancellationToken);
immediately reject every resolved address that hits the
IsBlockedIp(IPAddress, out string) blocklist (loopback,
private, link-local incl. AWS metadata
169.254.169.254, IPv6 ULA, IPv4-mapped, etc.). - Use ConnectCallback to intercept the connect step + use the pre-validated IP — defeats the DNS-rebinding attack (resolve, validate, then re-resolve to a different IP at connect time) by pinning the IP from the validation pass.
- Set AllowAutoRedirect = false.
On a 30x response, manually walk the
Location:header through ValidateRedirect(Uri, Uri, SecurityPolicy, int) + recurse with the updated hop count. - Cap response bytes at the configured per-resource limit so a malicious server can't stream gigabytes.
NetPdf v1 ships no default loader. This class is a reference implementation that consumers can opt into via:
options.ResourceLoader = new SafeHttpResourceLoader();Phase 5's wireup may wire it automatically when an HTTP-fetching surface is requested.
- Resolve the host via GetHostAddressesAsync(string, CancellationToken);
immediately reject every resolved address that hits the
IsBlockedIp(IPAddress, out string) blocklist (loopback,
private, link-local incl. AWS metadata
- SafeResourceLoader
Per Phase D D-1 — the only valid pipeline entry point for resource fetches. Wraps a user-supplied IResourceLoader + applies every safety check the NetPdf threat model requires:
- Per-render budget via ResourceFetchContext:
MaxResourcesPerRender(count cap),MaxTotalResourceBytes(cumulative byte cap). - URI safety via Validate(Uri, SecurityPolicy):
scheme allowlist (file/data/http/https per SecurityPolicy),
IP blocklist for HTTP(S) (loopback, private, link-local incl.
AWS/GCE/Azure metadata 169.254.169.254, IPv6 ULA, IPv4-mapped),
AllowedHostsfilter. - file: base-path check when the URI returns
RequiresBasePathCheck:
the resolved file path is verified to lie under
BaseUri's directory subtree
(canonicalized to defeat
../traversal). - Per-resource size cap from MaxResourceBytes (post-fetch validation; pre-fetch byte estimate not always available from the user loader).
- MIME allowlist per ResourceKind
so an
<img src=...>servingtext/htmlcan't route through the image decoder. - Per-fetch timeout via ResourceTimeout linked to the conversion's cancellation token.
Why this wrapper exists. The user-facing IResourceLoader contract is intentionally narrow (raw byte fetch). If any caller in the pipeline went directly to ResourceLoader, that caller would bypass every defense above. SafeResourceLoader is the only pipeline-internal entry point — when Phase 5 wires resource fetching, every consumer (CSS parser for
url()/@import/@font-face, image decoder, font resolver) calls THIS, never the underlying IResourceLoader directly.NetPdf v1 ships no default loader. When ResourceLoader is null, every fetch returns a ResourceFailure immediately without invoking any logic — the wrapper still exists so the contract is consistent for Phase 5's wireup.
- Per-render budget via ResourceFetchContext:
- SafeResourceLoaderWithHttp
Per post-Task-7 review (recommendation P1 #1) — bundle returned by CreateWithSafeHttp(ResourceFetchContext). Holds the constructed wrapper + the underlying HTTP loader so the caller can dispose the loader at shutdown without losing the wrapper's reference.
- SecurityPolicy
Controls which URI schemes and hosts the resource loader is allowed to fetch from, plus per-resource size / time limits. The default is the BaseUri-sandbox model: file:// reads under BaseUri's directory subtree are permitted, but the rest of the filesystem and remote schemes (http/https) are not. This lets typical templates with relative
<img src="logo.png">work out of the box without exposing the host filesystem.
- SystemFontResolver
IFontResolver backed by a process-wide system-font index. Resolves CSS-generic family names (
serif,sans-serif,monospace,cursive,fantasy,system-ui) by walking a per-platform fallback chain of known family names; for non-generic queries, looks up the family directly in the index built from the OS's font directories.
- UnsupportedFeature
A feature encountered in the input that is parsed but not yet rendered. Distinct from a Diagnostic in that it represents a known gap, not a runtime issue. Equivalent diagnostic codes are also emitted for convenience.
- UriSafetyValidator
Per Phase B B-7 — the SSRF / SSRP gate every resource-loader implementation is expected to call before issuing an outbound fetch. Combines two checks:
- Scheme allowlist — only schemes enabled on the
active SecurityPolicy are accepted. Default policy
(SafeDefault) accepts
file:only when the path is under BaseUri +data:inline content; bothhttp:andhttps:are off. - Private / loopback / link-local IP blocklist for
HTTP(S) hosts. Catches the standard SSRF amplifier set: cloud-metadata
endpoints (
169.254.169.254AWS / GCE / Azure / Alibaba;fd00::/8IPv6 ULA), localhost (127.0.0.0/8,::1), private LAN (10/8,172.16/12,192.168/16,fc00::/7), link-local (169.254/16,fe80::/10), multicast (224.0.0.0/4,ff00::/8), and unspecified (0.0.0.0,::). Hosts that resolve via DNS are NOT validated here — the loader must resolve to IP, then re-validate to defend against DNS rebinding. IsBlockedIp(IPAddress, out string) exposes the IP check standalone for that use.
Phase B contract. NetPdf v1 ships with no default loader, so this validator's only client today is unit tests. Phase 5 wires a real IResourceLoader implementation that calls ValidateScheme(Uri, SecurityPolicy) at intent time + IsBlockedIp(IPAddress, out string) after DNS resolution, refusing the fetch on any "unsafe" verdict and emitting
RES-LOAD-FAILED-001with the rejection reason.What this does NOT do. Network policy (firewalls, egress proxies, captive portals) belongs at the OS / fabric layer; this validator addresses application-level SSRF defense only. It also does not handle HTTP redirects — the loader must re-validate the redirect target host after each hop.
- Scheme allowlist — only schemes enabled on the
active SecurityPolicy are accepted. Default policy
(SafeDefault) accepts
Structs
- Diagnostic
A diagnostic emitted during conversion — an unsupported feature, a malformed rule, a failed resource load, or a raster-fallback notification. Codes are stable and versioned; see
docs/diagnostics-codes.mdfor the registry.
- FontQuery
A request to find a font face. Family is the CSS-resolved family name (after generic-family expansion). The query maps directly onto the three CSS Fonts Module Level 4 §5.2 matching axes: StretchCss, Style, and WeightCss.
- PageMargins
Default page margins applied unless overridden by
@pageCSS. All values are in CSS pixels (1 in = 96 px at default DPI).
- PageSize
A page size expressed in CSS pixels. NetPdf's canonical layout unit is the CSS pixel (1 px = 0.75 pt at 96 DPI); conversion to PDF points happens at emission only.
- ResourceResponse
Response returned by IResourceLoader. Use
default(an empty Content) to indicate the resource was not found.
- SafeResourceResult
Result of a FetchAsync(Uri, ResourceKind). Either a successful ResourceResponse (loaded bytes + MIME) or a typed failure with the reason for diagnostics.
- SourceLocation
Optional source location attached to a Diagnostic — typically the position in the input HTML or a fetched stylesheet where the issue originated.
- TimingBreakdown
Per-stage wall-clock timings. Total is the end-to-end conversion time; the per-stage values sum to roughly that minus parallelism overlaps.
- UriSafetyValidator.Verdict
Result of a validation check.
Interfaces
- IDiagnosticsSink
Receives diagnostics during conversion. Implementations should be thread-safe; NetPdf emits diagnostics from background paint threads. Use this for streaming logs; ConvertDetailed(string, HtmlPdfOptions?) aggregates them into PdfRenderResult at the end.
- IFontResolver
Resolves a font query (family + weight + style + script) to a font face. NetPdf falls back to system font enumeration if no resolver is set, but custom resolvers can ship fonts with the application or fetch them from a private CDN.
- IResourceLoader
Resolves external resources referenced by HTML/CSS — images, fonts, stylesheets. Implementations may load from disk, embedded assemblies, HTTP, in-memory caches, etc. NetPdf provides no default loader; if a resource is referenced but no loader is set, the resource is skipped and a
RES-LOAD-FAILED-001diagnostic is emitted.
Enums
- CssMediaType
Which CSS media-type stylesheet block applies. Default is Print because PDF is paged output.
@media print { ... }rules are honored when this is Print;@media screenapplies when this is Screen.
- DiagnosticSeverity
Severity of a Diagnostic. Error means the input was rejected when StrictUnsupportedCss is set.
- FeatureFlags
Opt-in flags that toggle experimental or non-default behavior. v1 ships with all non-default flags off; consumers opt in deliberately.
- PdfPageLayout
The page layout a PDF reader uses when it first opens the document (ISO 32000-2 §7.7.2, catalog
/PageLayout). Controls how many pages are shown side by side and whether the first page is treated as a cover.
- PdfPageMode
How a PDF reader's navigation UI is presented when the document first opens (ISO 32000-2 §7.7.2, catalog
/PageMode) — e.g. whether the bookmarks (outline) panel is open.
- PdfVersion
The PDF specification version emitted in the file header. Default is V1_7 for broad viewer compatibility. ISO 32000-2:2020 is the normative reference for our writer; emitting older bytes is a forward-compatible choice.
- ResourceKind
What the resource will be used as. Loaders may apply different policies per kind (e.g., size limits, MIME validation).
- UriSafetyValidator.SafetyOutcome
Per PR #16 review user-recommendation #5 + Copilot review #8 — the result of Validate(Uri, SecurityPolicy) is no longer a binary safe/unsafe split.
file:URIs under theAllowFileSchemeUnderBaseUridefault need a base-path check that this validator does not perform (it has noBaseUriin scope), and treating the scheme-allowlist verdict as a complete answer led to easy misuse. The three-state UriSafetyValidator.SafetyOutcome makes the contract explicit at the call site.