Test if your web server supports http/2.0 or spdy via Protocol Negotiation

Cloudflare started to support http/2.0 in production environment yesterday(HTTP/2 is here! Goodbye SPDY? Not quite yet), not like NGINX open source version(NGINX Open Source 1.9.5 Released with HTTP/2 Support), which dropped spdy support, Cloudflare supports them both like Google and Facebook does. Cloudflare is not the first CDN company to support http/2, KeyCDN launched there http/2.0 support from the early Oct 2015(KeyCDN Launches HTTP/2 Support), cdn77 started their http/2.0 support since Aug 2015(HTTP/2 Support for All Customers), but both of KeyCDN and cdn77 doesn’t support http/2 + spdy, now Cloudflare supports both, so maybe it’s just worthy(BTW, akamai also support them both), without a doubt it’s a good very good news to us, but how to test if a web server support http/2.0? Here we go.

In the beginning, I think you should know a little bit about the Application-Layer Protocol Negotiation , on Wikipedia:

Application-Layer Protocol Negotiation, on Wikipediais a Transport Layer Security (TLS) extension for application layer protocol negotiation. ALPN allows the application layer to negotiate which protocol should be performed over a secure connection in a manner which avoids additional round trips and which is independent of the application layer protocols. It is used by HTTP/2.

We can use TLS-ALPN to get the supported protocols by the server desired order, here we will use OpenSSL client as an example.

On OpenSSL man page:

-nextprotoneg protocols
enable Next Protocol Negotiation TLS extension and provide a list of comma-separated protocol names that the client should advertise support for. The list should contain most wanted protocols first. Protocol names are printable ASCII strings, for example “http/1.1” or “spdy/3”. Empty list of protocols is treated specially and will cause the client to advertise support for the TLS extension but disconnect just after receiving ServerHello with a list of server supported protocols.

The syntax should be like this:
openssl s_client -nextprotoneg NULL -servername host.domain.name -connect host.ip.or.domain:port

Because there may be many domains pointing to a same IP address, we should tell the server which domain we are going to connect by servername, and I don’t want to get a verify error, so I will also tell OpenSSL the path we store certificates by CApath, for example, on Ubuntu 14.04 LTS:

We will get this result:

depth=2 C = IL, O = StartCom Ltd., OU = Secure Digital Certificate Signing, CN = StartCom Certification Authority
verify return:1
depth=1 C = IL, O = StartCom Ltd., OU = Secure Digital Certificate Signing, CN = StartCom Class 1 Primary Intermediate Server CA
verify return:1
depth=0 C = TW, CN = www.peterdavehello.org, emailAddress = hsu @peterdavehello.org
verify return:1
Protocols advertised by server: h2, http/1.1

Which means www.peterdavehello.org wanna use http/2.0 first, and then http/1.1, if you do this test on www.google.com, you’ll get another result like this:

depth=3 C = US, O = Equifax, OU = Equifax Secure Certificate Authority
verify return:1
depth=2 C = US, O = GeoTrust Inc., CN = GeoTrust Global CA
verify return:1
depth=1 C = US, O = Google Inc, CN = Google Internet Authority G2
verify return:1
depth=0 C = US, ST = California, L = Mountain View, O = Google Inc, CN = www.google.com
verify return:1
Protocols advertised by server: h2, spdy/3.1, http/1.1

So we know that Google supports http/2.0, spdy/3.1 and http/1.1!

The funniest thing I noticed is that the result of Facebook is a little bit more complex and also unstable, test result 1:

depth=3 C = US, O = GTE Corporation, OU = “GTE CyberTrust Solutions, Inc.”, CN = GTE CyberTrust Global Root
verify return:1
depth=2 C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root
verify return:1
depth=1 C = NL, L = Amsterdam, O = Verizon Enterprise Solutions, OU = Cybertrust, CN = Verizon Akamai SureServer CA G14-SHA2
verify return:1
depth=0 C = US, ST = CA, L = Santa Clara, O = Akamai Technologies Inc., CN = http2.akamai.com
verify return:1
Protocols advertised by server: h2, h2-14, spdy/3.1, spdy/3, http/1.1, http/1.0

Test result 2:

depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High Assurance EV Root CA
verify return:1
depth=1 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert SHA2 High Assurance Server CA
verify return:1
depth=0 C = US, ST = CA, L = Menlo Park, O = “Facebook, Inc.”, CN = *.facebook.com
verify return:1
Protocols advertised by server: spdy/3.1-fb-0.5, spdy/3.1, spdy/3, http/1.1

I guess Facebook is still testing their http/2.0 feature.

nginx now supports http/2.0

From this commit: 257b51c37c5a: The HTTP/2 implementation

The HTTP/2 implementation (RFC 7240, 7241). The SPDY support is removed, as it’s incompatible with the new module.

nginx http/2.0 support has been implemented since 12 days ago, and the SPDY support was removed, the new version came after, nginx v1.9.5 was tagged since 39 hours ago, we can now download it from its download page, and there are also linux pre-built packages: http://nginx.org/en/linux_packages.html

For more info about http 2.0, see the links below: