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/2 server push support #51

Open
martinthomson opened this issue May 13, 2015 · 22 comments
Open

HTTP/2 server push support #51

martinthomson opened this issue May 13, 2015 · 22 comments
Labels
addition/proposal New features or enhancements topic: api

Comments

@martinthomson
Copy link
Contributor

We have an internal implementation of this in Gecko, but it would be nice if we could expose that to script.

@annevk
Copy link
Member

annevk commented Jun 9, 2015

You'll have to be a bit more concrete with what kind of API you're expecting for this.

@martinthomson
Copy link
Contributor Author

Sure. I was thinking that an event handler on Request, maybe called onpush might work. You get pushes before and during response delivery. Each push turns up in the form of a Request, and you need to actually fetch that to get the actual response.

@annevk
Copy link
Member

annevk commented Jun 10, 2015

So what are the use cases for this? I wonder if this should be part of the fetch registry proposal https://www.w3.org/Bugs/Public/show_bug.cgi?id=23878#c16 and some kind of associated network observer API.

@martinthomson
Copy link
Contributor Author

Not understanding the full scope of what your registry proposal is, it seems plausible, but I'd have to trust your judgment in this case.

The use cases I can think of, without getting into too much detail:

  • HTTP APIs that use server push
  • replacing long-polling (webpush uses server push)

@brendanlong
Copy link

This bug report has a lot of information about use-cases. Copying it here for convenience: https://www.w3.org/Bugs/Public/show_bug.cgi?id=28083

http://lists.w3.org/Archives/Public/public-whatwg-archive/2015Feb/0030.html

The use-case I have in mind is MPEG DASH or HLS live streaming:

A server updates the manifest (MPD or m3u8) and pushes it. The client browser will cache it, but JavaScript applications don’t know that it exists. For newly generated segments, we need the MPD to use them anyway, but for adaptive streaming we need to know when the request started and when it finished so we can estimate bandwidth. If a server is pushing MPD updates, we want a way to tell it to stop (RST_STREAM on a pushed stream to end the transfer, or RST_STREAM on the original client request to prevent future pushes for that request).

The obvious question to ask is “why not just poll the server”? The answer its that live streaming latency depends (among other things) on how quickly you poll. Unless you can perfectly predict when the server will have an update available, you need to either poll slightly late (introducing latency) or poll significantly more often than the server creates updates. Using server push is equivalent to to polling infinitely fast, while simultaneously reducing load on the server by making fewer requests (win/win).

I imagine that this would be useful for JavaScript implementations of HTTP/2 REST API’s, especially API’s using something like ATOM or RSS. Firefox has an API for addons to detect pushed streams, so presumably they think there is some use for this (but they didn’t propose this as a public API, so maybe not?).

What's needed:

  • Event when PUSH_PROMISE is detected, containing a new Response.
  • Ability to signal to a UA that a stream should left in the "half closed" state (to allow server pushes).

I'm not sure fetch is the best API for this, since there's currently no way to cancel fetches or use a partial response before it finishes, but it seems to be the only API anyone wants to make changes to.

@igrigorik
Copy link
Member

@annevk +1 on registry overlap. I think this is another instance of "observer use case": #65. Specifically, in this instance the receipt of the PUSH_PROMISE would register the request in the registry... which would trigger appropriate observer callbacks, etc.

@rektide
Copy link

rektide commented Aug 28, 2015

I have an example of this usage pattern in a server-to-server case- I stream IRC messages from one microservice to another.
https://github.com/rektide/tele-pump/blob/master/tele-muc-pump.js#L17

There's also an earlier implemented of this capability that I created by recording all push_promises i'd sent, then attaching an X-Associated-Content header to any replies made to the client with this list. Then I polyfilled XMLHttpRequest to read these headers, and postMessage to to the window to inform any listeners. By periodically issuing requests to the server, the client gets notice of what has been pushed.
https://github.com/rektide/pushchannel

This latter technique was something inspired by Jetty, who also has X-associated-content: in that implementation, the header informs the server to push that resource to the client; I took it one step further. This should be a readily available capability for the browser, without polyfilling XHR. I would love for the first project, tele-muc-pump, to be usable from the client (without having to devise an out of band signalling like the pushchannel XHR monkeypatching, or using a Server-Sent-Events or websockets).

@jakearchibald
Copy link
Collaborator

I don't think this API fits on request objects, as far as I can tell PUSH_PROMISE frames aren't linked to another request.

I don't think this API should be on pages because the lifecycle doesn't match up. As far as I know one H2 connection can cover many pages. Are H2 connections even per origin?

@martinthomson
Copy link
Contributor Author

@jakearchibald, actually PUSH_PROMISE is tied to a request and that binding is sometimes (often maybe) important.

That an h2 connection can cover multiple origins makes this less easy, I agree. In some cases you will be receiving a cross-grained request-response without a pre-flight. We have to ask whether we even want to surface the existence of something like that.

@rektide
Copy link

rektide commented Jul 21, 2016

I appreciate @martinthomson pointing out that PUSH_PROMISE is affiliated with a specific request (and that's super important as in the case with protocol specs like his WebPush Protocol). That makes fetch a sensible place to expose push events.

As a developer, it would also be convenient to have one high level place where I could perform observations on pushed data. If Service Workers also offered a way to see PUSH_PROMISES for their domain, for example, that would be useful and handy. It would both prevent developers from having to explicitly set up each fetch to listen, and secondarily, it would be answer to how to handle PUSH_PROMISES sent to non-AJAX/non-fetch-based PUSH_PROMISES.

@martinthomson
Copy link
Contributor Author

martinthomson commented Jul 26, 2016

Trying to record the result of in-person discussion...

Two options seem to be most attractive:

  1. A fetch-group-local service that provides events when requests are made. See Observer API for fetch groups #65.
  2. Attaching events to Response that surface when a server push is made.

In both these cases, a Request would be generated for each server push. These could then be passed to fetch() to attach to the existing request and acquire the answer. This would likely need to build on Response.clone() to deal with the fact that multiple clients could consume the answer.

The main shortcoming of the second option is that you would delay the receipt of pushes until the response header fields are populated. h2 permits PUSH_PROMISE to be sent prior to the generation of the response header block, but fetch() depends on the header block to construct the Response.

@igrigorik
Copy link
Member

In favor of (1): some RUM vendors wrap all the JS APIs + attach onload / onerror's to all new elements that initiate fetches via MutationObserver to capture "start of request". Exposing an event would eliminate that overhead.. which would be nice.

@annevk
Copy link
Member

annevk commented Jul 26, 2016

There's also some discussion on the semantics of server push and @mnot might write a draft on that. Fetch-wise the semantics would roughly be:

  1. All push promises end up in the HTTP cache (effectively). This way they can be used for navigation. (There's many ways to put something in the HTTP cache already so that wasn't really a valid concern.)
  2. Noncacheable push promises disappear together with the fetch group.

@DanielBaulig
Copy link

Is there any consideration of being able to cancel/abort an ongoing push from a future API through a reset stream? I don't think the proposed solutions in this thread allow for this.

@annevk
Copy link
Member

annevk commented Oct 28, 2016

@DanielBaulig I think we'd want to give full control, yes. The main tricky point is how to layer H/2 push.

@rektide
Copy link

rektide commented Nov 6, 2017

@slightlyoff providing a more tangible discussion point here:
https://gist.github.com/slightlyoff/18dc42ae00768c23fbc4c5097400adfb#gistcomment-2227534

[ed: jake archibald has also reiterated some ideas begat in fetch observer in second comment, and it's worth reviewing!! see: comment#2]

@rektide
Copy link

rektide commented Feb 20, 2022

Please help. This deserves to be worked upon. This issue speaks to one of the best, most interesting, most enabling new capabilities of http 2, and leaving it chronically un-usable is so sad.

@jakearchibald
Copy link
Collaborator

A lot of PUSH stuff was removed from Chrome https://groups.google.com/a/chromium.org/g/blink-dev/c/K3rYLvmQUBY/m/vOWBKZGoAQAJ

@mitar
Copy link

mitar commented Feb 22, 2022

Nothing has been removed from Chrome (yet).

@jakearchibald
Copy link
Collaborator

I'm pretty sure we never enabled PUSH over HTTP/3

@mitar
Copy link

mitar commented Feb 22, 2022

So? Your comment was that that PUSH was removed from Chrome, referencing a mailing list post where nothing to that effect was posted, but only that there is an intend and that they are conducting an experiment. So, what exactly has been already removed?

@rektide
Copy link

rektide commented Feb 22, 2023

This should still be followed up on, even if it's winter-cg that can use it & the browsers remain unmoved about letting dev's ever explore what the world could do with push.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
addition/proposal New features or enhancements topic: api
Development

No branches or pull requests

8 participants