Search code examples
phphttp2litespeed

HTTP/2 Server Push not working, what am I doing wrong?


This is my first question here, hope I'm doing it right.

I'm using a LiteSpeed webserver with HTTP/2 (shared hosting provider), but I can't get the push feature to work. I'm not quite sure how to check if it works, but at least as far as I can tell it isn't working properly.

So I have looked up a ton of guides (HTTP/2 Server Push Tutorial or A Comprehensive Guide To HTTP/2 Server Push as examples), and they all mention changing the headers by adding the following:

link: </my/theme/css/style.css>; rel=preload; as=style

I understand that this code tells the server to preload said resource, in this case style.css. However, if the server supports HTTP/2 push, then it should automatically push the resource instead (as long as you don't add nopush at the end of it). The second link does mention that this is true for most, but not all servers.

So with this in mind, I created a simple test PHP page to see if I could get it working. The result was this:

Chrome DevTools showing Headers tab with link preload

Network tab in DevTools showing the result

So most of the guides I saw mentioned that the Initiator in the Network tab for the pushed resource would say Push / Other (or similar) instead of just Other, but as you can see from my result it just says Other. Not to mention that the resource doesn't get loaded in the same request, it just looks like a simple preload to me. I also tested my site with https://http2.pro/check, and it says no resource is pushed.

This was tested with Chrome 71.0.3578.98.

  • Am I missing something important here? Could it be a problem with my server?
  • Another question. When defining multiple resources in the headers for preload and push, some guides mention creating multiple link-elements, while others mention comma separating them in a single link-element. Are both of these correct, is one better than the other?

Any help or enlightenment is appreciated, thanks!


Solution

  • First of all you need to find out if your infrastructure uses Link headers to activate push. Litespeed documentation doesn't seem great here but let's assume that is how you activate push.

    Next is to check if your server is sending the pushed request. I find nghttp the best tool to do this so if you have access to this too, then run a command like this to see the HTTP/2 frames and if the PUSH_PROMISE frame is sent, indicating the style sheet is being pushed:

    nghttp -anv https://www.example.com
    

    You can also see the frames using Chrome, though they've just made this a lot harder but insisting on logging to disk first and then opening in a viewer. Follow the instructions similar to @LucasRolff's answer, but for HTTP/2 or here.

    Assuming the server is pushing the resource you're next left with why Chrome is not using that pushed resource. The most common reason is if you are using a self-signed TLS certificate to provide HTTPS that the browser does not recognise. Even if you click through the error and get a connection with a red padlock, Chrome will not use the cache for that connection, and so cannot use HTTP/2 push (which requires using the HTTP/2 push cache). The nghttp or Chrome event log output should show if this is the case. Alternatively try using Firefox which DOES allow HTTP/2 push to be used if unrecognised certificates are clicked through.

    Finally to your last question:

    When defining multiple resources in the headers for preload and push, some guides mention creating multiple link-elements, while others mention comma separating them in a single link-element. Are both of these correct, is one better than the other?

    Both are correct. HTTP (whether HTTP/1.1 or HTTP/2) defines this:

    header1: value1
    header1: value2
    

    and this:

    header1: value1, value2
    

    as syntactically identical:

    A recipient MAY combine multiple header fields with the same field name into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field value to the combined field value in order, separated by a comma.