Table of Contents

Class SafeHttpResourceLoader

Namespace
NetPdf
Assembly
NetPdf.dll

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 hostile Location: headers without the wrapper's ValidateRedirect(Uri, Uri, SecurityPolicy, int) running.

What this loader does instead.

  1. 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.).
  2. 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.
  3. Set AllowAutoRedirect = false. On a 30x response, manually walk the Location: header through ValidateRedirect(Uri, Uri, SecurityPolicy, int) + recurse with the updated hop count.
  4. 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.

public sealed class SafeHttpResourceLoader : IResourceLoader, IDisposable
Inheritance
SafeHttpResourceLoader
Implements
Inherited Members

Constructors

SafeHttpResourceLoader(SecurityPolicy?)

Construct with the active SecurityPolicy. The loader captures the policy at construction so the configured IP blocklist + redirect cap + per-resource size cap apply uniformly across every fetch issued by this loader instance.

 <p>Per post-Task-7 review (P1 #1) — when this loader is
 wrapped by a <xref href="NetPdf.SafeResourceLoader" data-throw-if-not-resolved="false"></xref> whose
 <xref href="NetPdf.ResourceFetchContext.Policy" data-throw-if-not-resolved="false"></xref> differs from the
 policy passed here, the wrapper's constructor throws
 <xref href="System.ArgumentException" data-throw-if-not-resolved="false"></xref> to surface the misconfig before
 any divergent decisions are made. To keep them in sync, prefer
 <xref href="NetPdf.SafeResourceLoader.CreateWithSafeHttp(NetPdf.ResourceFetchContext)" data-throw-if-not-resolved="false"></xref>, which
 constructs both with the context's policy as the single source
 of truth.</p>
public SafeHttpResourceLoader(SecurityPolicy? policy = null)

Parameters

policy SecurityPolicy

Properties

Policy

Per post-Task-7 review (recommendation P1 #1) — the SecurityPolicy this loader captured at construction. Exposed so SafeResourceLoader's constructor can detect a policy-divergence misconfig (the wrapper's Policy differing from the inner HTTP loader's policy) + reject it at construction rather than letting redirects / AllowedHosts / per-resource-bytes validation use one policy while scheme / IP-blocklist validation uses another. Read-only — set once at construction.

public SecurityPolicy Policy { get; }

Property Value

SecurityPolicy

Methods

Dispose()

Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.

public void Dispose()

LoadAsync(Uri, ResourceKind, CancellationToken)

Per Phase 5 contract — fetch a resource with full SSRF / redirect / size enforcement.

public ValueTask<ResourceResponse> LoadAsync(Uri uri, ResourceKind kind, CancellationToken ct)

Parameters

uri Uri
kind ResourceKind
ct CancellationToken

Returns

ValueTask<ResourceResponse>