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
implement HTTP/2 server push #133
Conversation
…aming it to `open_pull`, as pushed streams should be counted separately)
…ngle hpack header element into multiple HTTP2 frames)
At the moment, the status is:
To test the feature, I have applied this patch so that it would send
However, looking at the log it is obvious that Firefox sent a pull request for the same CSS file, even though it had been already pushed. So we need to find out the reason why (does Firefox Nightly already support server-push?) (note: EDIT: the situation was the same for Chrome 42.0.2293.0 canary. |
@bagder @igrigorik Do you have any information regarding the status of server push support in Firefox / Google Chrome? The browsers do not seem to use the the CSS file being pushed. They simply ignore it, and sends an ordinary pull request for the file. Thank you in advance for your help. |
Firefox supports push for sure in Nightly, but I can't remember exactly when the support (will) exist in stable versions. I'll ping hurley and mcmanus to see if they can bring some insights here. |
@bagder Thank you for the quick response and for pinging your colleagues.
Hmm. That makes me wonder why it is sending a request to a file that has already been pushed. Maybe is it due to the response headers sent along with the push? I believe H2O is sending something like https://gist.github.com/kazuho/1c891149199f5ac2e971 |
I'm willing to bet the issue with Nightly is https://bugzilla.mozilla.org/show_bug.cgi?id=1127618 given that e10s is enabled by default on Nightly. @kazuho - if you try disabling e10s via Preferences -> General -> Uncheck "Enable E10S (multi-process)" and then restart Nightly (required to disable e10s), does push work for you with Nightly? If not, then we'll have to dig deeper, but that's a good first place to start. |
https://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-5.3.5
|
… they can be cancelled silently, without sending RST_STREAM or DATA(END_STREAM)
@todesschaf Thank you very much for the suggestions. I have found and fixed a number of bugs in H2O. With the changes up to 94c42b5, and e10s disabled on Firefox Nightly (380.a1 2015-02-03), server push is working like a charm. With this patch applied to the file handler to send the CSS files, the access log of H2O is printed as follows.
It is also evident from the Network panel of Nightly that server push is working, as the note: transfer of I will continue working on the server push support in H2O to make it easier to be used by programmers / system administrators. |
Thank you for the suggestion. The problem is that when sending CSS files using server push, they need to be given higher priority than the HTML file that uses the CSS files (since it is totally impossible to render the HTML without having a complete set of CSS files, while it is possible to progressively render HTML when once all the CSS files become ready). In other words, IMO the default behavior to make CSS streams dependent to the HTML stream is inappropriate in this case. EDIT: Ideally speaking, pushed streams should be given the same priority as if it were being pulled. The question is what the best approximation is. |
…any streams being pulled
Confirmed that server push also works with Chrome Canary (42.0.2294.0) using the H2O configuration described in #133 (comment). However, as Canary sets the weight of HTML to 256, there was a need to set even higher priority for CSS files to be sent before the HTML (8907f2e). Using a weight value of 257 is not a problem even though it exceeds the bounds defined by the HTTP2 spec., since the value is never exposed over the network. note: the internal weights are never exposed to the client, as sending |
Conflicts: include/h2o/string_.h
…tp2_conn_push_url
Yeah! Using Chrome Canary I see weights of 256 (HTML), 220 (CSS), 183 (JavaScript), 110 (images), which corresponds to your description.
Thank you for the clarification. Looking forward to see improvements to / experiments on the browser side.
Thank you for pointing that out. Stepping back from comparing between the weight numbers or dependencies, what would be the ideal approach? Would it be something like: send the HEAD element of the HTML first, then push the contents of the CSS / JavaScript files (that block the renderer), and then send the BODY element? If the approach sounds like a good way for most of the cases, it might be worth to consider adding a one-shot feature (i.e. send DATA only once at a very high weight and then return to the original weight) to the HTTP/2 scheduler of H2O.
I agree that the view better describes the situation (than what I had expected). |
…` header and push the contents if possible
Thank you all for your advises, the feature has successfully been merged to master. The reverse proxy module of H2O now recognizes a response header called The syntax of the header is: It is unfortunate that I have to close this PR even though interesting discussions are ongoing; it seems like there is no way to keep a PR open after merging the code. I would appreciate it if you could post suggestions from now on to #137. Please let me express my gratitude to your help in implementing / improving support for server push in H2O. |
~ish, yeah. Typically, we don't need all of the CSS or JavaScript to get visible content on the screen, and this is where the app developer needs to step in and provide the right context to the server - e.g. push these CSS and JS bytes alongside the HTML response to deliver a fast first render, then stream remaining markup to fill in the remaining bits.
I do like the idea of allowing "send X bytes of resource Y then yield it and use a lower priority for the rest". This would be useful for streaming initial HTML payload for large pages, and/or even images: I wan to stream header of the image to allow the UA to decode its geometry and perform layout (if progressive, then a rough preview as well), but I'll stream the image bytes themselves later after other more critical resources. Also, as an aside... Given that HTML is often dynamic and takes some time to generate, whereas CSS/JS is typically static, I'm guessing that even if we set them at same priority.. a good fraction of CSS/JS bytes will still come in front of HTML due to the associated app server response time delays. |
@igrigorik
Sounds interesting. Such a feature can definitely be implemented within the reverse proxy. As a note, redirections can be made faster by using server push. Proxies can monitor if |
Awesome work, @kazuho. |
As for header field to instrument resources to push, Link header field might be a good candidate: http://www.chromium.org/spdy/link-headers-and-server-hint/link-rel-subresource |
FWIW, our plan is to retire subresource in favor of "preload", see: http://w3c.github.io/preload/ |
@tatsuhiro-t Thank you for the comment. That is a good question. The fact is, I have cowardly limited the headers to be copied for building push responses (see 812dec8 for an example). The reason consists of two points described below.
After reading your comments (esp. the lines regarding the |
Sounds interesting. Although I am not excluding such possibility, however, regarding the issue of discovering the resources to be pushed my tendency goes to using response headers (as has been implemented by this PR) or using a mapping file for statically served contents, In case of automatic discovery, it is important to not have false positives. We would never want to push a resource that would not be used. That means that we would need a sophisticated parser for discovering the resources (e.g. the parser that extracts the So I believe that for the short term it would be better to use headers or mapping files for specifying the resources that should be pushed. Users can write the mapping files by hand, or use a tool (likely to be written in scripting languages) to extract the URLs of the resources that need to be pushed (and then possibly adjust the list by hand). EDIT: As an afterthought, if I were to implement such automatic discovery I would spawn an external filter that extracts the necessary resources for frequently served contents, and associate the results to the cache entry so that the associated contents can be pushed for future requests arriving to the resource. |
@kazuho I'd start with basic
^ This tells you the resource that could/should be pushed and its type, which can help determine priority. For more, see: http://w3c.github.io/preload/#interoperability-with-http-link-header |
@igrigorik Thank you for pointing that out. It is clear that I did not read @tatsuhiro-t's comment carefully enough. My apologies. |
Yeah, I was a bit short of words, I mean Link header field and no link element in HTML. |
FYI as of 85f4471 H2O recognizes |
@kazuho \o/ ... woot! Time to run some experiments... |
Great! https://nghttp2.org also enabled server push using Link header field, so we have suddenly 2 implementations using preload relation, which sounds very exciting. |
still wip
relates to: #50