Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

serviceworker for iframes with srcdoc #765

Open
ConradIrwin opened this issue Oct 21, 2015 · 21 comments · May be fixed by whatwg/html#3725
Open

serviceworker for iframes with srcdoc #765

ConradIrwin opened this issue Oct 21, 2015 · 21 comments · May be fixed by whatwg/html#3725
Labels
Milestone

Comments

@ConradIrwin
Copy link

As I understand it <iframe seamless="seamless" sandbox="allow-same-origin" srcdoc="<img src='/example.png'/>"/> should load /example.png as if it was on the containing page.

To this end, I feel like the navigation should go via the parent page's service worker's fetch event.

Unfortunately this doesn't work in either Chrome or Firefox because the srcDoc has no document.URI, you can see the current behaviour here: https://cdn.rawgit.com/ConradIrwin/2194f982494ba943a4c0/raw/ec0a6d3ebe69e2953e10d049005065de85588fa0/iframe.html

I'm trying to understand if this is a deliberate feature "iframes with srcdoc should not inherit the parent service-worker under any circumstance", or an edge-case that wasn't considered.

My use-case is loading emails into an iframe, I'd like to be able to fetch resources in the emails using the service worker so that I can load attachments as inline images.

@annevk annevk modified the milestone: Version 1 Oct 27, 2015
@jakearchibald
Copy link
Contributor

F2F:

srcdoc iframes with allow-same-origin should link up to the parent's service worker. We need to double check about:blank.

It's likely this change would happen in HTML, and we need to consider other inherited state outside of serviceworker.

+@mikewest

@jungkees
Copy link
Collaborator

jungkees commented Nov 9, 2015

Filed an issue: whatwg/html#321 and made a PR: whatwg/html#322.

@wanderview
Copy link
Member

@jakearchibald
Copy link
Contributor

Pre F2F notes: doesn't look like there's anything to discuss here

@jungkees
Copy link
Collaborator

jungkees commented Jul 28, 2016

F2F: The behavior here has been decided: an iframe with srcdoc will get a controller from its parent. The thing left here is to sort out the spec text with other changes for client-creating and hooking into html: #870.

@jungkees
Copy link
Collaborator

Currently working on this. Process the iframe attributes algorithm is where it seems the logic should be added (or at least the parts related with this algorithm.)

Note: I strongly feel both about:blank (no matter whether it goes through fetch or not) and about:srcdoc should NOT have a controller. They are NOT able to match any registration, so should be considered in non-controlled state. (The active service worker of those documents' environment is null by default.) So, going back to the OP issue, only when sandbox="allow-same-origin" comes together with srcdoc="/* source */", the iframe should inherit its parent's active service worker, if one exists.

@wanderview
Copy link
Member

Note: I strongly feel both about:blank (no matter whether it goes through fetch or not) and about:srcdoc should NOT have a controller. They are NOT able to match any registration, so should be considered in non-controlled state. (The active service worker of those documents' environment is null by default.) So, going back to the OP issue, only when sandbox="allow-same-origin" comes together with srcdoc="/* source */", the iframe should inherit its parent's active service worker, if one exists.

Since about:blank iframes inherit the origin from the parent, I don't see why they shouldn't inherit the controller as well. Without this how can a page programmatically build an iframe DOM in an offline state? Elements added to the child frame wouldn't be intercepted.

@mkruisselbrink
Copy link
Collaborator

I'm kind of on the edge about about:blank inheriting a controller. It does seem somewhat weird if about:blank iframes wouldn't inherit the controller. But it also does seem a bit arbitrary, as in where do we draw the line. Should all same origin iframes that have a URL that can't possibly be in scope of a service worker inherit the controller from their parent (for example blob URLs)? But maybe that inconsistency isn't too bad, and about:blank iframes (and windows?) are probably used a lot more than blob URLs anyway.

@asutherland
Copy link

Taking a step back to the use-case (as a reformed HTML/JS email app developer myself), I think the scenario is that the page is embedding third-party content (emails, rich HTML "chat" messages, tweets, maybe ads when the ad-blocker wars get worse) and Service Workers provide a simple abstraction to control remote network access in a powerful way that the sandbox attribute and CSP do not and cannot. The alternative to using Service Workers in these cases is to use data documents and understand 100% of the semantics of the HTML nodes and CSS rules applied to them in order to re-write or block the remote network accesses depending on the goals[1].

I think it's worth asking whether it's more appropriate to create a logically distinct affordance like "sandboxfetch" to explicitly recognize this use-case and enable good hygiene rather than have it depend on a carefully defined spec grey-zone. There's been interest in ideas like this before, see the public-webappsec Jan 2016 discussion on "In-browser sanitization vs. a “Safe Node” in the DOM" and Feb 2016 follow-up thread.

The primary benefit from such an approach would be to enable clever use of ServiceWorkers with embedded third-party content without enabling a class of XSS "gotcha!" where malicious sandboxed content is able to leverage naive ServiceWorker implementations. With explicit "sandboxfetch", the ServiceWorker author has to opt-in to handling the logic rather than being surprised.

1: For the example of an email app, goals would be as follows, with https://github.com/cure53/DOMPurify a common implementation choice:

  • Display embedded attachments (via re-written "cid:" URI scheme or implicitly embedded via attachment type which had a synthetic HTML element injected).
  • Privacy: not loading remote resources like 1-pixel webbugs without explicit user approval.
  • Offline: display pre-cached or previously loaded external resources from local storage.

@jungkees
Copy link
Collaborator

jungkees commented Nov 17, 2016

To clarify the spec point of view first,

Since about:blank iframes inherit the origin from the parent, I don't see why they shouldn't inherit the controller as well. Without this how can a page programmatically build an iframe DOM in an offline state? Elements added to the child frame wouldn't be intercepted.

You're right. I was focusing only on the document's URL and registration matching perspective and missed the point that they inherit the origin. (I confirmed it by testing with the browsers a bit but am still looking for the specific steps in the specs that inherit the origin though. The part in HTML spec is https://html.spec.whatwg.org/#creating-a-new-browsing-context step 8.)

That said, the behavior should be somewhat opposite to what I said in my note above. So, iframes having their src set to non-http(s) URLs (i.e. including about:, blob:, etc.) or their srcdoc is set will inherit the parent's controller. But navigation matching still wins, so when a navigation goes through HTTP fetch the matched registration's active worker replaces the inherited active service worker. When sandbox attribute is set without allow-same-origin token, it won't get a controller (set to null, precisely).

But it also does seem a bit arbitrary, as in where do we draw the line. Should all same origin iframes that have a URL that can't possibly be in scope of a service worker inherit the controller from their parent (for example blob URLs)?

I think so. The way how they're dealt with is the same as the about:blank case (not reaching http fetch to get the resources), and the fact that those iframes inherit the origin seems like a basic premise that they should get the parent's controller.

@jungkees
Copy link
Collaborator

@asutherland,

I think the scenario is that the page is embedding third-party content

I think if the main resource to the iframe is a cross-origin resource in the first place, it should go with its own registration matching. So, I presume the use-case in the OP is loading a resource as a same origin iframe srcdoc document and expecting its subresources will be fetched through the inherited controller (and foreign fetch SWs if they're implemented and avaiable.)

I think it's worth asking whether it's more appropriate to create a logically distinct affordance like "sandboxfetch" to explicitly recognize this use-case and enable good hygiene rather than have it depend on a carefully defined spec grey-zone.

Assuming the use-cases you pointed out here are iframes loading third-party main resource (note that object tag falls back to network early), they should get their own controller by matching a registration rather than inheriting one. In this regard, I don't think this case poses any addtional threats. Am I misunderstanding any of your concerns here?

jungkees added a commit to jungkees/html that referenced this issue Nov 23, 2016
This adds steps to make clients that have creator browsing contexts to
inherit the active service worker from their creators. While they have
an initial inherited active service worker, if one exists, navigation
matching still always wins. So, if the navigation goes through HTTP
fetch, the inherited active service worker is replaced by the matched
result. Also, if an iframe has a sandbox attribute set without
allow-same-origin token, the inherited active service worker is set to
null.

Related issue: w3c/ServiceWorker#765.
jungkees added a commit to jungkees/html that referenced this issue Dec 9, 2016
This adds steps to make clients that have creator browsing contexts to
inherit the active service worker from their creators. While they have
an initial inherited active service worker, if one exists, navigation
matching still always wins. So, if the navigation goes through HTTP
fetch, the inherited active service worker is replaced by the matched
result. Also, if an iframe has a sandbox attribute set without
allow-same-origin token, the inherited active service worker is set to
null.

Related issue: w3c/ServiceWorker#765.
jungkees added a commit to jungkees/html that referenced this issue Jan 24, 2017
This adds steps to make clients that have creator browsing contexts to
inherit the active service worker from their creators. While they have
an initial inherited active service worker, if one exists, navigation
matching still always wins. So, if the navigation goes through HTTP
fetch, the inherited active service worker is replaced by the matched
result. Also, if an iframe has a sandbox attribute set without
allow-same-origin token, the inherited active service worker is set to
null.

Related issue: w3c/ServiceWorker#765.
jungkees added a commit to jungkees/html that referenced this issue Jul 4, 2017
This adds steps to make clients that have creator browsing contexts to
inherit the active service worker from their creators. While they have
an initial inherited active service worker, if one exists, navigation
matching still always wins. So, if the navigation goes through HTTP
fetch, the inherited active service worker is replaced by the matched
result. Also, if an iframe has a sandbox attribute set without
allow-same-origin token, the inherited active service worker is set to
null.

Related issue: w3c/ServiceWorker#765.
@yoavweiss
Copy link

Was there any progress made on this issue?

@wanderview
Copy link
Member

wanderview commented May 16, 2018

FWIW firefox now makes srcdoc frames inherit the parent's service worker controller. We have a WPT as well:

https://github.com/w3c/web-platform-tests/blob/a3a5824500bdf2515114c6653253a9d8d172d37a/service-workers/service-worker/about-blank-replacement.https.html#L167

jungkees added a commit that referenced this issue Aug 5, 2019
This change makes it clear that this behavior needs to be (and will be)
specified normatively in HTML Standard, and any future changes for Service
Workers will be incorporated into Service Workers Nightly. It also clarifies,
non-normatively, the behavior of how a service worker client's active service
worker is determined.

Issue: #765.
This moves the issue to the next milestone.
@isubasinghe
Copy link

Hey guys,
I had a problem which I believe is caused by this issue, it would be greatly appreciated if I could get some input on this bug I'm facing.

I use a 3rd party plugin which uses an iframe to render content, inside this iframe a srcdoc defines html including some assets to load (js libraries). In chrome 73, offline functionality is broken because the js libraries loaded in this iframe are not cached by the service worker ( I believe this to be the case anyway as it works fine on the latest chromium and firefox builds).

Are there any hacks to make this work in older versions of browsers?

Thanks 😄 !!!

jungkees added a commit that referenced this issue Aug 9, 2019
This change makes it clear that this behavior needs to be (and will be)
specified normatively in HTML Standard, and any future changes for Service
Workers will be incorporated into Service Workers Nightly. It also clarifies,
non-normatively, the behavior of how a service worker client's active service
worker is determined.

Issue: #765.
This moves the issue to the next milestone.
@jungkees
Copy link
Collaborator

jungkees commented Aug 9, 2019

Move this to the next milestone with 2183f5e. We'll work on the normative definition of the active service worker determination in HTML Standard and Service Worker Nightly.

@jungkees jungkees modified the milestones: Version 1, Version 2 Aug 9, 2019
@jungkees
Copy link
Collaborator

jungkees commented Aug 10, 2019

@isubasinghe,

In chrome 73, offline functionality is broken because the js libraries loaded in this iframe are not cached by the service worker ( I believe this to be the case anyway as it works fine on the latest chromium and firefox builds).

Do you mean the JS files loaded in the srcdoc iframe were not captured by the service worker even though the parent frame has a controlling service worker? And it happen only on or before Chrome 73? If so, this seems like a bug that has been already addressed in Chromium. The expected behavior is the parent frame's service worker serves loading the JS library files in the iframe srcdoc document.

/cc @mattto @SteveBeckerMSFT

@isubasinghe
Copy link

@jungkees

Do you mean the JS files loaded in the srcdoc iframe were not captured by the service worker even though the parent frame has a controlling service worker?

Yes, this is what I meant, I was expecting the offline functionality to work regardless of it being inside an iframe.

And it happen only on or before Chrome 73?

I have only tested on chrome 73, latest chromium and latest firefox builds. It works on latest Chromium and Firefox but not Chrome 73. Happy to test it in other versions if it would help you guys out.

Unfortunately, I'm expecting some users to be using older versions of chrome, so I was hoping for a workaround.

I had some ideas to figure out a hack around this bug but they did not yield any useful results.

@zkrige
Copy link

zkrige commented Sep 18, 2019

I'm seeing same problem in chrome75. Service workers are not working for iframe with no src attribute

@kevodwyer
Copy link

Much like the email client scenario outlined by @asutherland we have a web app that uses the combination of a writeable stream and service worker request interception to be able to download chunks of encrypted data, unencrypt client side and feed a html5 video/audio element with media (not disimiliar to streamsaver.js). It is trivial to extend to arbitrary supplied static html/css/js resources and have them ultimately rendered in a sandboxed iframe.

The POC currently only works when the sandbox element is set to allow-same-origin in order for the request interception to be available. Our problem is as outlined in the html5rocks article on sandboxed-iframes [1]
"If a page on https://example.com/ frames another page on the same origin with a sandbox that includes both the allow-same-origin and allow-scripts flags, then the framed page can reach up into the parent, and remove the sandbox attribute entirely." Not the sandbox guarantees we are looking for...
I am seeking comment on whether this use-case has been considered and is so, an idea on the roadmap to realise a iframe sandbox where resource requests can be intercepted without the allow-same-origin restriction.

[1] - https://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/

@Kle0s
Copy link

Kle0s commented Aug 18, 2022

Chrome 104, seems like iframes with srcdoc / src="about:blank" / no src set, still do not inherit the parent SW :/

@zefhemel
Copy link

zefhemel commented Oct 2, 2023

Current state seems to be that both Safari (tested 17.0) and Firefox (tested 118) have SWs enabled for iframes with srcdoc, just Chrome seems to be the hold out.

adamziel added a commit to WordPress/wordpress-playground that referenced this issue Oct 9, 2023
…ce worker (#668)

## What is this PR doing?

Patches the block editor to use a special ControlledIframe component
instead of a regular HTML "iframe" element. The goal is to make the
iframe use a plain HTTP URL instead of srcDoc, blob URL and other
variations.

Normally, the patch applied here would be a huge maintenance burden over
time. However, @ellatrix explores fixing the issue upstream [in the
Gutenberg
repo](#646).
Once her PR is merged, the patch here will only be needed for a known
and limited set of WordPress and Gutenberg versions and will not require
ongoing reconciliation with new WP/GB releases.

Fixes #646

## What problem is it solving?

In Playground, the editor iframe needs to be controlled by Playground's
service worker so it can serve CSS and other static assets. Otherwise
all the requests originating in that iframe will yield 404s.

However, different WordPress versions use a variety of iframe techniques
that result in a non-controlled iframe:

* 6.3 uses a binary blob URL and the frame isn't controlled by a service
worker
* <= 6.2 uses srcdoc had a null origin and the frame isn't controlled by
a service worker
* Other dynamic techniques, such as using a data URL, also fail to
produce a controlled iframe

HTTP URL src like src="/doc.html" seems to be the only way to create a
controlled iframe.

And so, this commit ensures that the block editor iframe uses a plain
HTTP URL regardless of the WordPress version.

Once WordPress/gutenberg#55152 lands, this will
just work in WordPress 6.4 and new Gutenberg releases.

## Testing Instructions

Run `npm run dev`

Then, confirm the inserter is nicely styled and there are no CSS-related
404s in the network tools.

Test the following editors:

* Post editor
http://localhost:5400/website-server/?url=/wp-admin/post-new.php
* Site editor
http://localhost:5400/website-server/?url=/wp-admin/site-editor.php
* For all supported WordPress versions
* With and without the Gutenberg plugin (`&plugin=gutenberg`)


## Related

* https://bugs.chromium.org/p/chromium/issues/detail?id=880768
* https://bugzilla.mozilla.org/show_bug.cgi?id=1293277
* w3c/ServiceWorker#765
* #42
* b7ca737
adamziel added a commit to WordPress/wordpress-playground that referenced this issue Oct 10, 2023
…ce worker (#668)

## What is this PR doing?

Patches the block editor to use a special ControlledIframe component
instead of a regular HTML "iframe" element. The goal is to make the
iframe use a plain HTTP URL instead of srcDoc, blob URL and other
variations.

Normally, the patch applied here would be a huge maintenance burden over
time. However, @ellatrix explores fixing the issue upstream [in the
Gutenberg
repo](#646).
Once her PR is merged, the patch here will only be needed for a known
and limited set of WordPress and Gutenberg versions and will not require
ongoing reconciliation with new WP/GB releases.

Fixes #646

## What problem is it solving?

In Playground, the editor iframe needs to be controlled by Playground's
service worker so it can serve CSS and other static assets. Otherwise
all the requests originating in that iframe will yield 404s.

However, different WordPress versions use a variety of iframe techniques
that result in a non-controlled iframe:

* 6.3 uses a binary blob URL and the frame isn't controlled by a service
worker
* <= 6.2 uses srcdoc had a null origin and the frame isn't controlled by
a service worker
* Other dynamic techniques, such as using a data URL, also fail to
produce a controlled iframe

HTTP URL src like src="/doc.html" seems to be the only way to create a
controlled iframe.

And so, this commit ensures that the block editor iframe uses a plain
HTTP URL regardless of the WordPress version.

Once WordPress/gutenberg#55152 lands, this will
just work in WordPress 6.4 and new Gutenberg releases.

## Testing Instructions

Run `npm run dev`

Then, confirm the inserter is nicely styled and there are no CSS-related
404s in the network tools.

Test the following editors:

* Post editor
http://localhost:5400/website-server/?url=/wp-admin/post-new.php
* Site editor
http://localhost:5400/website-server/?url=/wp-admin/site-editor.php
* For all supported WordPress versions
* With and without the Gutenberg plugin (`&plugin=gutenberg`)


## Related

* https://bugs.chromium.org/p/chromium/issues/detail?id=880768
* https://bugzilla.mozilla.org/show_bug.cgi?id=1293277
* w3c/ServiceWorker#765
* #42
* b7ca737
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
15 participants