mod_h[ttp]2

HTTP/2 for Apache httpd

HTTP/2 gets a PUSH (in 2.4.18)

Copyright (C) 2015 greenbytes GmbH

There are several new things coming for HTTP/2 in the upcoming release 2.4.18 of Apache httpd. And one of them is PUSH. This post talks about the implementation of this protocol feature and all the other things that will be included.

Server Push

HTTP/2 Server Push means that a server can send responses to a client which it never asked for. Such pushes need to be tied to a request that originated from the client. That has the advantage that the client has context to process these responses. Imagine a browser opening two tabs, requesting two pages. Tying pushes to requests makes it clear to the browser which push belongs to which. So, if the user closes one tab, the browser knows which responses to cancel.

As a rule of thumb, the page load time is affected by the RTT, the round trip time, between your server and a client. If a client needs to send a request for a resource, that sending will take RTT/2 time to travel to the server. And the response needs RTT/2 to travel back to the client. So, when a server pushes responses to the client, it saves half the RTT for that resource.

Will that save RTT/2 in page load time? That depends. There are several resources in a web pages, where saving this time will not affect page load time, as a lot of other stuff is happening and this particular resource is not blocking anything else. In such a case, it is better to omit the push. Not the least because the client may already have it in its local cache from a previous visit!

So, you need to select the candidates for pushes carefully. But for motivation, there are page scenarios where push saving can really add up. That happens when vital resources are daisy chained, when the browser needs to see the content of resource A to find out that it needs to load B and then it finds out it needs to load C, etc. Pushing A+B+C at the same time can then save 1.5 times the RTT.

H2Push

The new directive

H2Push on|off
let's you control where server pushes are enabled. You can use it in server or vhost configurations. It is on by default. And it of course only works for clients that allow it. Which, fortunately, is Chrome, Firefox and others do. However Safari 9 does not.

How does it work? The implementation of HTTP/2, mod_h[ttp]2, looks at the headers of responses for ones which are named Link with the rel parameter value preload. An example of such headers would be:

Link: </css/my.css>;rel=preload
Link: </js/jquery.js>;rel=preload
and those will result in these resources to be pushed. You can combine several links into a single header, such as
Link: </css/my.css>;rel=preload, </js/jquery.js>;rel=preload

Where do these headers come from? Either your cgi/php/whatever application sets them or you can use mod_header to define those for certain locations. An example would be:

<Location /index.html>
    Header add Link "</css/my.css>;rel=preload"
    Header add Link "</js/jquery.js>;rel=preload"
</Location>

H2PushPriority

Another new directive related to server pushes is

H2PushPriority  mime-type  after|before|interleaved  weight
which set the ordering and priority with which pushed responses are sent out.

You need a nghttp2 library version 1.5.0 or newer for this to have an effect!

Explaining HTTP/2 priorities is a topic of its own. Happily, other people have already talked about it. There is Moto Ishizawas very nice explanation of HTTP/2 priorities, and there is Tatsuhiro Tsujikawa's explanation of his implementation in nghttp2.

tl;dr
The higher the weight, the more gets send out the sooner. This happens either after the requested resource has been sent, or before or interleaved with it.

The following is an example of how you can use the directive:

H2PushPriority *                      after
H2PushPriority text/css               before
H2PushPriority image/jpeg             after        32
H2PushPriority image/png              after        32
H2PushPriority application/javascript interleaved
There is a special rule for '*' which is a catchall that applies to all resources that do not find a specific rule. The order in which you use the directive is irrelevant. If you leave out the weight, defaults are chosen depending on the ordering you specified. The default when no rules are specified is after 16.

It will be interesting to hear from people how they use it for their sites and what they observed. A little more detail about the effects, defaults and consequences you can find at the mod_h[ttp]2 documentation once 2.4.18 is released.

TLS, Multidomain Certificates, Client Certificates

Several improvements habe been made in the area of TLS:

Multidomain Certificates

A thing that had bitten several people in the 2.4.17 release was the lack of support for connection reuse. In HTTP/2, when you have the same certificate for a.exmple.org and b.example.org, browsers will reuse any open connection they have for requests to the 'other' domain. But Apache did not allow that, answering with a 421 response code defined in the HTTP/2 spec for such a case. Some browsers did not handle that very gracefully.

In 2.4.18, any such connection reuse is allowed, as long as both domains have exactly the same SSL protocol settings.

TLS Renegotiation

Another improvement done to the TLS handling in mod_h[ttp]2 is that requests which trigger client certificate authentication or any other renegotiation of TLS parameters, are aborted with the specific HTTP1_1_REQUIRED error code. This informs the browser that the request should be done using the HTTP/1.1 protocol.

People in standardization are working on defining TLS client authentication for HTTP/2, but things are not done yet. So sites which need client certificate need this feature.

Modern TLS, Warmup and Cool-down

With the new directive

ModernTLSOnly on|off
you can control if mod_h[ttp]2 only accepts TLS connections which are secured as specified in RFC 7540 or should be totally relaxed about it and use HTTP/2 however you configured your SSL parameters. By default, the rigid checks are on and if your server expects to use HTTP/2 with common browsers, this is what you want.

With the new directives

H2TLSWarmUpSize     bytes
H2TLSCoolDownSecs   secs
you can fine tune how TLS record sizes should be chosen on a HTTP/2 connection. TLS record sizes can vary from 1 byte up to 16K, but there is always some overhead involved with each record. So, best throughput is achieved with 16K sizes. Unless you are on the real internet or even a cellular network and a packet might get lost and your TCP protocol is not yet certain what window size is best, etc.

Ilya Grigorik has written a whole book about such things and is full of good advice about web performance tuning. His recommendations for these parameters are 1MB of data for warmup (e.g. until 16K record sizes is preferred) and 1 second for cool-down, after which an idle connection is reset to the starting size of 1300 bytes records.

If you use your Apache in more controlled environments, like your LAN, you can disable this tuning by setting both parameters to 0, making mod_h[ttp]2 use 16K record sizes whenever possible.

Throughput

I wrote something about the throughput improvements a while ago and this code gets also shipped with 2.4.18. Enjoy!

One thing I'd like to add to performance measurements: they vary with the mpm module you use and the OS you are on. From the three available mpms prefork and worker show the best performance with mod_h[ttp]2, while event lags behind. The reason is that mod_h[ttp]2 does not play nice with event right now and needs some internal changes to make best use of it.

Trailers

As a last point, a somewhat, so far ivory towerish feature has been added and that is support for trailers. But what are trailers, you may ask?

In HTTP, trailers are the same as headers, meta data about the resource, only send after the request/response body, not before like headers. It's like post scriptums added to a letter (if anyone still knows what that is).

Trailers were introduced in HTTP/1.1 and, to stay backward compatible to HTTP/1.0, only worked when transfer encoding chunked was used. Which no one really wants to use only for that and so it was never used much and so implementations are limited.

In HTTP/2 however, trailers work for every request and response. This is nice if you want to implement a HTTP/1.1 to HTTP/2 gateway and, eventually, need to transfer trailers back and forth. Or if you use Apache as a HTTP/2 proxy to a HTTP/1.1 host.

Availability

You can get Apache releases from here. Expect the 2.4.18 release to show up there sometime beginning of December.

M√ľnster, 26.11.2015,

Stefan Eissing, greenbytes GmbH

Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. See LICENSE for details.