Nos están llegando consultas donde tras activar el soporte HTTP/2 en un servidor, se siguen viendo en los logs, trazadores de navegadores etc, peticiones HTTP/1.1. Esto ocurre, sobre todo, para webs con http:// (sin certificado).
Asumiendo que tiene correctamente activado el soporte HTTP/2 (que dependerá de cada servidor y software), usted seguirá viendo peticiones HTTP/1.1 cuando use accesos http:// sin certificado debido al mecanismo de UPGRADE.
Le explicamos todos los detalles.
Para usar HTTP/2, el navegador necesita actualizar/solicitar el protocolo
Cuando usted conecta a un servidor con HTTP:// (sin tls), su navegador tiene que hacer un UPGRADE para poder hacer un switch protocol y solicitar moverse de http/1.1 a http/2.
El navegador, a priori, y sin indicación adicional, no sabe qué protocolos soporta el servidor. De ahí que necesite entrar primero con http/1.1 (o TLS con APLN como ahora explicaremos), para poder solicitar el upgrade.
Para ello, con http:// (sin TLS) se usa la cabecera HTTP UPGRADE y para https:// (con TLS) se usa la extensión APLN para solicitarlo directamente.
En cualquier caso, el navegador solicita la activación del protocolo http/2, y para ello, tiene que hacerlo del modo que le sea posible, en función del protocolo usado (http:// o https://).
Cómo hace http:// el UPGRADE para usar HTTP/2
Esto se ve fácilmente ejecutando lo siguiente con un curl:
>> curl -vso /dev/null --http2 http://admon.webdominio.com * Rebuilt URL to: http://admon.webdominio.com/ * Trying 185.195.X.168... * TCP_NODELAY set * Connected to admon.webdominio.com (185.195.X.168) port 80 (#0) > GET / HTTP/1.1 > Host: admon.webdominio.com > User-Agent: curl/7.52.1 > Accept: */* > Connection: Upgrade, HTTP2-Settings > Upgrade: h2c > HTTP2-Settings: AAMAAABkAARAAAAA > < HTTP/1.1 101 Switching Protocols < Upgrade: h2c < Connection: Upgrade * Received 101 * Using HTTP2, server supports multi-use * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=28 * Connection state changed (MAX_CONCURRENT_STREAMS updated)! < HTTP/2 302 < date: Thu, 01 Jan 1970 00:00:00 GMT < server: Apache < x-powered-by: PHP/7.0.22 < set-cookie: PHPSESSID=o7odh6a4rfcpgcct47q9ebg1l7; path=/ < expires: Thu, 19 Nov 1981 08:52:00 GMT < cache-control: no-store, no-cache, must-revalidate < pragma: no-cache < set-cookie: anti-mentirosos=015ad02cbe55cdf6a3c94149a82c351c; expires=Fri, 29-Sep-2017 11:21:54 GMT; Max-Age=300 < x-frame-options: SAMEORIGIN < location: /login < content-type: text/html; charset=UTF-8 < { [0 bytes data] * Curl_http_done: called premature == 0 * Connection #0 to host admon.webdominio.com left intact
De hecho, tal es así, que cuando revisas los logs al ejecutar este comando o un acceso nuevo desde un navegador web, tendríamos:
==> /var/webs/webdominio.com/logs/access.admon.log <== 213.98.X.X - - [29/Sep/2017:13:23:01 +0200] "GET / HTTP/1.1" 101 426 "-" "curl/7.52.1" 213.98.X.X - - [29/Sep/2017:13:23:01 +0200] "GET / HTTP/2.0" 302 0 "-" "curl/7.52.1"
Es decir, ves dos conexiones, la primera HTTP/1.1 y la segunda actualizada a http/2.
Cómo hace https:// (con TLS) el UPGRADE para usar HTTP/2
En este caso, cuando usted use https://, al tener TLS de por medio, y requerir su activación primero, su navegador podrá optar por el soporte para APLN (Application Layer Protocol Negotation gracias a TLS).
Este soporte, no disponible en http:// (al no usar TLS), permite al navegador, directamente solicitar el http/2 sin tener que hacer la parte de HTTP UPGRADE de 1.1 a 2.0 como ocurre con http://
https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation
En la misma línea, cuando usted ejecuta la misma consulta con https:// , verá como curl solicita el UPGRADE de manera temprana, sin round-trip adicional, basándose en la cabecera APLN:
>> curl -vso /dev/null --http2 https://webdominio.com * Rebuilt URL to: https://webdominio.com/ * Trying 185.195.X.168... * TCP_NODELAY set * Connected to webdominio.com (185.195.X.168) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs * TLSv1.2 (OUT), TLS header, Certificate Status (22): } [5 bytes data] * TLSv1.2 (OUT), TLS handshake, Client hello (1): } [512 bytes data] * TLSv1.2 (IN), TLS handshake, Server hello (2): { [107 bytes data] * TLSv1.2 (IN), TLS handshake, Certificate (11): { [4371 bytes data] * TLSv1.2 (IN), TLS handshake, Server key exchange (12): { [333 bytes data] * TLSv1.2 (IN), TLS handshake, Server finished (14): { [4 bytes data] * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): } [70 bytes data] * TLSv1.2 (OUT), TLS change cipher, Client hello (1): } [1 bytes data] * TLSv1.2 (OUT), TLS handshake, Finished (20): } [16 bytes data] * TLSv1.2 (IN), TLS change cipher, Client hello (1): { [1 bytes data] * TLSv1.2 (IN), TLS handshake, Finished (20): { [16 bytes data] * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server accepted to use h2 * Server certificate: * subject: OU=Domain Control Validated; OU=PositiveSSL; CN=webdominio.com * start date: Dec 29 00:00:00 2016 GMT * expire date: Dec 29 23:59:59 2017 GMT * subjectAltName: host "webdominio.com" matched cert's "webdominio.com" * issuer: C=GB; ST=Greater Manchester; L=Salford; O=COMODO CA Limited; CN=COMODO RSA Domain Validation Secure Server CA * SSL certificate verify ok. * Using HTTP2, server supports multi-use * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 } [5 bytes data] * Using Stream ID: 1 (easy handle 0x55e2596979f0) } [5 bytes data] > GET / HTTP/1.1 > Host: webdominio.com > User-Agent: curl/7.52.1 > Accept: */* > { [5 bytes data] * Connection state changed (MAX_CONCURRENT_STREAMS updated)! } [5 bytes data] < HTTP/2 200 < date: Fri, 29 Sep 2017 11:29:36 GMT < server: Apache < x-powered-by: PHP/7.0.22 < set-cookie: PHPSESSID=paoduqu7gi1mn6d2g6fu0j3qq5; path=/ < expires: Thu, 19 Nov 1981 08:52:00 GMT < cache-control: no-store, no-cache, must-revalidate < pragma: no-cache < set-cookie: anti-mentirosos=9f6cd689235abbc753b43727b40bdaaf; expires=Fri, 29-Sep-2017 11:34:36 GMT; Max-Age=300 < x-frame-options: SAMEORIGIN < vary: Accept-Encoding < content-type: text/html; charset=UTF-8 < { [996 bytes data] * Curl_http_done: called premature == 0 * Connection #0 to host webdominio.com left intact
Resumiendo
Por tanto con http:// como con https:// es el navegador el que tiene que solicitar el “UPGRADE” a HTTP/2 (y el servidor aceptarlo ya que es opcional a día de hoy).
Para http://, ese UPGRADE consiste en una consulta HTTP/1.1 UPGRADE (lo cual requiere una ida con http/1.1, una vuelta con http/1.1 aceptando,y si es el caso, luego ya salta a http/2).
Para https:// ese upgrade se hace con APLN, directamente durante la fase de conexión y negociación TLS, de manera que se selecciona en el mismo paso tanto el certificado como la solicitud de activación inmediata del protocolo HTTP/2 (sin pasar por HTTP/1.1 y su UPGRADE).
Conclusiones generales
El protocolo http/2 tiene un encaje, casi a medida, con TLS ya que permite su activación directa, sin tener que pasar con http/1.1 (y su mecanismo de HTTP UPGRADE) justo en la fase temprana de negociación del certificado y su cifrado.
https://es.wikipedia.org/wiki/Cabecera_HTTP/1.1_Upgrade
De manera general, los navegadores no usarán HTTP/2 cuando solicite una web con http:// debido a que con http/1.1 se ahorra un round-trip con respecto a http/2. Por lo tanto, al navegador no le compensa (salvo que se le fuerce, lo cual es un tema distinto).
ShareSEP
Sobre el autor:
CTO at aspl.es. Linux sotfware developer http://github.com/asples and system administrator. Más en https://twitter.com/aspl_es, https://twitter.com/asplhosting y https://twitter.com/core_adm