Benjamin Solum Benjamin Solum - 1 year ago 66
Javascript Question

Is it possible to proxy iframe sub-resources with service workers?

I have an iframe that relies on 3rd party resources. The iframe itself doesn't have a src, is not sandboxed, is filled with content via AJAX and its sub-resources (e.x. CSS, images) exist on a CDN on a different domain.

In the case of an outage, either ours or our clients, I was hoping to be able to switch the iframe's CSS to a local file from our domain. I'm trying to do this via the fetch event in our Service Worker:

self.addEventListener('fetch', event => {
const processEpubRequests = () => fetch(`/epubs/${event.request.url.split('epub-resource/')[1]}`);

.then(response => response.status >= 400 ? processEpubRequests(response) : response)
.then(response => response || fetch(event.request))

This works great for the AJAX requests for the content but the CSS doesn't seem to work. It shows up in the Network tab with the correct response, but it's like the iframe just ignores it.

Is it possible to handle iframe sub-resources this way?


I produced a Github pages demo to illustrate what I'm seeing.

Answer Source

Turns out there's a Chrome bug out there for this issue. There are also several related issues for Firefox.

However, we can sort of get around the issue by:

  1. Setting the iframe tag to a same origin dummy src.

<iframe src=".iframe"></iframe>

  1. Responding to the dummy src (if we're using one instead of an actual blank html file) in our service worker

if(event.request.url == `${self.location.origin}/.iframe`)
    new Response(`<!doctype html><title>i</title>`, {
      status: 200,
      headers: { "Content-Type": "text/html" }

  1. Instead of using contentDocument.write(), use doc.documentElement.innerHTML. This will NOT change the existing <html> tag and DOCTYPE in the iframe.