The Redirect Engine manages local substitute resources that replace blocked remote resources. When uBlock Origin blocks a network request using a redirect rule (e.g., ||example.com/tracker.js$script,redirect=noop.js), this engine provides the replacement content, either as a data URI or as a web accessible resource URL.
For information about scriptlet injection (JavaScript code that runs in page context), see Scriptlet Filtering Engine. For general extended filtering coordination, see Static Extended Filtering.
The Redirect Engine consists of two main classes that manage redirect resources and their metadata:
Sources: src/js/redirect-engine.js157-471
Each redirect resource is represented by a RedirectEntry object containing the resource data and metadata:
| Property | Type | Purpose |
|---|---|---|
mime | string | MIME type (e.g., text/javascript) |
data | string | Resource content (raw or base64) |
warURL | string | Web accessible resource path |
params | array | URL parameters to extract from fctxt |
requiresTrust | boolean | Whether resource requires trusted context |
world | string | Execution context: 'MAIN' or 'ISOLATED' |
dependencies | array | Other resources this depends on |
The class provides two key methods:
toURL(fctxt, asDataURI) - Converts entry to URL (data URI or WAR URL)toContent() - Extracts raw content from data URI encodingSources: src/js/redirect-engine.js76-152
The RedirectEngine singleton (exported as redirectEngine) maintains two Map instances: resources mapping canonical names to RedirectEntry objects, and aliases mapping alternative names to canonical names. A modifyTime timestamp is updated via Date.now() each time resources are modified. The scriptlet engine compares its cache's reset time against modifyTime to detect stale entries.
Sources: src/js/redirect-engine.js157-168
Resources are loaded from three sources during initialization:
Sources: src/js/redirect-engine.js311-399 src/js/redirect-engine.js226-309
Scriptlet functions are dynamically imported from /js/resources/scriptlets.js using a dynamic import() call. Each entry in the builtinScriptlets array is processed: fn.toString() is called to obtain the function source, mimeFromName() infers the MIME type from the .js extension, and RedirectEntry.fromDetails() constructs the entry. Any aliases array on the scriptlet descriptor registers entries in the aliases map. The modifyTime is updated after all scriptlets are loaded.
Sources: src/js/redirect-engine.js316-335
Web accessible resources (images, media files) are registered by the internal store() function, which reads resource metadata from the redirectableResources map (imported from redirect-resources.js) and sets warURL to /web_accessible_resources/${name}. Binary blobs are converted to base64 data URIs via FileReader.readAsDataURL(). Text files have their top comment block stripped by removeTopCommentBlock(). Each resource's alias field from redirectableResources is registered in the aliases map.
Sources: src/js/redirect-engine.js338-396
Resources can also be defined in filter lists using this format:
/// resource-name.js
/// alias alternative-name
/// world ISOLATED
/// dependency other-resource.js
// Resource content follows
(function() {
// JavaScript code
})();
The parser handles both modern format (starting with /// name) and legacy format (whitespace-separated name and MIME type).
Sources: src/js/redirect-engine.js226-309
The primary interface for consuming redirect resources is token-based resolution. The diagram below shows all four public query methods and the internal resolution path used by tokenToURL.
Token resolution public API — RedirectEngine
Sources: src/js/redirect-engine.js171-195
Tokens can have two formats:
noop.js — prefers WAR URL if available%noop.js — always returns a data URI regardless of warURLThe % prefix is detected via token.charCodeAt(0) === 0x25 in hasToken() and passed as asDataURI = true to toURL().
Sources: src/js/redirect-engine.js188-194
RedirectEntry.toURL(fctxt, asDataURI) selects the URL format using the following priority:
warURL is defined, asDataURI is false, fctxt is an object, and the request type is not 'xmlhttprequest'. A secret= query parameter (from warSecret()) and any declared params extracted from fctxt are appended.entry.data === ''; the MIME type is looked up from typeToMimeMap using fctxt.type.entry.data and entry.mime for all other cases.XMLHttpRequest Restriction: XHR requests always receive a data URI to prevent extension ID leakage through XMLHttpRequest.responseURL. See src/js/redirect-engine.js87-93
Sources: src/js/redirect-engine.js95-133
The engine maintains two module-level maps for MIME type resolution.
extToMimeMap — Extension to MIMEFile extension is extracted from the resource name by mimeFromName() and looked up in extToMimeMap:
| Extension | MIME type |
|---|---|
css | text/css |
fn | fn/javascript (internal) |
gif | image/gif |
html | text/html |
js | text/javascript |
json | application/json |
mp3 | audio/mp3 |
mp4 | video/mp4 |
png | image/png |
txt | text/plain |
xml | text/xml |
Sources: src/js/redirect-engine.js27-39
typeToMimeMap — Request Type to MIMEFor empty redirects (entry.data === ''), typeToMimeMap provides the MIME type by fctxt.type so an appropriate empty data: URI can be returned:
| Request type | MIME type |
|---|---|
main_frame | text/html |
other | text/plain |
script | text/javascript |
stylesheet | text/css |
sub_frame | text/html |
xmlhttprequest | text/plain |
Sources: src/js/redirect-engine.js41-48 src/js/redirect-engine.js119-124
Web accessible resources (WAR) allow extension resources to be loaded by web pages. The redirect engine generates WAR URLs with security measures:
A short secret is appended to WAR URLs to prevent unauthorized access:
The warSecret is provided by the vAPI layer and rotates periodically. The secret prevents malicious sites from detecting the extension by probing for WAR URLs.
Sources: src/js/redirect-engine.js62-68 src/js/redirect-engine.js103-104
Resources can declare parameters to extract from the filtering context:
This allows resources to be customized based on the request context (e.g., passing the blocked URL to a placeholder image).
Sources: src/js/redirect-engine.js105-111
For a request blocked with $redirect=noop.js, the generated URL might be:
chrome-extension://[extension-id]/web_accessible_resources/noop.js?secret=abc123
Sources: src/js/redirect-engine.js95-117
The redirect engine is used by multiple filtering components:
Network filters with the redirect= option use the redirect engine:
||example.com/tracker.js$script,redirect=noop.js
The static net filtering engine calls redirectEngine.tokenToURL() to get the replacement URL.
Sources: src/js/scriptlet-filtering.js34
The scriptlet filtering engine imports the redirect engine as reng and monitors its modifyTime:
When resources are reloaded, modifyTime is updated, causing the scriptlet cache to be cleared.
Sources: src/js/scriptlet-filtering.js34 src/js/scriptlet-filtering.js264-266
RedirectEngine.contentFromName(name, mime) is the interface used by the scriptlet engine to retrieve scriptlet source. It resolves aliases, checks that the entry's MIME type starts with the requested mime string, and returns an object containing:
js — raw source text (extracted by entry.toContent())world — 'MAIN' or 'ISOLATED'dependencies — a copy of entry.dependenciesSources: src/js/redirect-engine.js209-219
RedirectEngine.tokenToDNR(token) is called by the MV3 ruleset generator. It resolves aliases then returns entry.warURL if present, or undefined if the resource has no web-accessible URL and therefore cannot be expressed as a DNR redirect action.
Sources: src/js/redirect-engine.js181-186
The engine provides methods to query available resources:
getResourceDetails()Returns a sorted array of [name, descriptor] pairs covering all canonical resources and their aliases. The token 'none' is always included as a special entry. This is used by the UI to display available resources in filter creation wizards.
| Property | Description |
|---|---|
canInject | Whether resource can be injected as scriptlet |
canRedirect | Whether resource can be used in redirect rules |
aliasOf | Empty string if canonical, otherwise points to canonical name |
extensionPath | WAR path if available |
Sources: src/js/redirect-engine.js401-423
getTrustedScriptletTokens()Returns an array of token names (without the .js extension) for scriptlets that have requiresTrust === true, no warURL, and a string data field. Aliases pointing to these scriptlets are also included. Trusted scriptlets can only be activated from the user's own filter rules, not from third-party filter lists.
Sources: src/js/redirect-engine.js425-443
Resources can be serialized to cache storage for fast startup without re-fetching.
selfieFromResources(storage)Writes the aliases and resources maps together with RESOURCES_SELFIE_VERSION (currently 7) to cache under the key RESOURCES_SELFIE_NAME ('selfie/redirectEngine/resources').
Sources: src/js/redirect-engine.js70-71 src/js/redirect-engine.js445-451
resourcesFromSelfie(storage)Reads the cache entry, validates the version and map types, then restores aliases and resources. Each plain object in the restored resources map is converted back to a RedirectEntry instance via RedirectEntry.fromDetails(). Returns false if the selfie is absent or version-mismatched, forcing a full reload.
Sources: src/js/redirect-engine.js453-466
invalidateResourcesSelfie(storage)Removes the selfie cache entry. Called when filter lists are updated so that resources are reloaded fresh on the next startup.
Sources: src/js/redirect-engine.js468-470
RedirectEntry.toURL() lazily encodes entry.data into a data: URI on first call, then caches the result back into entry.data. If the MIME type string does not contain ; (no encoding qualifier), the raw text is base64-encoded with btoa(). If a ; is present, the data is assumed to be pre-encoded and is used as-is after the comma.
Sources: src/js/redirect-engine.js125-131
RedirectEntry.toContent() performs the reverse: it strips the data:mime[;base64], prefix and, if the ;base64 marker is present, decodes the payload with atob(). This mutates entry.data in place.
Sources: src/js/redirect-engine.js135-145
Resources in filter lists follow this format:
/// resource-name.js
/// alias alternative-name
/// world ISOLATED
/// dependency other-resource.js
// Resource content
(function() {
// Code here
})();
Note: Two blank lines are required after the resource content to signal the end.
| Directive | Purpose | Example |
|---|---|---|
/// alias | Define alternative name | /// alias noop |
/// world | Set execution context | /// world ISOLATED |
/// dependency | Declare dependency | /// dependency core-lib.js |
Sources: src/js/redirect-engine.js260-302
resource-name.js text/javascript
(function() {
// Code here
})();
The legacy format uses whitespace-separated name and MIME type. The modern format with /// directives is preferred.
Sources: src/js/redirect-engine.js247-257
The redirect engine is exported as a singleton:
This allows it to be imported and used throughout the codebase:
Sources: src/js/redirect-engine.js475-477
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.