-
Notifications
You must be signed in to change notification settings - Fork 37
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
Server pushed resources in ResourceTiming #53
Comments
+1 to figuring this out and exposing it. Maybe a F2F session? |
FWIW, I think we'd need to solve whatwg/fetch#65, whatwg/fetch#51 first. |
Current behavior, for reference, is that we're too cowardly to send values that go backwards in time, so we make sure no value is before requestStart (FetcherStart? The time the URLRequest was created). This currently applies mostly to sockets create before the request using preconnect / late binding. |
We're starting to use HTTP/2 push across our video products now and will hopefully be expanding on their use in the coming months so this kind of info is increasingly important for our product teams. If possiable I'd love to talk about this at the next f2f :) It'd be cool if we could make some progress on or at least talk about this issue before whatwg/fetch#65 and whatwg/fetch#51 are totally resolved. |
Cloudflare enabled h2 push via Link: preload, so we can use that as a demo: https://blog.cloudflare.com/announcing-support-for-http-2-server-push-2/ They also provide a diagnostics header to indicate what got pushed. E.g..
Looking up one of those resources via RT in Chrome yields: What's missing in the above report; what do you want to know about such resources beyond what's already there? |
What we would like to know is the fact that the server has pushed the resource. Maybe the initiatorType should not be "link", but "push"? Or an additional field would expose the fact that this was pushed. It would probably also be helpful to know when the push started, ended, etc. I believe the current data only exposes when the user-land request started and the user-land response started and ended. For pushed resources it's also of interest when the push promise was received and fulfilled. |
From what I can tell, these numbers report when the resource was read by the renderer, rather than when the resource was actually pushed and read from the socket by the networking stack. This may be an implementation issue, but it's currently not properly defined what these numbers should be. Also, what do we do with resources pushed in one nav and read from the push cache over another nav? AFAICT, that's possible for consecutive pages that use the same H2 connection. Would they have negative numbers? Should we define their timings as 0? |
Actually, the times represent when the browser process received the request. We're too cowardly to return times prior to when the browser received, which could result in negative times, and times out of order. Preconnect means connection times could be too early. With push, most times could be before navigationStart (I'm not quite sure about fetchStart. If we're talking about the fetch API, fetchStart would still only happen once the renderer issues the request, so it could be after most other events. If we're talking about when we start receiving data, that would be another time entirely. Note that, per spec, fetchStart is when the "fetch process" starts, and that links directly to fetch API, implying the former interpretation. |
Fair enough, but that's still after the renderer initiated the request for the resource, and therefore still significantly after the time these resources were received by the net stack. Going to https://mygreatjobs.de/jobs/en/jobboard in Canary, I see:
|
I assume fetchStart is set by the renderer, when it requests the resource. The navigation timing API makes it sound like this is when the fetch API starts, which requires checking with things like service worker, which we can't do (Or at least don't do) with push. I think requestStart is actually the more interesting value here - it currently is when the URLRequest is created, but with push, perhaps it shouldn't be, though requestStart is currently also recorded before we talk to ServiceWorker, so switching it to when the resource was pushed would be inconsistent there. |
Ok, I'll bite.. This is a bit of pathological example, but it's also a good one to discuss because it highlights all of the major corner cases -- three of them, for a single file:
Inspecting performance timeline in Chrome, I see two requests:
The first RT entry corresponds to the request initiated by
Here's the cleaned up netlog trace from Chrome for above flow:
In short, I believe the current Chrome behavior is correct. The two existing records reflect the two browser-initiated requests (one by preload other by rel=stylesheet), which I would expect to see. The remaining question is if and whether we ought to surface the push'ed response as the third RT entry in that set. |
Yeah, this is a misconfiguration on the site's part. RT (and dev tools) are doing the right thing here and reporting it as a duplicate download. The main problem I see with these requests is that when running devtools with "disable cache", they are not being fetched from the HTTP cache, but getting double downloaded. In any case, this is out of scope for this discussion.
While I agree that above issues should be tackled and the observable behavior of these "push caches" should be properly defined, I don't think there's any cause to block exposing the times in which the push resources actually arrived on the network on defining their caches. IMO, these issues are orthogonal.
It is according to the current spec. It is also lacking info regarding the times resources were actually pushed, which I believe is the reason we're discussing it here :)
I don't think push should be exposed as a separate entry. Multiple entries indicate multiple fetches from the renderer's perspective. Push responses don't constitute multiple fetches. I think we could have exposed the actual push times as separate attributes on the same resource entry, e.g. |
The question in my head is not whether it is committed to cache or not, but whether it is exposed to the developer at all as a first-class primitive. Current browser behavior seems to indicate "no". Personally, I don't think that's quiet right, but we should resolve that first.
I would argue the opposite, actually.. We've already been burned by this and hence the various discussions on unbundling redirects, preflights, range-requests and the like -- i.e. #21. Following that same line of reasoning, a pushed response is a separate entity; a preload is separate from the request that consumed it, and so on. That said, I do agree that it's helpful to mark push'ed response as such: initiator = push, or some such. |
OK. I agree we need to decide on the principle question of "is it OK to expose the fact that H2 push happened to the platform?" before we can continue on either front.
Seems like an overkill to me, but I could be convinced that it's the right thing for the sake of consistency...
That is not currently true (unless the consuming request didn't match the preload, and hit cache/network). |
You're right, and I still feel like that's a bug (demo here). Ideally, I'd prefer to see separate requests, one for preload, and one for each instance of consuming that said response, but that's a separate discussion, let's focus this on push. |
A simple question, hope to get some comments if available @igrigorik @yoavweiss . For pushed resource, what does the |
As of today, in Chrome at least, that's the time when the request was initiated by the renderer for that resource; this timestamp has no relation to when the server initiated the push.
The short answer is that it's not defined.. :-) server ---> (client's push cache) <-- renderer request Server pushes the response into the push cache. Renderer makes the request and if there is a yet to be fulfilled promise, may block until the server delivers said response. Defining how all of this is actually resolved via RT is what this thread is all about. |
I see. May I understand in this way. No matter server pushed the resource or not, client side will always initiate the request, the requestStart time is exactly the time before initiate the request. After initiating the request, the client will check whether there is a push promise frame indicating that the resource is going to be received, if so, client will not send the request but waiting for the response. If not, client may send request to the server for the resource. And there is no attribute in the RT specify something related to server push, right?
This is the definition of requestStart. According to your explanation, does |
Yep.
Yep. |
I have a related question about transferSize field for server-pushed resources. If server sends a PUSH promise and browser cancels the stream because it has that resource in cache. Should transferSize show actual number of bytes transferred to the browsers even if the push was cancelled? It think it should as there is not other way to get that data. Server push might waste bandwidth if resource already in cache and it's important metric when deciding whether some resources should be server-pushed or not. |
@nbeloglazov no, I think these are orthogonal problems. If the resource came from cache, it should have a transferSize of zero. The fact that server push is not observable is a separate concern and needs a different mechanism. |
The issue for us with |
Is HTTP2-push still a thing, or are we moving away from this to link headers and early hints? |
Chromium has dropped / is dropping support, and no other browser engine ever added support for it, I believe, so think we can probably close this. |
HTTP/2 allows the server to "push" resources to the client. We should figure out if and how these should be exposed via ResourceTiming.
The text was updated successfully, but these errors were encountered: