-
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
Handing fetch termination #1178
Conversation
docs/index.bs
Outdated
@@ -2996,6 +2997,9 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe | |||
1. If |e|'s [=FetchEvent/respond-with error flag=] is set, set |handleFetchFailed| to true. | |||
1. Else, set |response| to |e|'s [=FetchEvent/potential response=]. | |||
1. If |e|'s <a>canceled flag</a> is set, set |eventCanceled| to true. | |||
1. Run the following steps [=in parallel=]: | |||
1. Wait for the fetch to become [=fetch/terminated=]. | |||
1. [=Queue a task=] to [=AbortSignal/signal abort=] on |requestObject|'s [=Request/signal=]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems this algorithm has a chance to never finish.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I figured "GC" would take care of it.
What's the alternative? "Wait for the fetch to become [=fetch/terminated=], or (something that signal successful completion)"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to think about this a bit and the way XMLHttpRequest seems to approach is that you always get a response from the fetch process, but it might be a network error annotated with a termination reason. And for the request/response bodies we got the stream that errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could wait until on of the following:
- Fetch is terminated.
- "Process response" for fetch occurs, and the response type is "error".
- "Process response done" for fetch occurs.
Then, only signal abort if fetch is terminated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I was saying is that currently "Fetch is terminated." is not really a signal we expose to the outside (other than the response having a termination reason or the stream erroring).
This makes the following changes: * Integrates DOM's `AbortSignal`. * Specifies abort points and how to handle termination. * Replaces termination reason with an aborted flag. Tests: web-platform-tests/wpt#6484. Service worker integration follow-up: w3c/ServiceWorker#1178. Fixes #447. Closes #563.
2358afd
to
d4fd56b
Compare
@annevk re:
I agree, but this feels like a special case since fetch called me, I didn't call fetch. In the fetch spec I've tried to keep termination handling as close to the leaf end as I can. HTTP fetch doesn't have a "If terminates" break clause around the call to service workers, so it feels "handle fetch" should be handling the termination. Alternatively, I could add a break clause the call to "handle fetch" in "main fetch". Then, in "handle fetch" I can somehow "handle response" for the outer fetch, and see if its abort flag is set. But this will be really messy, as the fetch spec is waiting for a response from the service worker spec, but the service worker spec is also waiting for a response from the fetch spec. I'd also end up looping the service worker response back into the service worker spec via the fetch spec, and I'd need to ignore that somehow. I've updated the PR a little, but it seems to express the behaviour pretty clearly. It's a bit hand-wavey around getting an instance of the fetch, but I think that's part of whatwg/fetch#536 (comment). |
docs/index.bs
Outdated
1. Initialize |e|’s {{Event/type}} attribute to {{fetch!!event}}. | ||
1. Initialize |e|’s {{Event/cancelable}} attribute to true. | ||
1. Initialize |e|’s {{FetchEvent/request}} attribute to a new {{Request}} object associated with |request| and a new associated {{Headers}} object whose [=guard=] is "`immutable`". | ||
1. Initialize |e|’s {{FetchEvent/request}} attribute to |requestObject| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs a trailing dot.
Yeah, I guess we need to fix that issue at some point. Not looking forward to updating all the callers again. |
@annevk Are you ok with:
And
Here? If so I'll write some tests and get this merged. |
Yeah, as you said there's not really any better way to do it at the moment. Maybe note these cases in the Fetch issue so we make sure they get addressed by whatever we come up with? |
Tests at web-platform-tests/wpt#7674 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I defer to @annevk's review for this.
@jakearchibald, it seems this is ready to be merged? |
Done. I need to take another pass at the tests. Just minor stuff though. |
Hi all, sorry for resurrecting this old thread. Wondering if this behavior that I'm noticing is the one as intended according to the spec, as I'm noticing the same thing on all major browsers (Firefox, Chromium, Safari). It seems that this doesn't catch situations where the browser itself is terminating a request. Example: index.html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test fetch</title>
</head>
<body>
<button onclick="getVideo()">Get video</button>
<button onclick="stop()">Stop</button>
<div id="out"></div>
<script>
;(async function() {
await navigator.serviceWorker.register('sw.js')
console.info('Service worker registered')
await navigator.serviceWorker.ready
console.log('Service worker installed')
document.getElementById('out').innerText = 'Ready'
})()
function getVideo() {
document.getElementById('out').innerHTML = '<video autoplay controls muted="muted" src="video.mp4" style="width: 400px; height: auto;"></video>'
}
function stop() {
document.getElementById('out').innerHTML = ''
}
</script>
</body>
</html> sw.jsself.addEventListener('install', () => {
self.skipWaiting()
})
self.addEventListener('fetch', (event) => {
console.log('fetch', event)
event.request.signal.addEventListener('abort', (event) => {
console.log('aborted', event)
})
})
self.addEventListener('activate', () => self.clients.claim()) DescriptionPlace a video file in the same folder called Start playing the video (hint: it helps to throttle the network), then press the "stop" button before the video is done loading. Alternatively, skip forward in the video to a part that hasn't been buffered yet. In the dev tools, you'll see the browser interrupted the old request (and made a new one if necessary). However, the Is this how it's supposed to behave according to specs? Or is it a bug in the browsers? Why am I doing this? I have a SW that intercepts a request and makes a new one instead. I need to be able to understand if the browser has canceled the "original" request to cancel the new one too. |
I recently raised the same issue on #1544. I think the intent was to abort the signal here, but no browser implements it yet. Also, as I mention in the issue above there may be a spec problem that also makes it not do what is intended. |
Thanks, @wanderview ! I'll follow the other thread then. If you need more details on what I'm trying to do, to add to your case on #1544, please let me know. |
Is this a valid way of handling this, in terms of whatwg/fetch#523.
It seems too easy.
(I'll add the same to foreign fetch if this is 👍 )
Preview | Diff