Okhttp: HTTP/2 Server Push (again...)

Created on 16 Jul 2018  ·  11Comments  ·  Source: square/okhttp

Would we consider supporting HTTP/2 server push now?

Adoption is still minuscule, and wins are not clear. https://blog.apnic.net/2018/04/26/adoption-performance-and-human-perception-of-http-2-server-push/

Mainly curious as it comes up related to DNS over HTTPS. Could be a nice optimisation there. But that is still 50/50 anyway. So just asking the question for now.

Previous
https://github.com/square/okhttp/issues/3106
https://github.com/square/okhttp/issues/856
https://github.com/square/okhttp/issues/607

enhancement

Most helpful comment

Push client support looks decent

https://dev.to/meyer9/http-2-server-push-explained-4gh

image

But I've only really found test servers using it. Nothing compelling to say implementing it would help more than a few specific users. So I agree, and I'll close this issue unless we decide to support.

$ okurl --frames https://http2-push.appspot.com/
>> CONNECTION 505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
>> 0x00000000     6 SETTINGS
>> 0x00000000     4 WINDOW_UPDATE
<< 0x00000000    18 SETTINGS
<< 0x00000000     4 WINDOW_UPDATE
>> 0x00000000     0 SETTINGS      ACK
<< 0x00000000     0 SETTINGS      ACK
>> 0x00000003    38 HEADERS       END_STREAM|END_HEADERS
<< 0x00000003   164 PUSH_PROMISE  END_PUSH_PROMISE
<< 0x00000003    27 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x00000002     4 RST_STREAM
<< 0x00000003    28 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x00000004     4 RST_STREAM
<< 0x00000003    53 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x00000006     4 RST_STREAM
>> 0x00000008     4 RST_STREAM
<< 0x00000003    49 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x0000000a     4 RST_STREAM
<< 0x00000003    50 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x0000000c     4 RST_STREAM
<< 0x00000003    54 PUSH_PROMISE  END_PUSH_PROMISE
<< 0x00000003    26 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x0000000e     4 RST_STREAM
>> 0x00000010     4 RST_STREAM
<< 0x00000003    35 PUSH_PROMISE  END_PUSH_PROMISE
<< 0x00000003    60 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x00000012     4 RST_STREAM
<< 0x00000003    46 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x00000014     4 RST_STREAM
<< 0x00000003    59 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x00000016     4 RST_STREAM
<< 0x00000003  1115 HEADERS       END_HEADERS
>> 0x00000018     4 RST_STREAM
<< 0x00000003  2262 DATA
<< 0x00000003  1339 DATA
<< 0x00000003     0 DATA          END_STREAM

All 11 comments

I wanna do it with fancy joining & canceling. It's difficult cause it requires some rework of our cache persistence.

@swankjesse In no way shall this be taken as offense - but have you considered working on this in the meantime? Closing feature requests to refer them here, where the last activity was in 2018, is somewhat awkward.

I suppose many devs will eventually move to Java 11's native HttpClient (supporting Server Push natively) which would be a shame, with OkHttp having reached its state-of-the-art-library status.
Indeed, while you may consider Server Push a nice-to-have feature, the nonexistence of the feature is a showstopper for servers with billions of daily client requests.

@swankjesse is it awkward because of a non user controlled request? i.e. we'd need some hook to allow clients to cancel when it gets triggered?

Or matching against the cache.

@Harti do you have specific examples you want to support from API or Web servers? I'd love to understand the typical usage.

General use cases encompass (but are not limited to):

  • Batch requests resulting in multiple responses

    • Significant: Eliminates round-trip and connection pool overheads of having to make N separate requests (the Headers can sum up and get very data hungry quickly); furthermore connectivity issues are alleviated more easily (N small downloads vs. one big download)

    • Neat: No longer required to define proprietary API error/success codes for each returned item (server sends Http statuscodes for each push); fewer workers required on webserver side; and you get fewer requests (and less RX traffic) at your server (only 1 instead of N).

    • Nice-to-have (better UX): The data trickles in at the client side, as opposed to having to wait for the whole batch to be processed and downloaded.

  • Requests that may serve a result instantly (200/204/304), or at a later time (202)

    • In HTTP/1.1 you'd manually evaluate the 202 Retry-After headers and schedule a request.

    • In HTTP/2, with server push, the connection could be kept open and the processed result could be pushed.

  • Requests which the server thinks should receive additional data/files for

    • For instance, when you request index.html, and the server already knows that you will also need style.css, hero-banner.png and app.js, and pushes these resources along. (Many websites already do this, and our browsers deal with it automagically.)

Alas, I cannot currently offer a working example of a server-push endpoint for development and evaluation. Should that be a precondition I shall try to assist with finding a working example.

I'm familiar with the concept. More interested how prevalent this is for usecases that OkHttp would generally also be used for. A real world use as an example to test against.

It's probably not _prevalent_, but for any application wanting to display any list of backend-served data where an item consists of both textual information and (an) image(s), it would serve most useful for the reasons explained above.

(Maybe I'm missing the actual question, I'm sorry)

Yes. First, what your usage is. Second, not how useful it can be for one specific private API. More how adoption is overall in the wild.

I do not have objective measures for an expected adoption rate and it's not something I can argue for beyond this opinion.
Developers would need to adjust to this on both client and backend side, which is something that will only happen over the years. Quite unlikely that many would, as the paradigm is fairly complex and unexplored (or they have been using Websockets instead). The benefit over regular HTTP/2 (or HTTP/1.1) overhead isn't really relevant to most low-/medium-scale applications. (I wonder if adoption was already higher if the feature already existed in OkHttp and was advertised through the docs? Reminds me of the chicken/egg paradox.)

I don't mean to sound entitled to this feature at all - just wanted to friendly ping you since it's something you've seemingly been wanting to do, and it's probably _the_ most talked about feature when researching how to leverage HTTP/2.
If it doesn't bother you that developers requiring such functionality might eventually move away from OkHttp and instead use Java's HttpClient (especially once Android supports JDK 11), then I agree that the general library benefit isn't big enough to warrant the implementation effort. In that case I suggest this ticket be closed as "won't do".

I must not disclose my exact usage scenario, but for what it's worth, here is the general idea:

From an OAuth-protected API, JSON data (text/json) and unknown related data of incompatible content types (e.g. image/webp) are fetched. For one, some data may not be there yet and are generated on-demand. The most crucial point however is to keep the total data usage footprint low by avoiding unnecessary outbound requests (and avoiding unnecessary inbound transfer of image URLs and the proprietary evaluation of those which makes the code extremely messy).

Instead of 100 subsequent requests (with 100 responses), 1 request should be made (with the same 100 responses, except asynchronously received, handled either with regular Callbacks or Observables/Promises) - effectively reducing traffic incurred by HTTP Headers by up to 50% (though HPACK will mitigate some of this).

I think we should abandon server push and instead support early hints. It's a better design that avoids a lot of the drawbacks of server push.
https://tools.ietf.org/html/rfc8297

[edit: #3671]

Push client support looks decent

https://dev.to/meyer9/http-2-server-push-explained-4gh

image

But I've only really found test servers using it. Nothing compelling to say implementing it would help more than a few specific users. So I agree, and I'll close this issue unless we decide to support.

$ okurl --frames https://http2-push.appspot.com/
>> CONNECTION 505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
>> 0x00000000     6 SETTINGS
>> 0x00000000     4 WINDOW_UPDATE
<< 0x00000000    18 SETTINGS
<< 0x00000000     4 WINDOW_UPDATE
>> 0x00000000     0 SETTINGS      ACK
<< 0x00000000     0 SETTINGS      ACK
>> 0x00000003    38 HEADERS       END_STREAM|END_HEADERS
<< 0x00000003   164 PUSH_PROMISE  END_PUSH_PROMISE
<< 0x00000003    27 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x00000002     4 RST_STREAM
<< 0x00000003    28 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x00000004     4 RST_STREAM
<< 0x00000003    53 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x00000006     4 RST_STREAM
>> 0x00000008     4 RST_STREAM
<< 0x00000003    49 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x0000000a     4 RST_STREAM
<< 0x00000003    50 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x0000000c     4 RST_STREAM
<< 0x00000003    54 PUSH_PROMISE  END_PUSH_PROMISE
<< 0x00000003    26 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x0000000e     4 RST_STREAM
>> 0x00000010     4 RST_STREAM
<< 0x00000003    35 PUSH_PROMISE  END_PUSH_PROMISE
<< 0x00000003    60 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x00000012     4 RST_STREAM
<< 0x00000003    46 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x00000014     4 RST_STREAM
<< 0x00000003    59 PUSH_PROMISE  END_PUSH_PROMISE
>> 0x00000016     4 RST_STREAM
<< 0x00000003  1115 HEADERS       END_HEADERS
>> 0x00000018     4 RST_STREAM
<< 0x00000003  2262 DATA
<< 0x00000003  1339 DATA
<< 0x00000003     0 DATA          END_STREAM

FWIW an interesting post on the implementation challenges for push https://jakearchibald.com/2017/h2-push-tougher-than-i-thought/

Was this page helpful?
0 / 5 - 0 ratings