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

Improve clarity in link and style sheet resource fetching #3544

Closed
wants to merge 4 commits into from

Conversation

domenic
Copy link
Member

@domenic domenic commented Mar 7, 2018

  • Defines the critical subresources for CSS as @imported style sheets, including
    indirectly imported ones. This was previously defined nowhere; probably it
    should live in CSS, but for now it lives here.
  • Makes it clearer that the steps to obtain the resource are the default steps,
    which some link types override.
  • Adds explicit steps for fetching critical subresources, and ties those to the
    load/error events.
  • Uses fetch primitives like network error and ok status instead of vague
    language.
  • Makes it clearer how incorrect Content-Types for CSS generate error events, by
    defining the new "resource-specific fetch error" concept.
  • Makes it clearer that resources apply if and only if their main fetch
    succeeds. (Critical subresource fetches generate error events, but do not
    impact the "obtained successfully" or "apply" concepts.)

Fixes #3532.


Of these only the first is really a normative fix; the rest were present in the existing spec if you squint hard enough.


/infrastructure.html ( diff )
/links.html ( diff )
/semantics.html ( diff )

@domenic
Copy link
Member Author

domenic commented Mar 16, 2018

@bzbarsky @annevk review ping

source Outdated
@@ -2025,8 +2025,14 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
<ref spec=HTTP></p>

<p>A resource's <dfn>critical subresources</dfn> are those that the resource needs to have
available to be correctly processed. Which resources are considered critical or not is defined by
the specification that defines the resource's format.</p>
available to be correctly processed. Which resources are considered critical or not generally
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are generally*

source Outdated
stylesheets.</p>

<p class="&#x0058;&#x0058;&#x0058;">This definition should be moved to CSS, alongside more detail
around how they are fetched.</p>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be great if we could turn this into an issue link.

source Outdated
@@ -13612,38 +13621,66 @@ interface <dfn>HTMLLinkElement</dfn> : <span>HTMLElement</span> {
</ol>
</li>

<!--FETCH--><li><p><span data-x="concept-fetch">Fetch</span> <var>request</var>.</p></li>
<!--FETCH-->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should start dropping these now we have concept-fetch?

source Outdated
<ol>
<li><p>If <var>response</var> is a <span>network error</span>, or its <span
data-x="concept-response-status">status</span> is not an <span>ok status</span>, or it has a
<dfn>resource-specific fetch error</dfn>, then <span>queue a task</span> using the <span>DOM
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems a little COMEFROM?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How so? It's defining a concept which each resource is allowed to define; basically polymorphism.

source Outdated
resources. (For example, redirects will be followed and 404 responses will cause the external
resource to not be applied.)</p>
<li><p>Once the original fetch and all of the <span data-x="critical subresources">critical
subresource</span> fetches have completed (i.e. have reached the <span>process response
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i.e.,*

source Outdated
<code data-x="event-error">error</code> at the <code>link</code> element, and abort these
steps. The resource was not <span>obtained successfully</span>.</p></li>

<li><p>At this point, the resource has been <span>obtained successfully</span>.</p></li>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems wrong. I think this needs to be done as part of the task that is queued. Otherwise we update .sheet and other state too early, no?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THis whole step is inside of the task that is queued by https://fetch.spec.whatwg.org/#ref-for-process-response%E2%91%A0 , right?

<span>resource-specific fetch error</span>, then <span>queue a task</span> on the
<span>DOM manipulation task source</span> to <span data-x="concept-event-fire">fire an
event</span> named <code data-x="event-error">error</code> at the <code>style</code> element, and
abort these steps.</p></li>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be nice to abstract this error handling. Seems reasonable as a follow-up. The less duplication the better imo.

source Outdated
<p>The <span>task source</span> for these <span data-x="concept-task">tasks</span> is the <span>DOM
manipulation task source</span>.</p>
<li><p>Once all of the <span data-x="critical subresources">critical subresource</span> fetches
have completed (i.e. have reached the <span>process response done</span> phase), <span>queue a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i.e.,*

source Outdated
<span>same origin</span> as the <span>URL</span> of the external resource<!-- CVE-2010-0654 -->,
and the <span data-x="Content-Type">Content-Type metadata</span> of the external resource is not a
supported style sheet type, the user agent must instead assume it to be <code>text/css</code>.</p>
<p>For style sheet resources, a <span data-x="concept-response">response</span>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSS style sheet*

* Defines the critical subresources for CSS as @imported style sheets, including
  indirectly imported ones. This was previously defined nowhere; probably it
  should live in CSS, but for now it lives here.
* Makes it clearer that the steps to obtain the resource are the default steps,
  which some link types override.
* Adds explicit steps for fetching critical subresources, and ties those to the
  load/error events.
* Uses fetch primitives like network error and ok status instead of vague
  language.
* Makes it clearer how incorrect Content-Types for CSS generate error events, by
  defining the new "resource-specific fetch error" concept.
* Makes it clearer that resources apply if and only if their main fetch
  succeeds. (Critical subresource fetches generate error events, but do not
  impact the "obtained successfully" or "apply" concepts.)

Fixes #3532.
@domenic
Copy link
Member Author

domenic commented Apr 4, 2018

@annevk ready for another pass

source Outdated

<p>For CSS style sheets, we tentatively define here that their critical subresources are other
style sheets imported via <code data-x="">@import</code> rules, including those indirectly
imported by other imported stylesheets.</p>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style sheets*

source Outdated
<p class="&#x0058;&#x0058;&#x0058;">This definition is not fully interoperable; furthermore, some
user agents seem to count resources like background images or web fonts as critical subresources.
Ideally, the CSS Working Group should define this; see <a
href="https://github.com/w3c/csswg-drafts/issues/1088">w3c/csswg-drafts</a> to track progress on
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add 1088 to the link text in case we end up linking to more of their issues?

source Outdated
status</span>, or that has a <span>resource-specific fetch error</span>, then <span>queue a
task</span> using the <span>DOM manipulation task source</span> to <span
data-x="concept-event-fire">fire an event</span> named <code data-x="event-error">error</code>
at the <code>link</code> element, and abort these steps.</p></li>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the main problem here is that you queue another task. If something ran before that task but after the networking event it could observe sheet being non-null. I don't think that's reality in implementations.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right, good catch; I'll remove the second task queuing.

source Outdated
subresource</span> fetches have completed (i.e., have reached the <span>process response
done</span> task), <span>queue a task</span> using the <span>DOM manipulation task
source</span> to <span data-x="concept-event-fire">fire an event</span> named <code
data-x="event-load">load</code> at the <code>link</code> element.</p></li>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

source Outdated
<li><p>If <var>response</var>'s <span data-x="Content-Type">Content-Type metadata</span> is
<code>text/css</code>, return false.</p></li>

<li><p>If the document has been set to <span>quirks mode</span>, and <var>response</var>'s <span
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this document come from?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jeez, now we have a can of worms regarding the question of what happens if you move between a quirks and non-quirks document while the response is coming in. Please hold while I write some tests...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least in Gecko, I believe anything that moves the <link> in the DOM drops the old request and starts a new one. Certainly if the move is across documents. The document affects not only the MIME type bit but also the encoding you have to use to decode the bytes, various security properties, etc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, in the processing of the response it looks like there's a similar check in the spec already, so maybe it's already accounted for.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so I wrote up some tests. web-platform-tests/wpt#10350

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the best model is the one depicted in those tests, where you get an error or load event based on whether the document you were in at the time the fetch started was quirks or no-quirks. Do you agree, @bzbarsky? Firefox doesn't pass all of the tests; in particular for the last test it hits the "load event must not be fired yet" assert.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have to pretty carefully dig though exactly what Gecko does here, but in terms of expected behavior... I actually don't know what the behavior should be if loads are canceled before completing.

Furthermore, I'm not sure that any spec says that any loads should start in this case before the quirksDocument.body.appendChild(link) call...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing is, nothing in the spec suggests loads should be canceled. Just that, once the load finishes, the stylesheet should not be applied, if another load has been started. So the tests above support firing the appropriate error/load event regardless if another load has been started.

Furthermore, I'm not sure that any spec says that any loads should start in this case before the quirksDocument.body.appendChild(link) call...

Well, before that we have noQuirksDocument.body.appendChild(link);, which is one of the relevant mutations which would cause a load, right? It becomes browsing-context connected.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It becomes browsing-context connected.

Ah, looks like this is much better-defined than it used to be.

That said, nothing in the spec suggests the loads should be canceled, but that might be a bug in the spec. What do UAs do? I think it would be pretty surprising for web developers to have these racing loads and be getting a "load" event when the sheet is not ready to be applied yet!

This will also fix #3610
@domenic
Copy link
Member Author

domenic commented Apr 6, 2018

@bzbarsky, also, given the discussion in w3c/csswg-drafts#1088, I wonder if we should change course and just get rid of the "critical subresources" concept entirely? At least for CSS? It certainly would be simpler.

@bzbarsky
Copy link
Contributor

bzbarsky commented Apr 7, 2018

and just get rid of the "critical subresources" concept entirely?

What would that mean in terms of observable behavior? What do authors want to happen?

@domenic
Copy link
Member Author

domenic commented Apr 9, 2018

Sorry, upon re-reviewing the thread, let's scratch that suggestion. If everyone interoperably delays the load event for at least top-level @imports, we probably shouldn't move away from that.

@bzbarsky
Copy link
Contributor

bzbarsky commented Apr 9, 2018

Note that the things that browsers delay for and the things that might lead to error instead of load may not be the same set.

That is, I expect even browsers that don't let non-toplevel imports make the load error out still wait for them before firing load... Testcase:

<!DOCTYPE html>
<script>
  var start = performance.now();
</script>
<link rel="stylesheet"
      href="data:text/css,@import url(&quot;data:text/css,@import url('http://software.hixie.ch/utilities/cgi/test-tools/delayed-file?pause=4&mime=text%2Fhtml&text=NOT+A+STYLESHEET');&quot;)"
      onload="alert('loaded in: ' + (performance.now() - start))"
      onerror="alert('errored in: ' + (performance.now() - start))">

and that shows "loaded in" followed by a 4+s time in Chrome. So it's waiting for that innermost import, but then ignoring that it failed.

@domenic
Copy link
Member Author

domenic commented Apr 9, 2018

It's amazing what you can inline into a single-file test case...

To me a reasonable model would be that error events only fire if the top-level sheet itself fails to come over the network. Any ideas if that is consistent with browsers at all? (I can write tests if you haven't already.) It's certainly not allowed by the current spec, which says that if any critical subresource fails, you must fire error and must not fire load.

It does seem like this whole area needs a more comprehensive test suite. I guess I'm up for taking over that enterprise. You have some tests already written, right? Can you point me to them?

@bzbarsky
Copy link
Contributor

bzbarsky commented Apr 9, 2018

It's amazing what you can inline into a single-file test case...

Yeah... arguably there's all sorts of violations of same-origin policy in there. I wonder whether that affects anyone's behavior...

You have some tests already written, right? Can you point me to them?

Sure. There's https://searchfox.org/mozilla-central/source/layout/style/test/test_bug1443344-2.html and https://searchfox.org/mozilla-central/source/layout/style/test/test_bug1443344-1.html (not testharness tests, but should be pretty self-explanatory and not too bad to port to testharness).

There's also https://searchfox.org/mozilla-central/source/layout/style/test/test_load_events_on_stylesheets.html which I modified in the course of making the changes in https://bugzilla.mozilla.org/show_bug.cgi?id=1442126

Plus the bits I already posted in #3532

@gsnedders
Copy link
Member

@domenic web-platform-tests/wpt#5525 also has some tests for this

domenic pushed a commit that referenced this pull request Jan 17, 2019
* Introduce new link loading infrastructure, specifically algorithms to
  fetch and process linked resources that are overridable by the
  individual link types. This replaces the previous "obtain the
  resource" algorithms with something more structured and rigorous.
* Specify the order in which style sheets are removed, created/added,
  their corresponding load/error events are fired, and scripting is
  unblocked from a loading style sheet.
* Replace "style sheet done" flag with Document's "script-blocking style
  sheet counter", which works in tandem with the "contributes a
  script-blocking style sheet" conditions, which replaces the definition
  of "a style sheet that is blocking scripts".
* Change <link> load/fire events to be fired from tasks queued on the
  networking task source, instead of the DOM manipulation task source.
* Handle much of what #3544 set out to do, minus defining and explicitly
  fetching a style sheet's critical subresources.

Fixes #3610.

Tests: web-platform-tests/wpt#14899
mustaqahmed pushed a commit to mustaqahmed/html that referenced this pull request Feb 15, 2019
* Introduce new link loading infrastructure, specifically algorithms to
  fetch and process linked resources that are overridable by the
  individual link types. This replaces the previous "obtain the
  resource" algorithms with something more structured and rigorous.
* Specify the order in which style sheets are removed, created/added,
  their corresponding load/error events are fired, and scripting is
  unblocked from a loading style sheet.
* Replace "style sheet done" flag with Document's "script-blocking style
  sheet counter", which works in tandem with the "contributes a
  script-blocking style sheet" conditions, which replaces the definition
  of "a style sheet that is blocking scripts".
* Change <link> load/fire events to be fired from tasks queued on the
  networking task source, instead of the DOM manipulation task source.
* Handle much of what whatwg#3544 set out to do, minus defining and explicitly
  fetching a style sheet's critical subresources.

Fixes whatwg#3610.

Tests: web-platform-tests/wpt#14899
mustaqahmed pushed a commit to mustaqahmed/html that referenced this pull request Feb 15, 2019
* Introduce new link loading infrastructure, specifically algorithms to
  fetch and process linked resources that are overridable by the
  individual link types. This replaces the previous "obtain the
  resource" algorithms with something more structured and rigorous.
* Specify the order in which style sheets are removed, created/added,
  their corresponding load/error events are fired, and scripting is
  unblocked from a loading style sheet.
* Replace "style sheet done" flag with Document's "script-blocking style
  sheet counter", which works in tandem with the "contributes a
  script-blocking style sheet" conditions, which replaces the definition
  of "a style sheet that is blocking scripts".
* Change <link> load/fire events to be fired from tasks queued on the
  networking task source, instead of the DOM manipulation task source.
* Handle much of what whatwg#3544 set out to do, minus defining and explicitly
  fetching a style sheet's critical subresources.

Fixes whatwg#3610.

Tests: web-platform-tests/wpt#14899
@annevk
Copy link
Member

annevk commented May 30, 2020

Is this obsolete @domenic?

@domenic
Copy link
Member Author

domenic commented Jun 1, 2020

Yeah, it looks like @domfarolino's work has done pretty much everything this was hoping to accomplish.

There's still some messiness around stylesheet links, e.g. I think

Quirk: If the document has been set to quirks mode, has the same origin as the URL of the external resource, and the Content-Type metadata of the external resource is not a supported style sheet type, the user agent must instead assume it to be text/css.

should be integrated into the processing model (like this PR tried to do), and of course we have the confusion with CSSOM and HTML both attempting to fetch the stylesheet. But this seems reasonable for now.

@domenic domenic closed this Jun 1, 2020
@domenic domenic deleted the link-loading-clearer branch June 1, 2020 14:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

Something needs to define the actual behavior of load/error events on <link>
4 participants