Skip to content
This repository has been archived by the owner on Jun 30, 2023. It is now read-only.

Sending a Purpose: prefetch header for prefetched resources #74

Closed
yoavweiss opened this issue Jan 9, 2018 · 29 comments · Fixed by whatwg/html#8111 or whatwg/fetch#1576
Closed

Comments

@yoavweiss
Copy link
Contributor

Chrome seems to be setting a Purpose: prefetch header for prefetched resources. I'm not sure what other implementations are doing.

This is not documented in the spec, but seems to be something developers are interested in. (presumably in order to tell apart in their server-side analytics which resources were prefetched vs. which ones were explicitly needed by the browser)

We should probably add it to the spec (or decide that it's an awful, awful idea and file bugs against implementations that do that).

@igrigorik
Copy link
Member

Sounds like a good plan 👍

@jyasskin
Copy link
Member

jyasskin commented Jun 1, 2018

To what extent does this header interact with Sec-Metadata and friends?

@mikewest

@jyasskin
Copy link
Member

jyasskin commented Jun 5, 2018

Anne suggests we specify this header in Fetch, by keying off the initiator. He points out that we need to also decide which of the lists starting at https://fetch.spec.whatwg.org/#cors-safelisted-request-header it should appear in. We can imitate whatwg/fetch#751 to actually add the header.

@annevk
Copy link
Member

annevk commented Jun 5, 2018

FWIW, I suspect we probably don't want to add it to any list.

@kinu
Copy link

kinu commented Mar 18, 2019

While discussing how cross-origin prefetch could be processed we came across this one; if we want to make all cross-origin prefetches non no-cors (and it feels we should) we probably should 1) document this header in the spec, and 2) add it to the reasonable cors safelist or consider renaming the header name to something like 'Sec-'.

@toyoshim
Copy link

@annevk do you have any specific reason why we don't want to?

I'm working on re-designing of Chrome CORS implementation so that we can do the most things outside the renderer processes safely, and notice that this Purpose header triggers CORS preflight in the new implementation.

If we allows JavaScript to specify this, we want to add it to the CORS-safelisted request-header (https://fetch.spec.whatwg.org/#cors-safelisted-request-header). Otherwise, adding to the forbidden header name (https://fetch.spec.whatwg.org/#forbidden-header-name), or using 'Sec-' prefixed header name sounds preferable answer for this. IMO, the purpose header should be fully controlled by user-agents. So, forbidden is the right list.

@annevk
Copy link
Member

annevk commented Mar 18, 2019

In that case adding the Sec- prefix would be best as otherwise legacy user agents can be used to confuse the server.

Ideally these lists are largely treated as immutable as otherwise clients and servers have moving targets for maintaining SOP protections.

@yoavweiss
Copy link
Contributor Author

@annevk thoughts on wholesale safelisting anything with a Sec- prefix? Presumably servers should not be vulnerable to those, and they cannot be added by (potentially malicious) developers.

@annevk
Copy link
Member

annevk commented Mar 18, 2019

@yoavweiss I think that's the rough consensus. That browsers are allowed to emit new Sec--prefixed headers across origin boundaries and that servers should not be surprised by them. The values of those headers should still largely be outside the control of attackers though. At some point we should document that.

@yoavweiss
Copy link
Contributor Author

@annevk That's great. I currently have that logic as part of the Client Hints PR, but happy to spin it off to a separate PR, if you think it's something we can land sooner.

@annevk
Copy link
Member

annevk commented Mar 18, 2019

@yoavweiss interesting, that definitely seems like something that's worth splitting out and tackling separately.

@yoavweiss
Copy link
Contributor Author

@annevk - will do!

@toyoshim
Copy link

As I also commented at #880, Sec- prefix is already in the Fetch spec.
https://fetch.spec.whatwg.org/#forbidden-header-name

We should not move it from the forbidden list to the safelist. It causes a security risk. Since Sec- headers are ensured that they are not set by JavaScript but by user-agents, servers can accept them safely. Otherwise, we should make a CORS preflight request.

@toyoshim
Copy link

Anyway, it looks we agreed that renaming the Purpose header to Sec-Purpose is preferable.
So, I will make this change in Chrome 75.

This header haven't spec-ed until today, but it will be a breaking change for users who already relies on that. @yoavweiss , do you know how widely is this header already known and used? Or any concern if I make this change in the 75?

@yoavweiss
Copy link
Contributor Author

any concern if I make this change in the 75?

No particular concerns, but it seems like something that would benefit from an Intent.

@akhiljay
Copy link

akhiljay commented Sep 3, 2020

Hi @yoavweiss , just checking in here. Our team at Amazon is looking to leverage the "purpose: Prefetch" request header. Is it advisable to still use the same header or has the working group formalized a header format for prefetch requests?

@yoavweiss
Copy link
Contributor Author

No progress to report on just yet. Sorry. I'm hoping progress would be made here soon...

@mfalken
Copy link
Member

mfalken commented Jun 10, 2021

To what extent does this header interact with Sec-Metadata and friends?

@mikewest

@mikewest at https://bugs.chromium.org/p/chromium/issues/detail?id=942976#c14 expressed not wanting both Sec-Purpose and Sec-Fetch-Dest.

Could it make sense to add prefetch to https://fetch.spec.whatwg.org/#requestdestination? I'm not sure: we lose the info about what the type of resource the prefetch is for.

Perhaps it is just an issue with naming, and this could be a header like Sec-Prefetch: true instead of Sec-Purpose?

@mikewest
Copy link
Member

I might have misunderstood how prefetch integrates into Fetch. My understanding (based on the table just below https://fetch.spec.whatwg.org/#request-destination-script-like), is that prefetch and prerender are enum values of a request's "initiator", and that the corresponding destination is the empty string. In that case, it would make sense to me to define a destination of prefetch, and send it via Sec-Fetch-Dest.

If things work differently, such that prefetched resources have a defined destination, then I agree that it would make sense to define some other mechanism of representing it. Would exposing the initiator directly be reasonable? That would have the advantage of exposing a "download" intent as well, which could be helpful when servers are making decisions.

If not, then a Sec-Fetch-Preload: ?1 header, similar to the Sec-Fetch-User header, seems like the simplest way of aligning this information with the rest of fetch metadata.

@mfalken
Copy link
Member

mfalken commented Jun 14, 2021

Good point, this was actually a similar discussion we were also having, and I filed a new bug at whatwg/fetch#1252 about whether destination should be the empty string for these.

I don't see an issue with exposing the initiator but am not well-versed in the implications of doing so. Assuming it is acceptable, would it be exposed as something like Sec-Fetch-Initiator in that case?

@mikewest
Copy link
Member

I think my only concern with Sec-Fetch-Initiator is that I'm not sure it's useful enough to justify being sent on every outgoing request. download and prefetch/prerender seem like the only interesting values that aren't replicated as destinations; if those are the only things we care about, then mirroring the values in the destination seems like a simpler way of doing things that doesn't add any header overhead.

If there's good reason not to mirror the value, then I think it'd be worth looking into Sec-Fetch-Pre{fetch,load,render}: ?1 instead, as we could leave that off the vast majority of outgoing requests (similar to Sec-Fetch-User).

@mikewest
Copy link
Member

/cc @arturjanc and @lweichselbaum, who might have thoughts about initiator values in request headers.

@arturjanc
Copy link

I fully agree with the approach described in #74 (comment) and don't have much to add. Specifically, Sec-Fetch-Dest: prefetch seems like a natural option to me, but if that doesn't work Sec-Fetch-Pre{fetch,load,render}: ?1 looks reasonable as well.

@yoavweiss
Copy link
Contributor Author

Chromium is using <link rel=prefetch>'s as attribute value to determine if it's destined for top-level navigations or not (in unspecified ways :/).

If we want to properly specify that behavior, it makes sense to keep prefetches' destinations intact. If that's the case, Sec-Fetch-Pre* would be a better option.

@mikewest
Copy link
Member

If Chromium is doing a thing, properly specifying the thing (or changing the thing so that it matches the existing spec) sounds like a good idea. :)

I don't have strong feeling about the direction y'all choose here. I think either option we're discussing is defensible. Which would y'all prefer?

@kinu
Copy link

kinu commented Jun 21, 2021

Chromium's behavior has been trying to formulate things on top of the existing spec'ed concepts (i.e. initiator and destinations are orthogonal and prefetch also has as= attribute), we can remove the behavior with as= attribute if we want to reconsider the part, but we'll want to keep having some indication (at fetch layer) for 'prefetching resources for next navigation' cases anyways. The WIP spec text for the document-level prefetch (or prerender) is being developed/discussed here (in my understanding): https://github.com/jeremyroman/alternate-loading-modes/blob/main/fetch.md

For prerendering if we mirror 'prerender' to the destination it feels it's a bit unclear what Sec-Fetch-Dest headers subresource fetch requests for prerender should use. If we just use 'prerender' it'll lose the real final destination context, but if we just use the final destination it'll lose the context that it's for prerendering.

With these contexts I'd vote for Sec-Fetch-Pre{fetch,load,render}: ?1 (but can be convinced if others have reasons not to prefer this one / other better alternatives for above cases)

@yoavweiss
Copy link
Contributor Author

Should be defined as part of #86

/cc @noamr

@tigt
Copy link

tigt commented Apr 19, 2022

It looks like Firefox sets an x-moz: prefetch header for this, so hopefully they’d have no problem switching to a standardized header instead.

kodiakhq bot pushed a commit to vercel/next.js that referenced this issue May 29, 2022
Continuation of #34498 this updates to send a `purpose: prefetch` header (related [w3c discussion](w3c/resource-hints#74)) when prefetching data routes and then on the server we skip revalidating when this header is set. 

When a client-transition is actually made we send a background HEAD (non-blocking) request to the data route without the `purpose: prefetch` header which signals a revalidation should occur if the data is stale.  

This helps alleviate the number of revalidations occurring currently caused by prefetches as a path can be prefetched but not visited during a session so may not need to be revalidated yet. 

Fixes: #17758
x-ref: #20521
x-ref: [slack thread](https://vercel.slack.com/archives/C031QM96T0A/p1645129445819139?thread_ts=1645124478.067049&cid=C031QM96T0A)
@noamr
Copy link
Contributor

noamr commented Nov 28, 2022

whatwg/html#8111 now specifies Sec-Purpose: Prefetch as the header.
I feel like we should really settle on something here. Currently firefox sends x-moz, Chromium sends purpose, and Safari doesn't support prefetch yet. Can we agree on Sec-Purpose: Prefetch? Something else?

annevk added a commit to whatwg/fetch that referenced this issue Jan 17, 2023
This replaces the existing `Purpose: prefetch` and `x-moz: prefetch` headers.

Tests: web-platform-tests/wpt#35707.

Part of whatwg/html#8111.

Closes w3c/webappsec-fetch-metadata#84 and w3c/resource-hints#74.

Co-authored-by: Anne van Kesteren <annevk@annevk.nl>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet