-
Notifications
You must be signed in to change notification settings - Fork 312
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
reserved Client objects and redirected navigations #1031
Comments
For now I am going to work towards implementing a new reserved Client on every redirect. I can adjust if we consensus reaches a different conclusion. |
Also consider that the worker environment creation URL is set based on the worker global scope's URL which reflects redirects. It seems we should probably reflect redirects here as well. Of course, the worker creation URL is only set after following all redirects and not at each redirect step. It also doesn't give us the opportunity to create a new Client on each redirect since fetch spec handles the redirections. The fact that workers are same-origin avoids issues with cross-origin postMessage(), though. I guess there is an open question here about how close we need to keep worker and window Client behavior to each other. Closer seems better, though. |
Thanks for spotting this!
Agreed to all those points. Redirect mode
Basically, I think we can think of it as we defer the behavior to what the request expects to fetch. Here, the worker script fetch |
One of the aims of reserved clients is to be able to A way around this is to provide a way to get a genuine client from a reserved client - a promise that would resolve with a client or undefined if the client isn't created or goes cross-origin. |
@jakearchibald, your idea of getting a genuine client is under the assumption of using a single reserved client throughout the redirects of a navigation or multiple reserved clients for each redirect? Hope the API isn't get too much complex to cover a corner case but not sure if this case is rather common in practice. |
I have thought about this a bit more over the weekend. Given the fact that we are making So I now think it would be a bit better to keep the same reserved Client when a redirect is same-origin. If a redirect cross origin boundaries then a new reserved Client would need to be created. This solves the immediate problem and also make the window reserved Client consistent with the worker reserved Client during redirects. |
A Personally I'd be happy to make |
Another reason to create a new Client when following a redirect across origins: In general Edit: In other words, the origin of a Client should never be allowed to change. Even though there is no URL exposed on Client while its reserved it still has a pinned origin. |
We should also make it clear that if a Window navigation is redirected the final Client object has the final redirected Response URL as well. |
I like this reasoning but see a corner case with the same-origin redirect scenario: Browser has two registrations for an origin: foo.com/a/ and foo.com/b/.
In this case, if step 2 and step 4 called |
I can go either way on this issue. @jakearchibald, what do you think? |
To summarize, we have three options here:
1 seems the simplest. 3 seems good in the sense that a single reserved client represents what becomes the actual client at the end regardless of which location urls are encountered. For 2 and 3, the fact that client:scope can be 1:N bothers me. |
|
In the option 1, the scope apparently doesn't matter as only the final client will survive and the other clients created for redirects won't get the actual global object. But in the option 2 and 3, the same client is reused for redirects. (e.g. the case in #1031 (comment).) So, the messages sent from multiple (same-origin) SWs with different scopes will be delivered to the same ServiceWorkerContainer object. Not sure if it's an expected behavior. I didn't think it'd be but not really sure.
This opens up two possibilities. It can creates three clients as you suggested, and the final client will survive, being associated with the actual global object. Or it can use two clients for different origins, in which case we might retain the message from the same-origin SW before it redirected to cross-origin resource. (For this, we'll need to track the redirects to queue only the messages from the same-origin SWs to the original request's url.) |
As an implementation note, I likely will have to do something like:
I don't like this, but due to a number of implementation details its very very racy to handle redirects for worker threads any other way. The redirects happen on a different thread altogether. |
Once an origin is crossed as part of a redirect, the reserved client must be discarded and a new one created for the other origin. In terms of clients that cross service worker scopes, I think that's fine, even if multiple service workers queue messages for that client.
I was thinking the promise would resolve with the real (not-reserved) client. |
FWIW, turns out I don't need to do this any more. I was able to prove to myself that we don't allow cross-origin redirects for worker scripts even with our non-standard data URL handling in gecko. So I will create a new Client where appropriate in firefox instead of mutating the existing one. |
For added fun, @bzbarsky posed this question while implementing this: If a sandboxed iframe is loads foo.com and it redirects to another foo.com URL, is that considered same-origin or cross-origin? My initial implementation in gecko is going to treat it as cross-origin since sandboxed iframes use opaque origins. What do people think? |
Yeah, the newly created document for another foo.com will have a unique origin. So, treating it as cross-origin makes sense. I don't see any reason we shouldn't follow it.
Has this been the consensus? If so, "origin1 to origin2 to origin1 to origin2" will have two clients or four clients? |
I plan to do four clients here. I don't think its worth the complexity to try to match redirects back to old clients on the same network request in previous redirects. That would be complicated and this is a corner case. |
Agreed. |
F2F: 4 clients in the #1031 (comment) sounds good - new client at every change of origin. Reuse reserved client for same origin navigations. |
(As I noted before, I'd be very suspicious about reusing clients in the "corner case" scenario (A -> B -> A) (which is not that corner case really, with lots of login flows using it). That might very well lead to subtle attacks. So this solution seems good.) |
We aren't going to expose reserved clients, so this is no longer an issue. |
I'm looking at implementing the new Client semantics including "reserved Client" for navigations. I'm curious, though, if the current spec works as intended for redirects.
Consider:
Per the current spec:
postMessage()
to the Client which is ultimately in the bar.com originThe
postMessage()
behavior seems like a clear SOP violation and should be fixed. We could do this by either:postMessage()
events on the reserved Client.I personally lean towards creating a new reserved Client on every redirect. This would also ensure the
Client.url
matches the actual final URL loaded in the window. It also seems conceptually consistent with an algorithm that uses manual redirection and re-enters the service worker each time. It also simplifies edge cases for the service worker code. It doesn't have to worry about possibly having a reserved ClientpostMessage()
'd by two different service workers or twice by the same service worker by accident.Thoughts? @jungkees @jakearchibald
The text was updated successfully, but these errors were encountered: