The Static Network Filtering Engine (SNFE) is the subsystem responsible for loading, indexing, and evaluating all network-level filters from static filter lists (e.g., EasyList). This page documents the internals of src/js/static-net-filtering.js covering filter class design, the flat typed-array storage model, the token-based dispatch system, the match pipeline, and compiled-filter serialization.
For how raw filter text is parsed into an AST before reaching this engine, see Filter Syntax and Parsing. For how a live browser request flows through this engine and reaches a block/allow decision, see Request Processing Pipeline. For how filter lists are fetched and compiled at startup, see Filter List Management and Updates.
Diagram: SNFE data flow from compiled filter lists to a match result
Sources: src/js/static-net-filtering.js1-35 src/js/static-net-filtering.js451-534 src/js/static-net-filtering.js542-554
Every filter is assigned a 18-bit category (called a "realm") that encodes its block/allow status, party constraint, resource type, and modifier type. These bits are used to partition filters into separate buckets before any pattern matching occurs. The engine only probes buckets whose realm matches the current request context.
Bit layout of category bits src/js/static-net-filtering.js48-90:
| Bits | Name | Values |
|---|---|---|
| 0–1 | Block/Allow/Important | BLOCK_REALM=0, ALLOW_REALM=1, IMPORTANT_REALM=2 |
| 3–4 | Party | ANYPARTY=0, FIRSTPARTY=8, THIRDPARTY=16 |
| 5–9 | Resource type | typeNameToTypeValue (e.g., script=4<<5, image=2<<5) |
| 10 | Headers-based | HEADERS_REALM |
| 11 | Redirect | REDIRECT_REALM |
| 12 | Removeparam | REMOVEPARAM_REALM |
| 13 | CSP | CSP_REALM |
| 14 | Permissions | PERMISSIONS_REALM |
| 15 | URI transform | URLTRANSFORM_REALM |
| 16 | Replace | REPLACE_REALM |
| 17 | URL skip | URLSKIP_REALM |
The constants BLOCK_REALM, ALLOW_REALM, IMPORTANT_REALM, FIRSTPARTY_REALM, THIRDPARTY_REALM, MODIFY_REALMS, and TYPE_REALM are all module-level constants in src/js/static-net-filtering.js68-90
Resource type names map to integer offsets via typeNameToTypeValue src/js/static-net-filtering.js93-119 The reverse lookup is typeValueToTypeName src/js/static-net-filtering.js142-167 The constant TYPE_REALM_OFFSET = 5 is the bit shift applied to place type values into the realm word.
Modifier types (redirect, csp, removeparam, etc.) are enumerated as MODIFIER_TYPE_* constants src/js/static-net-filtering.js186-227 and mapped to realm bits via modifierBitsFromType.
Sources: src/js/static-net-filtering.js48-227
Rather than allocating JavaScript objects per filter, the SNFE stores all filter node data in a single growing Int32Array called filterData, and a parallel filterRefs array for values that cannot fit in 32-bit integers (e.g., compiled RegExp objects).
src/js/static-net-filtering.js451-509
| Symbol | Role |
|---|---|
filterData | Module-level Int32Array; grows by FILTER_DATA_PAGE_SIZE (65536) pages |
filterDataWritePtr | Current allocation pointer into filterData |
filterDataAlloc(...args) | Allocates a fixed-length record, returns the index (idata) |
filterDataAllocLen(len) | Allocates len slots, returns start index |
filterSequenceAdd(a, b) | Allocates a 2-element linked-list node |
filterDataReset() | Clears the pool (used on filter list reload) |
filterDataToSelfie() | Returns the live subarray for serialization |
filterDataFromSelfie(selfie) | Restores filterData from a serialized Int32Array |
The first word at any idata is always the filter class id (fid). All other words are class-specific fields.
src/js/static-net-filtering.js511-533
| Symbol | Role |
|---|---|
filterRefs | Plain JS array for object references |
filterRefAdd(ref) | Appends an object, returns its index |
filterRefsReset() | Clears the array |
filterRefsToSelfie() / filterRefsFromSelfie() | Serialization helpers |
Filter classes store the filterRefs index in a filterData slot when they need to hold a JS object (e.g., a RegExp). On selfie restore, the RegExp is reconstructed lazily on first use.
Sources: src/js/static-net-filtering.js451-533
Diagram: Filter class organization and code-level names
Sources: src/js/static-net-filtering.js670-724
Each class is a static-method-only object registered with registerFilterClass src/js/static-net-filtering.js569-574 Registration assigns a sequential integer fid (filter class id), stored as FilterClass.fid. The filterClasses array maps fid → class object.
The standard interface every filter class implements:
| Method | Purpose |
|---|---|
match(idata) | Returns true if the filter matches the current request (reads global $ registers) |
compile(details) | Produces a serializable args array from compilation details |
fromCompiled(args) | Allocates into filterData/filterRefs, returns idata |
logData(idata, details) | Populates a log details object for the logger UI |
keyFromArgs(args) | Optional; returns a dedup key to avoid allocating identical filter nodes |
dnrFromCompiled(args, rule) | Optional; emits a DNR rule for the MV3 pipeline |
The filterFromCompiled(args) dispatcher src/js/static-net-filtering.js576-588 deduplicates filter nodes using filterArgsToUnit (a Map<string, idata>) when the class supplies keyFromArgs.
Sources: src/js/static-net-filtering.js565-658
src/js/static-net-filtering.js542-554
bidiTrie is a module-level instance of BidiTrieContainer (from src/js/biditrie.js). It serves two roles:
bidiTrie.storeString(s) and retrieved with bidiTrie.extractString(i, n). The returned index i is stored in filterData.FilterPatternPlain.match() uses bidiTrie.startsWith() to check whether the stored pattern appears at a given position in the URL haystack. The "bidi" (bidirectional) aspect lets the trie confirm a match both forward and backward from the token position.The bidiTrieMatchExtra callback src/js/static-net-filtering.js542-552 is invoked by BidiTrieContainer when a trie node matches, and it runs additional filter logic for the full filter unit.
src/js/static-net-filtering.js537-538
Two module-level HNTrieContainer instances (from src/js/hntrie.js) are used:
| Instance | Purpose |
|---|---|
origHNTrieContainer | Trie for from= (origin) domain options |
destHNTrieContainer | Trie for to= (destination) domain options |
HNTrieContainer is optimized for hostname suffix matching — e.g., matching example.com against a filter that specifies domain=example.com or a parent domain.
Sources: src/js/static-net-filtering.js537-554
Filters are partitioned into buckets keyed by a token hash. A token is a short (up to MAX_TOKEN_LENGTH = 7 characters) lowercase alphanumeric substring extracted from the filter pattern at a position where a literal sequence must appear. This dramatically reduces the number of filters evaluated per request.
Special token hash constants src/js/static-net-filtering.js234-241:
| Constant | Meaning |
|---|---|
NO_TOKEN_HASH | Filter has no tokenizable part; always evaluated |
DOT_TOKEN_HASH | Filter is a pure hostname (stored in FilterHostnameDict) |
ANY_TOKEN_HASH | Filter applies to any URL |
ANY_HTTPS_TOKEN_HASH | Filter applies to any HTTPS URL |
ANY_HTTP_TOKEN_HASH | Filter applies to any HTTP URL |
EMPTY_TOKEN_HASH | Sentinel for empty patterns |
INVALID_TOKEN_HASH | Filter cannot be stored |
Diagram: Token dispatch in the match pipeline
Sources: src/js/static-net-filtering.js230-241
The match pipeline avoids per-call allocation by writing request properties into module-level short-lived registers before evaluating any filters. All match() methods read these directly.
src/js/static-net-filtering.js248-312
| Register | Type | Content |
|---|---|---|
$requestMethodBit | number | Bitmask for HTTP method (GET, POST, …) |
$requestTypeValue | number | Integer type from typeNameToTypeValue |
$requestURL | string | Lowercased request URL |
$requestURLRaw | string | Original-case request URL |
$requestHostname | string | Hostname of the request |
$requestAddress | string | IP address if available |
$docHostname | string | Hostname of the document (origin) |
$docDomain | string | eTLD+1 of the document |
$tokenBeg | number | Start offset of current token in $requestURL |
$patternMatchLeft | number | Left boundary of current pattern match |
$patternMatchRight | number | Right boundary of current pattern match |
$isBlockImportant | boolean | Set to true when FilterImportant.match() fires |
Two lazy-computed entity objects $docEntity and $requestEntity src/js/static-net-filtering.js261-290 compute the wildcard entity string (e.g., google.*) from the hostname, caching the result per hostname to avoid recomputation.
$httpHeaders src/js/static-net-filtering.js292-311 provides lazy header lookup for $header= filters.
Sources: src/js/static-net-filtering.js248-312
src/js/static-net-filtering.js783-915
These three classes handle plain (non-wildcard) string patterns. All three store the pattern in bidiTrie and record the tokenBeg offset (the distance from the start of the pattern to where the token starts).
FilterPatternPlain — token is at offset 0 in pattern.FilterPatternPlain1 — token is at offset 1.FilterPatternPlainX — token is at an arbitrary offset.match() computes left = $tokenBeg - tokenBeg and calls bidiTrie.startsWith(left, ...). This is the hot path for the most common filter type.
src/js/static-net-filtering.js919-1017
For patterns containing wildcards (*) or separator characters (^) with anchors. On first match, the pattern is compiled to a RegExp via restrFromGenericPattern() and stored in filterRefs. The regex is then tested against $requestURL. Marked isSlow = true to indicate it bypasses the fast trie path.
src/js/static-net-filtering.js1213-1300
Handles /regex/ patterns. The regex string is stored in bidiTrie; the compiled RegExp is stored lazily in filterRefs. Tests against $requestURLRaw (preserves case). Also marked isSlow = true.
src/js/static-net-filtering.js1021-1114
FilterAnchorHnLeft implements the || hostname anchor. It caches the start and end offsets of the hostname in the URL haystack across consecutive calls (invalidated when $requestHostname.length changes). FilterAnchorHn extends it to additionally verify the match ends exactly at the hostname boundary (^).
Not shown in the visible excerpt but referenced at src/js/static-net-filtering.js670-724 This collection class holds multiple filter units that must all match (logical AND). A complex filter like ||example.com^$third-party,script would be represented as a FilterCompositeAll containing separate pattern, anchor, party, and type units.
Diagram: Filter class registration and runtime dispatch
Sources: src/js/static-net-filtering.js565-595
The filterMatch(idata) function src/js/static-net-filtering.js594 is the universal dispatch point — it reads the fid from filterData[idata+0] and calls the corresponding class's match().
Additional dispatchers follow the same pattern:
| Dispatcher | Purpose |
|---|---|
filterGetClass(idata) | Returns the class object for the unit |
filterHasOriginHit(idata) | Checks for origin domain hit |
filterGetDomainOpt(idata, out) | Extracts from= option value |
filterGetRegexPattern(idata, out) | Extracts regex pattern string |
filterIsBidiTrieable(idata) | Whether the pattern can be stored in bidiTrie |
filterToBidiTrie(idata) | Returns {i, n, itok} for trie insertion |
filterMatchAndFetchModifiers(idata, env) | Matches and collects modifier values |
filterGetModifierType(idata) | Returns the MODIFIER_TYPE_* constant |
filterLogData(idata, details) | Populates log details |
dnrRuleFromCompiled(args, rule) | Emits a DNR rule for MV3 |
Sources: src/js/static-net-filtering.js590-658
The fully-initialized SNFE state is serialized (a "selfie") to avoid reprocessing filter lists on every startup. The selfie round-trips the two storage arrays.
src/js/static-net-filtering.js501-533
| Function | Direction | Data |
|---|---|---|
filterDataToSelfie() | Save | Returns filterData.subarray(0, filterDataWritePtr) |
filterDataFromSelfie(selfie) | Restore | Assigns filterData = selfie, sets filterDataWritePtr |
filterRefsToSelfie() | Save | Returns filterRefs.slice(0, filterRefsWritePtr) |
filterRefsFromSelfie(selfie) | Restore | Copies entries back into filterRefs |
The bidiTrie and HN tries also have their own toSelfie/fromSelfie methods in their respective modules. The FilterContainer class coordinates all of these into a single selfie object stored via cachestorage. The compiledMagic field (referenced in the comment at src/js/static-net-filtering.js558-563) acts as a version guard — if the filter class registration order changes, the magic number changes and the selfie is invalidated.
Sources: src/js/static-net-filtering.js501-533 src/js/static-net-filtering.js556-563
The LogData class src/js/static-net-filtering.js353-431 reconstructs the human-readable filter string from a matched filter unit for display in the logger UI (see Logger UI and Diagnostics).
Its constructor calls filterLogData(iunit, logData) which dispatches to each class's logData() method, collecting pattern fragments, regex strings, and option names. The assembled fields are:
| Field | Content |
|---|---|
result | 1 = blocked, 2 = allowed |
source | Always 'static' for SNFE matches |
tokenHash | The token hash; isUntokenized() and isPureHostname() are convenience checks |
raw | Reconstructed filter text (e.g., `@@ |
regex | Equivalent regex string for the pattern |
reason | Optional explanation string if set by the filter |
Sources: src/js/static-net-filtering.js353-431
The DomainOptIterator class src/js/static-net-filtering.js1446-1480 is a reusable iterator for parsing the pipe-separated values in from= / domain= options (e.g., domain=example.com|~other.com). A singleton domainOptIterator is reused throughout filter compilation via domainOptIterator.reset(domainOpt) to avoid allocation.
The compileDomainOpt function src/js/static-net-filtering.js1486 classifies domain option entries into hostname hits, hostname misses, entity hits, entity misses, and regex entries, then selects the optimal filter class to represent them (FilterOriginHit, FilterOriginHitSet, etc.).
Sources: src/js/static-net-filtering.js1446-1486
| Symbol | File | Role |
|---|---|---|
FilterContainer | static-net-filtering.js | Top-level engine class; holds all buckets and drives matching |
filterData | static-net-filtering.js | Global Int32Array pool for all filter node data |
filterRefs | static-net-filtering.js | Global array pool for JS object references |
bidiTrie | static-net-filtering.js | BidiTrieContainer for string storage and pattern matching |
origHNTrieContainer / destHNTrieContainer | static-net-filtering.js | HNTrieContainer instances for domain option matching |
registerFilterClass(fc) | static-net-filtering.js | Assigns fid and registers a filter class |
filterFromCompiled(args) | static-net-filtering.js | Dispatches to the correct class's fromCompiled() |
filterMatch(idata) | static-net-filtering.js | Universal match dispatcher |
LogData | static-net-filtering.js | Reconstructs filter text for the logger |
typeNameToTypeValue | static-net-filtering.js | Maps filter option type names to realm bit values |
AstFilterParser | static-filtering-parser.js | Parses raw filter text into an AST before compilation |
CompiledListReader | static-filtering-io.js | Reads compiled filter lines fed to FilterContainer |
FilteringContext | filtering-context.js | Carries per-request properties into the engine |
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.