5.0 KiB
Service Workers on file:// — Analysis & Options
The Problem
navigator.serviceWorker.register() on a file:// page rejects with:
"serviceWorker.register() must be called with a script URL whose protocol is either HTTP or HTTPS"
Where the Check Lives
The error message is generated inside WebKit's web process (the
JavaScript engine / WebCore layer), not in the WebKitGTK C API layer.
The check is in WebKit's ServiceWorkerContainer::register() C++ code
(in Source/WebCore/workers/service/ServiceWorkerContainer.cpp), which
validates the script URL protocol against a hard-coded list of
http and https.
This is not controllable via:
WebKitSettings(no setting for SW protocol allowlist)WebKitSecurityManager(only controls local/secure/cors/empty/no-access scheme classification — not SW registration eligibility)WebKitWebsiteDataManager(only controls the storage directory for SW registrations, not the protocol gate)
Options
Option A: Patch WebKit (fork / rebuild) — HIGH EFFORT
We could fork webkitgtk (or maintain a patch set) that removes or
relaxes the protocol check in ServiceWorkerContainer.cpp. This is the
only way to make navigator.serviceWorker.register() accept file://
URLs natively.
Pros:
- Fully native — JS code works unchanged
- SW lifecycle (install/activate/fetch events) works as designed
Cons:
- Requires maintaining a WebKit fork or patch set against Debian's
webkit2gtkpackage - Every WebKitGTK update requires re-applying the patch
- Build complexity — WebKit is ~35MB of system lib; rebuilding from source is heavy
- The SW spec assumes HTTP semantics (scope, update checks, fetch
interception) that don't map cleanly to
file://
Verdict: Too heavy for the benefit. Service Workers on file:// is a
niche use case.
Option B: Register file:// as a "secure" scheme — ALREADY DONE, DOESN'T HELP
We already call webkit_security_manager_register_uri_scheme_as_secure()
for file in src/main.c:850. This makes file:// origins treated as
"potentially trustworthy" for some purposes (like navigator.geolocation
or getUserMedia), but does not bypass the SW registration protocol
check — that check is a separate hard-coded http/https test in
WebCore.
Option C: Use a custom URI scheme instead of file:// — MODERATE EFFORT
Instead of loading local sites via file:///path/to/index.html, we could
register a custom scheme (e.g. local://) via
webkit_web_context_register_uri_scheme() that serves files from disk.
If we also register local:// as secure via WebKitSecurityManager, SW
registration might work — but only if WebKit's SW code checks
"potentially trustworthy origin" rather than hard-coding http/https.
This needs testing.
Pros:
- No WebKit fork needed
- We control the scheme handler entirely
- Could also solve the Cache API issue (Issue #5)
Cons:
- Changes the URL model — users see
local://instead offile:// - Relative path resolution may differ
- Still might not work if WebKit's SW check is truly hard-coded to
http/https(need to test) - Significant implementation effort (scheme handler, path mapping, security registration)
Verdict: Worth investigating if SW on local files becomes important.
The first step would be a quick test: register local:// as secure,
load a page, try navigator.serviceWorker.register().
Option D: JavaScript shim / polyfill — LOW EFFORT, PARTIAL
We could inject a JS shim that overrides navigator.serviceWorker.register
to do something useful on file:// — e.g., load the SW script as a Web
Worker instead, or implement a minimal fetch interceptor.
Pros:
- No WebKit changes
- We already inject JS shims (
window.nostr)
Cons:
- Not a real Service Worker — no
fetchevent interception, noinstall/activatelifecycle, noclientsAPI - Would only provide a subset of SW functionality
- Complex to implement convincingly
Verdict: Only useful if someone specifically needs SW-like behavior
on file:// and is willing to accept a polyfill.
Option E: Do nothing — RECOMMENDED
Service Workers are designed for HTTP/HTTPS origins. On file://:
- Web Workers work perfectly (tested ✅) — use those for background computation
- Shared Workers also work perfectly (tested ✅) — use those for cross-tab/cross-page shared background computation
- IndexedDB works perfectly (tested ✅) — use that for offline storage
- Cache API doesn't work (Issue #5) — but local files are already local, so caching is redundant
- fetch interception (the main SW use case) is less relevant when everything is local
The "deprecated web security" design goal is about cross-origin access (CORS/SOP), which works. Service Workers are a different concern — they're about offline web apps and PWA features, which are inherently HTTP-oriented concepts.
Verdict: Document the limitation and move on. If a specific use case
emerges that needs SW on file://, revisit Option C (custom scheme).