cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: how to use http/2 server push?

From: Ray Satiro via curl-library <curl-library_at_cool.haxx.se>
Date: Mon, 04 May 2015 21:54:06 -0400

On 5/4/2015 8:11 AM, Daniel Stenberg wrote:
> Anyone around who has been thinking about using HTTP/2 and server push
> in an application? Server push means that a new stream is initiated
> from the server without the client specifically asking for it.
> Typically it would be resource B that the server thinks the client
> wants since it asked for resource A. Like in a web scenario it could
> be the CSS if the client asked for the html.
>
> A client can of course deny it (or disallow it completely in the first
> place), but how would you like the API for libcurl to expose this
> functionality?
>
> Method 1:
>
> I started out thinking we should have an option that allows us to
> setup an easy handle and add it to the multi handle just idling until
> the server (might) do a push. This is rather inflexible and forces the
> application to know before-hand how many pushed streams it'd like.
>
> Method 2:
>
> We would (somehow) dynamically create a new easy handle and stream for
> a pushed resource and allow the application to deny it or to receive
> it like an ordinary transfer. The creation of the easy handle would
> probably then have to be presented to the application with a callback
> or something and the application would then have to setup options etc
> for the transfer (like write callback etc). We could also imagine the
> application being allowed to cancel such a request.
>
> Method 3:
>
> I'm sure we can think of other ways. What do you think?
>

1 by itself seems impractical, if not now then in the future. The advent
of push and multiplexing could lead to a lot of resources being pushed.
Resources that were once inline are no more; would-be same-origin
resources that were once sparse on several servers are no more. The
flexibility to handle push and stream priority/dependency will be crucial.

If I was contributing code to help implement this (it's not likely,
sorry) I'd model to the maxim you don't pay for what you don't use. I'd
disable server push by default and I'd expose
SETTINGS_MAX_CONCURRENT_STREAMS for when it is enabled. I'm not saying
you must know how many streams or only beforehand as in 1.

I'm unclear on whether push stream DATA is sent immediately following
the push of (promise) headers to the client or whether the client needs
to give some explicit approval first. I'm guessing the former because of
latency but really I don't know. The spec in section 8.2.2 Push
Responses [1] says "Once a client receives a PUSH_PROMISE frame and
chooses to accept the pushed response,...". Does that mean approval
required? In other words do clients have to signal the server to start a
push stream's DATA or does it start on its own?

If push data starts on its own (and assuming that's not preventable via
flow control setting) you'd need internally at least an object for each
stream. Again that may sound like 1 but it's not, at this point it's
abstract to the user. Internal stream objects (buffers basically) are
automatically created and receiving data. Then while all that is
happening call the user's callback like you say in 2 as a push-notify
and offer a helper function to transition to an easy handle:

CURLPUSHcode push_cb(curl_http2_stream *foo) {
// foo was pushed
if(find(foo->resource, accepted_urls) && check_headerorsomething(foo)) {
CURL *bar = curl_stream_to_easy(foo, INHERIT_FROM_PARENT);
// bar is created and is in the same multi as foo's parent
set_my_options(bar);
// user sets options for bar (some of which will be ignored
// curl_easy_init does nothing here. returning "starts" the transfer
which has actually already started but the application will process it
as just started
return CURLPUSH_ACCEPT; // again don't know about this
}
return CURLPUSH_REJECT; // don't know about this either..set some error
code to pass to server for the reject?
}

I don't like it now that I see it written out. It's an easy handle but
it can't use many of the options of an easy handle. How about a new
handle type curl_push_handle and make the easy handle options that do
work backwards compatible so users can use their existing set_options
functions.

CURLPUSHcode push_cb(curl_push_stream *foo) {
if(!check(foo)) {
return CURLPUSH_REJECT; //?
}
set_my_options((CURL *)bar); //or maybe set_my_push_options(bar)
curl_push_perform(bar); // this is non-blocking
// now the application's callbacks set on bar are called as if the
transfer just started
return CURLPUSH_ACCEPT; //? don't stop receiving data
}

I'm rambling now I suppose but maybe something here is beneficial.

[1]: https://http2.github.io/http2-spec/#PushResponses

-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
Received on 2015-05-05