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

HTTP responses should be able to indicate that a resource cannot be prefetched/prerendered #138

Closed
jeremyroman opened this issue Feb 9, 2022 · 39 comments
Labels
affects-compat Resolution of the issue is likely to affect backward or forward compatibility. prefetch Related to prefetching. prerendering Related to prerendering.

Comments

@jeremyroman
Copy link
Collaborator

jeremyroman commented Feb 9, 2022

We need to settle on how servers should indicate in a response that the response is not available right now but that the client should refetch the resource when it actually needs it, because it is likely to succeed then.

I also think there are going to be cases where the main resource isn't prefetchable but related resources (subresources) are, so it would be useful if a response can simultaneously identify such subresources. This is a little messy to do with 400-599 responses without some work, because it isn't clear whether those links apply to the requested resource or to the returned error.

In any case, servers should be careful about the cache lifetime of such responses. If they're different depending on Sec-Purpose, they might need to send a Vary response header to indicate this, if it would otherwise be cacheable.

New HTTP status code

Define a new HTTP status code, along these lines:

309 Not Ready
The resource is not available and should be retried when circumstances change. This response contains a null response body, but may contain header fields which describe the identified resource (e.g., Link headers identifying related resources).
This response is not heuristically cacheable.

And then specify that prefetch/prerender send a Sec-Purpose request header field and interprets a Not Ready response as indicating the prefetch cannot proceed but we might fetch subresources. This requires a minor edit to Fetch to specify how this status code is treated there.

This is very explicit and semantically correct, but the IETF/HTTPWG process may be long and involved. Still, we could ask HTTPWG what they think.

Sample exchange:

GET / HTTP/1.1
Sec-Purpose: prefetch

309 Not Ready
Link: </style.css>; as="style"; rel="preload", </app.js>; as="script"; rel="preload"

New HTTP response header field

Define a new response header field, along these lines:

Prefetch-Control
If present and contains the structured token discard-body, the response body, if any, is not valid for prefetch use. The client should instead issue a new request when the body is required. However, specified other response header fields, including Link, apply to the requested resource.

Advise clients to serve such a response when a response body suitable for prefetch with the parameters indicated in the Sec-Purpose request header field is not available. Since the body will be discarded, this should be a 204 No Content response, but servers may serve another status.

The generic name anticipates the possibility of using this as an extension point for varying the maximum prefetch lifetime or similar things in the future, if required, and is similar to Cache-Control.

Sample exchange:

GET / HTTP/1.1
Sec-Purpose: prefetch

204 No Content
Prefetch-Control: discard-body
Link: </style.css>; as="style"; rel="preload", </app.js>; as="script"; rel="preload"

This is slightly awkward semantically, but not dramatically so. Web browsers have felt more free to introduce new header fields than status codes, so this path is more well-worn. This also opens the possibility of doing scanning for an equivalent <meta> tag in the response body in the future.

Using 204 No Content

Define a 204 No Content in response to Sec-Purpose: prefetch requests to indicate that the response body is unavailable, but that response header fields which describe the resource might still be present. This is analogous to a 204 response to a PUT request, or to a 304 response to a conditional GET (but note that a separate status code was used for the latter).

Sample exchange:

GET / HTTP/1.1
Sec-Purpose: prefetch

204 No Content
Link: </style.css>; as="style"; rel="preload", </app.js>; as="script"; rel="preload"

Error status codes

Define that all errors 400-599 force prefetching and prerendering to fail.

This has the advantage that we get a retry of content which has failed to load but which might have a non-error response when the user actually navigates (e.g., a 503 Service Unavailable response but the server became available minutes later). However, it slightly muddles the meaning of these responses and makes prefetching/prerendering resources which do have such statuses impossible. It may also lead to authors seeing elevated error rates.

Sample exchange:

GET / HTTP/1.1
Sec-Purpose: prefetch

403 Forbidden
Link: </style.css>; as="style"; rel="preload", </app.js>; as="script"; rel="preload"
Content-Type: text/html; charset=utf8

<!DOCTYPE html>
Prefetch is forbidden.

Still respecting Link hints here, if we wanted to do so, would be slightly awkward because it's not obvious whether they describe the error resource or the indicated resource. We could consider extending Link to disambiguate, or if we restrict to 204 responses only, specifying that this is the meaning of Link header fields in 204 responses to Sec-Purpose: prefetch requests.

Respond to cache behavior

Declare that only resources which are cacheable to some extent are eligible for prefetch and prerender, and authors should reject prefetch/prerender by returning a non-cacheable response.

This means that some resources which are extremely variable will avoid prefetching/prerendering due to their existing headers. However it is even more awkward a fit for prerendering than it is for prefetching (because prerendering resembles an HTTP cache much less), and would make such responses rejecting prefetch harder to cache (though CDN-Cache-Control would still make it possible).

Still respecting Link hints here, if we wanted to do so, would be slightly awkward because it's not obvious whether they describe the error resource or the indicated resource. We could consider extending Link to disambiguate.

Sample exchange:

GET / HTTP/1.1
Sec-Purpose: prefetch

204 No Content
Cache-Control: no-store, private
@jeremyroman
Copy link
Collaborator Author

@noamr @domenic @yoavweiss @spelchat
These are basically the options, right? What are people's inclinations?

My impression is that IETF/HTTWG would make a new status code hard (but I don't have deep insight here). Given that I think my preference is for either using a response header field (Prefetch-Control modulo bikeshed) or the 204 No Content status.

@domenic
Copy link
Collaborator

domenic commented Feb 9, 2022

I agree these are basically the options.

I think a pro/con list might help. Here is one for my currently-preferred option, 204:

  • (+) Already has the right behavior
  • (+) Arguably has reasonable semantics
  • (-) Semantic match is not perfect
  • (-) If you actually prefetch/prerender a legit 204, the browser will then re-fetch it when it comes time to actually use the resource. Versus if we used an unambiguous "this is a rejected pre*" signal, the browser could just use the cached 204 and save itself a request / save the server a response.
    • Mitigating factor: the user experience is the same either way: a broken image / a navigation that doesn't navigate / etc.
    • Mitigating factor: the server response processing is not costly.
  • (-) It makes it harder for clients to have useful metrics on rejected prerenders vs. intentional 204s, which could be useful in e.g. predictive modeling, or measuring the spread of prerendering-ready sites. (Note: server metrics are fine.)
    • Mitigating factor: a site intentionally prefetching/prerendering a 204 resource should be extremely rare. 204s mostly show up as API endpoint responses, not as navigation responses or resource responses. So we will get pretty good metrics if we count all 204 responses as rejected prerenders.

I'll note that these cons seem small, and can be roughly bounded by a use counter or HTTP archive search that determines how many navigation/subresource responses end up in 204s. Additionally, they can be addressed in the future by introducing a new response header field or a new HTTP status code and urging sites to migrate to those.

However, I do think we should try to get IETF first-impressions on the 309 option. If there's a chance that can get some sort of unofficial blessing soon, before we evangelize 204 too hard, that would be even nicer.

@spelchat
Copy link

These are basically the options, right?

I think so. The other options we/I mentioned earlier are strictly worse I think.

My impression is that IETF/HTTWG would make a new status code hard (but I don't have deep insight here).

Beyond spec, I assume adoption of a new status code by some origins might be particularly difficult as well. Not sure how much that should inform spec work though.

I think my preference is for either using a response header field (Prefetch-Control modulo bikeshed) or the 204 No Content status.

Me as well. A new header (while slightly awkward), seems more explicit (no confusion with a server that legitimately wants to serve a 204), so I'm leaning very slightly toward that.

@noamr
Copy link
Collaborator

noamr commented Feb 10, 2022

I agree these are basically the options.

I think a pro/con list might help. Here is one for my currently-preferred option, 204:

  • (+) Already has the right behavior

  • (+) Arguably has reasonable semantics

  • (-) Semantic match is not perfect

  • (-) If you actually prefetch/prerender a legit 204, the browser will then re-fetch it when it comes time to actually use the resource. Versus if we used an unambiguous "this is a rejected pre*" signal, the browser could just use the cached 204 and save itself a request / save the server a response.

    • Mitigating factor: the user experience is the same either way: a broken image / a navigation that doesn't navigate / etc.
    • Mitigating factor: the server response processing is not costly.
  • Mitigating factor: a site intentionally prefetching/prerendering a 204 resource should be extremely rare. 204s mostly show up as API endpoint responses, not as navigation responses or resource responses. So we will get pretty good metrics if we count all 204 responses as rejected prerenders.

These cons and mitigating factors are non-existent when we supplement 204 with a response header... are there any cons to using a header for the sake of being explicit?

@noamr
Copy link
Collaborator

noamr commented Feb 10, 2022

I checked the HTTP archive for 204. They are very common, but not as navigation. Their main use-cases for text/html are:

  • checking connectivity, e.g. sending a fetch to https://google.com/gen_204 which responds with a 204 empty text/html response.
  • Pixels/Tracking - e.g. Google Ads. It's like a beacon-ish thing.

So 204 are used mainly as a server side-effect that doesn't require CORS and doesn't affect UX.
By giving it another meaning with prefetch, there might be edge cases where this will cause duplicate 204 requests (And thus duplicate side-effects), and I feel it creates some unknowns, though I agree they're at the edge.

@nyaxt
Copy link
Collaborator

nyaxt commented Feb 10, 2022

I feel like 503 is an option that we can explore.

The use cases for the opt out I've heard so far are:

  • Server want to throttle relatively low-prio prerender requests.
    • →This intent seems to be best described by 503.
  • Geo restricted content and unsure (may be only relevant for the privacy preserving proxy)
    • → May not be directly the use case of 503, but 503 as generic "check back again"
  • The content only makes sense if logged in
    • → Even weaker than above..., can be 503 but maybe 406?

@noamr
Copy link
Collaborator

noamr commented Feb 10, 2022

I feel like 503 is an option that we can explore.

I like the idea of 503. One con is that if there is a genuine 503, the server will get twice the error rate due to prerender retries. But maybe that's OK as 503 means "retry later" anyway.

@nyaxt
Copy link
Collaborator

nyaxt commented Feb 10, 2022

I'm not convinced with the error rate concern. Ideally, I believe server should respond with why they don't want the page to be prerendered, and that seems to be able to be mapped to 4xx/5xx responses (too much load! -> 503)

My personal preferences at the moment are:

  • 503 Retry-After: 0 (most preferred)
  • New HTTP response header field. - but I'd like to stay away from 204 if possible, because I'm worried about their implementation complexity (Many HTTP client/servers special case 204)

@noamr
Copy link
Collaborator

noamr commented Feb 10, 2022

I'm not convinced with the error rate concern. Ideally, I believe server should respond with why they don't want the page to be prerendered, and that seems to be able to be mapped to 4xx/5xx responses (too much load! -> 503)

My personal preferences at the moment are:

  • 503 Retry-After: 0 (most preferred)
  • New HTTP response header field. - but I'd like to stay away from 204 if possible, because I'm worried about their implementation complexity (Many HTTP client/servers special case 204)

I am less familiar with the implementation specific but I share the same preferences.

@noamr
Copy link
Collaborator

noamr commented Feb 10, 2022

I created a WPT for this that we can populate once we reach consensus. For now it shows that the implementation discards prerendering on 204, 205, and 4xx/5xx.

@noamr
Copy link
Collaborator

noamr commented Feb 10, 2022

After the conversation on Matrix, I am leaning more towards the response header, and to be agnostic to status code.
It has some advantages:

  • we can later enable an http-equiv or so meta-tag to discard a prerender statically
  • We can experiment with downgrading a prerender into a no-state prefetch
  • Implementation-wise it's simpler according to @nyaxt's previous comments
  • It's straightforward semantically. We don't stretch some status code to mean something else

The main disadvantage is that this flexibility also adds complexity - a response code is very straightforward.

I suggest to use the existing Allow-Loading-Mode which is specified for prefetch, but in the case of same-origin or omnibox prerender to allow prerendering if the header is missing.

@domenic
Copy link
Collaborator

domenic commented Feb 10, 2022

I'm not sure how to be agnostic to the status code, at least in the spec.

Consider a 204 for omnibox prerendering. The desired result when the user types https://httpstat.us/204 and then presses enter is, they stay on the current page. (Which might be the new tab page.) I.e., no prerendering browsing context is ever shown to the user.

So we need something like:

  • Discard the prerendering browsing context on 204.
  • However, keep note that when the user commits the navigation, that should instead do nothing?

I guess the spec already has an issue where it's not clear what happens in start a user-initiated prerendering step 6.2 if bc got discarded. So first we'd need to fix that (presumably, with the answer being to do a new navigation from scratch) and then we'd need to say, actually, if we prerendered a 204, do nothing.

@jeremyroman
Copy link
Collaborator Author

Conceptually I think if we go with a response header then 204 No Content would (from a conceptual cleanness POV) indeed have a special tombstone stored in the prerender buffer to consume the next navigation.

But I don't strongly mind whether 204 No Content winds up being an alternate way of achieving a full opt-out of prefetch+prerender or not, as long as it's possible to do something more nuanced. I personally suspect 204 is not well-understood and so most developers won't try that unprompted.

@jeremyroman
Copy link
Collaborator Author

jeremyroman commented Feb 10, 2022

Okay, so here's an expanded stab at what absorbing this into Supports-Loading-Mode would look like. This might be overengineering but I don't think it's much larger than the combination of what we already needed SLM to do plus this.

Supports-Loading-Mode is a structured header which is a list of tokens.

The loading mode support is a map from {"prefetch", "prerender"} to {"auto", "unsupported", "supported"}. (Plus "fenced-frame" for that project, and in future "uncredentialed-prefetch", "uncredentialed-prerender" as we get to those.) All values are initially "auto".

Tokens are parsed from left to right.

  • "prefetch": set the "prefetch" value to "supported"
  • "no-prefetch": set the "prefetch" value to "unsupported"
  • "prerender": set the "prerender" value to "supported"
  • "no-prerender": set the "prerender" value to "unsupported"
  • "none": set all values to "unsupported" (I'm not sure this is needed, but we could have it if we wanted)

Each defines what "auto" means. For prefetch, auto is true (allowed by default). For prerender, auto is whether prefetch is supported. For fenced-frame, auto is false.

Dynamic server behavior in response to Sec-Purpose is possible, but not required -- a server can unconditionally serve this header if it likes in its 200 OK responses (and cache that response), or it can include this Supports-Loading-Mode: no-prefetch in a terse 503 Service Unavailable (or another suitable status) and bail. If a request with Sec-Purpose: prefetch observes Link rel=preload response headers but Supports-Loading-Mode: no-prefetch (etc), it can still use those hints (whether they occur in 103 Early Hints or not).

@noamr
Copy link
Collaborator

noamr commented Feb 11, 2022

I'm not sure how to be agnostic to the status code, at least in the spec.

Consider a 204 for omnibox prerendering. The desired result when the user types https://httpstat.us/204 and then presses enter is, they stay on the current page. (Which might be the new tab page.) I.e., no prerendering browsing context is ever shown to the user.

So we need something like:

  • Discard the prerendering browsing context on 204.

  • However, keep note that when the user commits the navigation, that should instead do nothing?

I guess the spec already has an issue where it's not clear what happens in start a user-initiated prerendering step 6.2 if bc got discarded. So first we'd need to fix that (presumably, with the answer being to do a new navigation from scratch) and then we'd need to say, actually, if we prerendered a 204, do nothing.

Yea in the HTML spec a 204 or 205 aborts the navigation but doesn't discard the bc. In this case we have a pre-rendering bc that hasn't navigated. I believe the behavior here should be identical to opening a 204 page directly from the omnibox - as in, do nothing as if enter wasn't pressed. We should verify this in the wpts.

@noamr
Copy link
Collaborator

noamr commented Feb 11, 2022

One disadvantage with allowing this header with any status is that people might start serving it regardless of the request, accidentally disallowing prerenders without realizing. But maybe it's OK and it's a feature rather than a bug.

@nyaxt
Copy link
Collaborator

nyaxt commented Feb 14, 2022

I like the SLM proposal that is sketched out in #138 (comment)
My latest view is to rely on this for the generic "I don't want to be prerendered for whatever reason", and web authors may use 4xx/5xx for "I don't want to be prerendered for this reason that can be expressed via status code". Can we have the words for the latter as well? (if you have a good reason to prerender 4xx/5xx, I'd appreciate if you can highlight them again)

@noamr
Copy link
Collaborator

noamr commented Feb 14, 2022

Can we have the words for the latter as well? (if you have a good reason to prerender 4xx/5xx, I'd appreciate if you can highlight them again)

The reason to prerender 4xx/5xx is to avoid fetching them twice. If it took the server a few second and it ended up responding with a 404, we don't want the user to have to send that request again.

@nyaxt
Copy link
Collaborator

nyaxt commented Feb 14, 2022

Can we have the words for the latter as well? (if you have a good reason to prerender 4xx/5xx, I'd appreciate if you can highlight them again)

The reason to prerender 4xx/5xx is to avoid fetching them twice. If it took the server a few second and it ended up responding with a 404, we don't want the user to have to send that request again.

Thank you.
I'd respectfully disagree that the less chance of seeing the error page (assuming that there's a good chance that the second request succeed) is better than the cost of issuing the network request twice. I think this is true for many server transient failures.

I think we should retry 404s too. Let's say that I'd like to book a very popular ticket asap, which is put on sale at 9:00am I'd type a complete URL on the URL bar at 8:55 and I'll hit the enter button as soon as clock hit 9:00am. If prerender triggers at 8:55am and that results in 404 (or other server errors that shows the ticket is not on sale yet) and the navigation commit by the enter button doesn't retry the network fetch, I'd be sad.

@noamr
Copy link
Collaborator

noamr commented Feb 14, 2022

Yea I can see your point. It's a bit of a UX choice, like "the user would refresh if there's an error so let's refresh for them". not sure if there's a correct answer.
I think if we discard 4xx/5xx then we shouldn't bother with SLM and recommend that people serve 503 (or 204 for that matter) based on what they receive in Sec-Purpose.

I feel that some user-agents would want to make that UX choice... which might make things less "correct" in some senses (sending two requests for the same stable 404) but if that's the case it would be better to make it the standard and not bother with a new header.

@jeremyroman
Copy link
Collaborator Author

jeremyroman commented Feb 15, 2022

Summarizing from some discussions elsewhere:

Since UAs are always free to drop prefetches and prerenders (e.g., for resource reasons), even if we don't always drop error statuses the UA can heuristically choose to do so (and re-fetch) when it thinks it's likely to degrade the user experience. It could even do so differently for content-initiated vs chrome-initiated (e.g., address bar) requests. Such choices wouldn't, however, be necessarily interoperable without normative text.

So the following behavior could be specified, and could be narrowed in the future if certain cases are widespread:

  • responses which don't cause a document to be committed (I think this includes null body responses such as 204/205, responses with attachment disposition, and possibly some or all non-HTML mime types) cause the prerender to be abandoned
  • responses with the 503 status code cause prefetch or prerender to be abandoned

Options for narrowing this in the future include:

  • specifying additional status codes that are always abandoned
  • specifying uses Supports-Loading-Mode which force abandonment of one or both (but which could allow the same response to be a valid ok response for an ordinary navigation)

It also leaves to the future the definition of extracting hints, but it seems like it's probably fine to take preload hints for all of these cases if we want to.

I'm still not confident we have a principled reason to choose a particular option among the following for the normative text:

  • 503 abandons
  • no status code abandons, requires SLM
  • all error statuses abandon

The best reason to not rely on the SLM header (but to nominate one or two status codes) that I've seen is that it will require less text to specify and implement for the immediate upcoming objectives Chrome has. Nominating at least one error status for that purpose lets us punt that a little, and happens to be the "middle" (compromise) option.

@jeremyroman
Copy link
Collaborator Author

On the intent thread, Alex Russell asked:

Has there been any thought about supporting a response header that would allow a response document to opt into, e.g., only prefetch behavior but not prerendering?

The response header deals with this straightforwardly Supports-Loading-Mode: no-prerender. Lacking that, if we make some status code abandon (like 503) a site can 503 whenever it sees a Sec-Purpose: prefetch; prerender. I will note that the latter somewhat depends on having a programming language expressive enough to easily parse structured headers, and a static response header might be easier elsewhere, like in Apache config (at least if you don't want to rely on regexps to parse structured header syntax, which is potentially unreliable).

@domenic
Copy link
Collaborator

domenic commented Feb 17, 2022

I found @nyaxt's arguments in #138 (comment) compelling. In particular I think that's the best reason not to rely on the SLM header; it gives a good default behavior for sites that just add some speculationrules or want to be prerendered in the omnibox, while still dynamically switching some URLs between 404s and 200s. If we relied on SLM, such sites would need to use SLM to opt their 404s out of prerendering.

More generally, I think a useful framing might be to think about defaults. Both short-term ones that are good for experimentation, and can flexibly be changed pending more feedback, and long-term ones that are best for web developers and the ecosystem.

I think "all error statuses abandon" (including 204/205 as error statuses) might be a good default in that regard:

  • It means by default the user will never get a "stale" error, or an avoidable 204.
  • We can probably relax it in the future, if it turns out that cases like @nyaxt's are not common and people wanting fast 404 pages becomes common.
    • If we are worried about the compat risk, we could make prerendering errors an opt-in, e.g. in speculationrules, for those sites that want fast 404 pages.
  • We can add Supports-Loading-Mode on top of it, if we find that (per @jeremyroman's points in HTTP responses should be able to indicate that a resource cannot be prefetched/prerendered #138 (comment)) making your server respond conditionally in this manner is difficult in practice.
    • Supports-Loading-Mode would also be useful in a future where we loosen and allow prerendering 404s; maybe the site wants fast 404s in most cases but for their ticket-buying page they do not.

Of course, in addition to the above ecosystem arguments that might cause us to change course, feedback from the community and from other implementers could also do so. In either case, I think "all error statuses abandon" is a reasonable conservative starting point, similar to other cases like delaying workers.

@noamr
Copy link
Collaborator

noamr commented Feb 17, 2022

I can stand behind this ^^

We have to think about iframes as well though. What happens when a browsing context prerenders, but an iframe returns an error status? Do we want to cancel the top level prerender? That would mean that pages that have some small (same-origin) add-on with an error would have to discard prerendering. Perhaps that's for the best in terms of interop, especially at first.

@nyaxt
Copy link
Collaborator

nyaxt commented Feb 17, 2022

same-origin subframe errors

This is an interesting point. I haven't thought about that. I'm leaning toward allowing them since it happens much later in the stage - we would know the status code of the main page response very early, but it is after that we constructed the DOM of the prerender target page that we know this. Also it can be the case that the subframes are loaded dynamically.

@noamr
Copy link
Collaborator

noamr commented Feb 17, 2022

same-origin subframe errors

This is an interesting point. I haven't thought about that. I'm leaning toward allowing them since it happens much later in the stage - we would know the status code of the main page response very early, but it is after that we constructed the DOM of the prerender target page that we know this. Also it can be the case that the subframes are loaded dynamically.

This means that if a page is put in an iframe it can't opt-out of prerendering. Maybe that's OK.

@nyaxt
Copy link
Collaborator

nyaxt commented Feb 17, 2022

same-origin subframe errors

This is an interesting point. I haven't thought about that. I'm leaning toward allowing them since it happens much later in the stage - we would know the status code of the main page response very early, but it is after that we constructed the DOM of the prerender target page that we know this. Also it can be the case that the subframes are loaded dynamically.

This means that if a page is put in an iframe it can't opt-out of prerendering. Maybe that's OK.

Yes. I believe that is OK as long as we are considering same-origin prerendering.

@jeremyroman
Copy link
Collaborator Author

We always have the option of hanging the load of a subframe if the document isn't okay with prerendering.

@jeremyroman
Copy link
Collaborator Author

Trying to write out that case seems awkward, because I'm not sure that the counterpart for cross-origin makes sense if we wanted to allow content to expressly permit that in the future. Would it be hard from an implementation perspective to have the same failure condition for subframes, and if they aren't prerenderable we hang the subframe load and retry it on activation? That feels more consistent to me.

Is response supported for prerender?

  1. response is not supported for prefetch, then return false.
  2. Otherwise, return true.

Noting that if the prerendering browsing context fails to create a document (null body, non-HTML MIME type, inappropriate content disposition, etc), this causes an immediate abandonment.

Is response supported for prefetch?

  1. If response's status is not an ok status, then return false.
  2. Otherwise, return true.

In the future, these would be amended to check first for a Supports-Loading-Mode header overriding this baseline behavior -- either to make an ok response non-prefetchable/prerenderable, or an error response prefetchable/prerenderable. This means that sites may observe an increased error rate since error responses could be retried, but if they wished they could distinguish these (or make them fail faster) by observing the Sec-Purpose request header.

@nyaxt
Copy link
Collaborator

nyaxt commented Feb 18, 2022

Yes. We can implement behavior (in Chromium) to cancel prerender on certain http response code received for subframe navigations.
@nhiroki are you cool with that?

Note to self: I believe this can be implemented via PrerenderSubframeNavigationThrottle

@nhiroki
Copy link
Collaborator

nhiroki commented Feb 21, 2022

@nyaxt SGTM. Filed: https://crbug.com/1299316.

I think "all error statuses abandon" (including 204/205 as error statuses) might be a good default in that regard:

Currently, Chromium cancels prerendering on following HTTP status code for main frame navigations in prerendered pages:

 bool IsDisallowedHttpResponseCode(int response_code) {
   return response_code < 100 || response_code > 399;
 }

I'm going to include 204/205 here and check it for subframe navigations as well. Is this sufficient? Do I have to handle other status codes?

@noamr I'll use your WIP WPTs for verifying the implementation. Thanks!

@nyaxt
Copy link
Collaborator

nyaxt commented Feb 21, 2022

One edge-case of the prerendering subframe error case is that when the prerender has a pending subframe navigation (setup for failure) but activation happened before the subframe navigation.
The activation will succeed, but it will make tests harder. Would this be a reason for restricting status error code cancellation to main frame only? (that it would be hard for web authors to rely on this anyways given the asynchronous nature)

@noamr
Copy link
Collaborator

noamr commented Feb 21, 2022

One edge-case of the prerendering subframe error case is that when the prerender has a pending subframe navigation (setup for failure) but activation happened before the subframe navigation. The activation will succeed, but it will make tests harder. Would this be a reason for restricting status error code cancellation to main frame only? (that it would be hard for web authors to rely on this anyways given the asynchronous nature)

I think we should allow subframe same-origin error navigation - allowing the main frame to prerender and then starting to reload iframes might disrupt the page.

@nyaxt
Copy link
Collaborator

nyaxt commented Feb 21, 2022

I don't have a strong opinion here. I have a mild preference of the current implementation behavior (only discard on the main frame error response), but given that the implementation of all other proposed behavior is straightforward, I'm not against them.

@jeremyroman What is your thoughts?

I think we should allow subframe same-origin error navigation - allowing the main frame to prerender and then starting to reload iframes might disrupt the page.

I agree that "reloading iframes on activation" is disruptive. Would it be a problem if we keep the iframes errored (no reload)?

@noamr noamr closed this as completed Feb 21, 2022
@noamr noamr reopened this Feb 21, 2022
@noamr
Copy link
Collaborator

noamr commented Mar 16, 2022

One edge-case of the prerendering subframe error case is that when the prerender has a pending subframe navigation (setup for failure) but activation happened before the subframe navigation. The activation will succeed, but it will make tests harder. Would this be a reason for restricting status error code cancellation to main frame only? (that it would be hard for web authors to rely on this anyways given the asynchronous nature)

I think we should allow subframe same-origin error navigation - allowing the main frame to prerender and then starting to reload iframes might disrupt the page.

Yes I'm totally fine with either keeping them errored or discard the whole navigation. I'm leaning towards leaving them errored by default, and letting the UA decide that in certain cases an errored same-origin iframe should discard the whole BC.

@nhiroki
Copy link
Collaborator

nhiroki commented Mar 18, 2022

FYI: For now Chromium cancels prerendering on iframe navigation failure [crbug]. We are open to changing the behavior based on the spec resolution.

@noamr
Copy link
Collaborator

noamr commented Mar 21, 2022

FYI: For now Chromium cancels prerendering on iframe navigation failure [crbug]. We are open to changing the behavior based on the spec resolution.

At least 204/205 in iframes is a valid use-case ("connected" detection), we shouldn't discard preload when that happens.
If there's no one who argues for discarding the navigation due to iframe error status, I believe we should call that a consensus.

Added a clarifying PR: #153

@jeremyroman jeremyroman added prefetch Related to prefetching. prerendering Related to prerendering. affects-compat Resolution of the issue is likely to affect backward or forward compatibility. labels Apr 13, 2022
@nhiroki
Copy link
Collaborator

nhiroki commented Apr 20, 2022

At least 204/205 in iframes is a valid use-case ("connected" detection), we shouldn't discard preload when that happens.
If there's no one who argues for discarding the navigation due to iframe error status, I believe we should call that a consensus.

Added a clarifying PR: #153

OK, we will update the Chromium implementation based on this [crbug].

@domenic
Copy link
Collaborator

domenic commented Apr 25, 2022

This is done and in the spec!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
affects-compat Resolution of the issue is likely to affect backward or forward compatibility. prefetch Related to prefetching. prerendering Related to prerendering.
Projects
None yet
Development

No branches or pull requests

6 participants