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:

$ openssl s_client -CApath /etc/ssl/certs -nextprotoneg NULL -servername www.peterdavehello.org -connect www.peterdavehello.org:443 | grep ‘Protocols advertised by server’

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.