Class ResourceFetchContext
- Namespace
- NetPdf
- Assembly
- NetPdf.dll
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.ConvertAsync invocation;
sharing across renders would let attacker-A's traffic exhaust attacker-B's
budget. The pipeline allocates this in
HtmlParsingHost.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.
public sealed class ResourceFetchContext
- Inheritance
-
ResourceFetchContext
- Inherited Members
Constructors
ResourceFetchContext(SecurityPolicy, Uri?, CancellationToken)
public ResourceFetchContext(SecurityPolicy policy, Uri? baseUri, CancellationToken cancellationToken)
Parameters
policySecurityPolicybaseUriUricancellationTokenCancellationToken
Properties
BaseUri
The conversion's BaseUri. Loaders use this to resolve relative URIs + to anchor the AllowFileSchemeUnderBaseUri path-prefix check that UriSafetyValidator defers.
public Uri? BaseUri { get; }
Property Value
CancellationToken
The conversion-level cancellation token.
public CancellationToken CancellationToken { get; }
Property Value
FetchedBytes
Running cumulative bytes returned across every successful fetch. Written via Add(ref long, long) in TryAddBytes(long); reads are volatile.
public long FetchedBytes { get; }
Property Value
FetchedCount
Running count of resources successfully fetched. Read is volatile per Interlocked semantics; writes go through TryReserveSlot()'s atomic CAS.
public int FetchedCount { get; }
Property Value
Policy
The active SecurityPolicy. Captured once at construction so a hostile loader can't swap policies mid-render.
public SecurityPolicy Policy { get; }
Property Value
Methods
TryAddBytes(long)
Charge bytes against the per-render
byte budget. Used after a successful fetch when the actual byte
count is known; does not increment the slot counter (the caller
already reserved one via TryReserveSlot()). Returns a
non-null reason when the byte budget would be exceeded; null on
success.
<p>Per PR #18 review #6 — concurrency-safe via CAS.
<xref href="System.Threading.Interlocked.Add(System.Int64%40%2cSystem.Int64)" data-throw-if-not-resolved="false"></xref> alone would
over-charge: two concurrent calls could each see a value under
the cap, both add their bytes, and end above the cap. The CAS
loop reserves the byte count atomically.</p>
public string? TryAddBytes(long bytes)
Parameters
byteslong
Returns
TryReserveSlot()
Reserve one fetch slot against the per-render count cap. Returns a non-null reason when the slot budget is exhausted; null when the reservation succeeded.
<p>Per PR #18 review #6 — uses CAS (<xref href="System.Threading.Interlocked.CompareExchange(System.Int32%40%2cSystem.Int32%2cSystem.Int32)" data-throw-if-not-resolved="false"></xref>)
so concurrent callers can race the increment without exceeding
the cap. The CAS loop reads the current count, computes the
next value, attempts to swap; on contention re-reads + retries.</p>
<p>Byte budget enforcement is split out into <xref href="NetPdf.ResourceFetchContext.TryAddBytes(System.Int64)" data-throw-if-not-resolved="false"></xref>
so the caller can reserve a slot at fetch START (when the byte count
is unknown) + charge the actual byte count at fetch END (without
re-incrementing the slot counter).</p>
public string? TryReserveSlot()