HTTP3

HTTP/3 y QUIC

Introducción a HTTP

¿Qué es HTTP/3 y QUIC?, en este audio le dedico media hora para que puedas conocer qué es HTTP/3 y QUIC.

En 1996 se creó HTTP/1 y fue en 2015 cuando se creó HTTP/2, así que tuvimos 19 años entre las dos versiones principales de HTTP, y cuando ya creíamos que eso era inmutable ahora nos vienen con HTTP/3.

De hecho HTTP/3 viene del año 2015, así que tampoco es algo tan nuevo y el soporte en los navegadores está ya muy extendido.

Seguro que sabes que HTTP es un protocolo que funciona sobre TCP, bueno, que funcionaba, ahora iremos entrando en materia.

TCP ya sabéis que es un protocolo sobre IP. IP es el encargado de transportar los paquetes y TCP es el encargado de asegurar que esa conexión existe y de asegurar que esa comunicación se efectúa.

Ya sabes, todo empieza con desafío en 3 vías y todas esas cosas de las que ya he hablado en el podcast alguna que otra vez.

Una vez se ha establecido la conexión se convierte en una conexión totalmente confiable. Ya sabes que si se perdiera un paquete se pediría al origen que lo reenviara.

Y todo esto es maravilloso porque hace que la información que el servidor nos envía después de hacer un GET llegue en un orden concreto y eso es estupendo porque tenemos la información completa.

Al usar TCP puedo asegurar que es así y sabemos en qué orden tenemos que procesar los paquetes, bueno, segmentos porque hablamos de TCP.

Este modo de funcionar nos parece tremendamente obvio, seguro que piensas que claro que es así y tienes razón, pero a ti y a mi nos suena tan obvio y tan lógico porque estamos usando esa forma de trabajar desde hace 30 años.

HTTPS

A día de hoy esto va evolucionando y a día de hoy tengo la impresión que lo que más usamos, con mucha diferencia, cuando navegamos por Internet, este podcast por ejemplo, es una cosa llamada HTTPS.

HTTPS es http seguro, quizás esa sea la visión más simplista que existe y ya deberíamos de decir eso de que HTTPS es TCP + TLS + HTTP. Hemos añadido el Transport Layer Security sobre TCP

Esta aproximación tampoco es muy profunda pero desde luego más que http seguro, y ya es un poco más seria, así que recuerda HTTPS es TCP + TLS + HTTP.

Añadir TLS lo que hace es generar otro handshake, la misma filosofía que el desafío en 3 vías, para establecer la conexión TLS encima de TCP. Esto simplemente tenlo en la cabeza, sin más, pero eso es lo que nos añade la famosa seguridad, bueno y la privacidad también.

Por eso que te acabo de contar se dice que HTTPS es HTTP seguro, bueno, si no lo sabías, ahora ya sabes de donde viene la S.

Fíjate que cosa más buena, ahora puedo consultar una web que me da unos datos y nadie en medio puede leerlo porque el TLS se ha establecido entre tu ordenador, móvil o lo que sea, y el servidor.

HTTP/1.1

Volviendo al tema que me voy, el primer cambio realmente significativo en HTTP vino con la versión HTTP/1.1, en el año 1999.

Hasta 1999 cualquier conexión HTTP era secuencial, es decir, no se podía transmitir el siguiente elemento hasta que no terminara con el que estaba, eso era terrorífico.

Las webs en aquella época tampoco es que fueran muy sofisticadas, pero transmitir de forma secuencial en un sólo hilo no es lo más eficiente.

Así pues en 1999 con la versión 1.1 de HTTP ya se podían abrir varias conexiones TCP en paralelo, eso así en frío es una buena idea, pero TCP no está diseñado para ese funcionamiento.

En TCP la idea es levantar una sesión que quedará abierta durante un tiempo y se utilizará para enviar por ahí información, de hecho ese es el uso que la mayoría de los protocolos de aplicación sobre TCP hacen del protocolo, pero HTTP no.

En HTTP se levantan sesiones TCP para cerrarlas casi automáticamente, así que el uso de TCP es francamente ineficiente y contrario a su filosofía obviamente.

Pero aquí no vengo a hablar de la filosofía de TCP, aquí lo importante es que TCP no es un protocolo rápido, TCP necesita establecer la conexión, el tamaño de ventana y esas cosas.

Realmente el inicio de TCP es lento y si estamos constantemente levantando sesiones TCP pues estamos haciendo un uso malo que al final lleva a que las webs carguen mucho más lentas de lo que debieran. Aunque luego tengamos sistemas como el TCP Fast Open que nos permite reutilizar conexiones TCP.

Y aquí me puedes decir que HTTP/1.1 permite levantar varias sesiones TCP paralelas, es cierto, pero aquí tenemos un concepto muy chulo llamado Head-of-line blocking, el cual hace que una vez se agota el número de conexiones paralelas permitidas en el navegador (típicamente 6) tengamos el mismo efecto que si fueran conexiones secuenciales.

Y en HTTP/2, del que ahora te hablaré, pasa algo parecido porque aunque HTTP/2 elimine el bloqueo nos da igual porque al final TCP va a tener el bloqueo, así que estamos un poco mejor, pero al final tenemos el bloqueo igual.

Si perdemos un paquete de una de las conexiones multiplexadas al final va a afectar a todo.

HTTP/2

Para solucionar el problema de las múltiples conexiones TCP se inventó una cosa llamada HTTP/2 que multiplexaba las conexiones en una sólo, sólo una por host, de forma que ahora ya tenemos una conexión TCP que se alarga en el tiempo y no hay que ir creando y destruyendo conexiones.

El rendimiento de TCP obviamente se dispara al no tener que establecer sesiones constantemente.

Por ahí existe la idea de que HTTP/2 por defecto utiliza tráfico encriptado, pero no es verdad, lo que pasa es que muchos de los dispositivos que están entre el servidor y tu navegador no saben cómo tratar ese tipo de tráfico porque pueden ser equipos más antiguos que el protocolo.

La solución es implementar TLS y así los nodos intermedios no tendrán nada que decir, esa es la razón por la que HTTP/2 se implementa únicamente sobre TLS.

Así que oh! sorpresa, la razón principal para encriptar el tráfico en Internet no es la seguridad o la privacidad, sino para evitar las cajas intermedias, al menos nos soluciona el problema de los nodos intermedios.

Ante los problemas del Fast Open, del Head-of-line blocking, en definitiva de los problemas asociados con TCP se pensó en cambiar de protocolo, pero las pruebas y los experimentos no fueron buenos.

QUIC

Para solucionar el problema de los nodos intermedios se inventó en Google un nuevo protocolo de transporte llamado QUIC, aunque en un inicio era de transporte y aplicación.

Pero en 2016 cuando empezó el grupo de la IETF a funcionar se dividió en dos y QUIC quedó en la capa de transporte porque no podía haber un protocolo entre capas.

Es importante tener esto en cuenta porque el protocolo QUIC de Google y el protocolo QUIC de la IETF no es lo mismo, pero la suerte es que cuando se habla de QUIC lo normal es hablar del QUIC bueno, el fetén, el de la IETF.

El tener un nuevo protocolo de transporte permite muchas cosas como por ejemplo corregir el problema del Head-of-line blocking haciendo que cada paquete sepa a qué stream pertenece dentro de la sesión, y así no afectando a los demás en caso de pérdida.

También se corrige el tema del hadshake, haciendolo más rápido y evitando el handshake del desafío en 3 vías y además el del TLS, se introduce el concepto de zero round-trip para el handshake.

Pues esto del QUIC se construye sobre UDP porque es más fácil ponerlo sobre UDP que al mismo nivel que UDP ya que ese cambio sería masivo y no podría implementarse así alegremente.

Recuerda que antes hemos hablado de TLS sobre TCP, ahora hablamos de QUIC sobre UDP.

QUIC sobre UDP
QUIC sobre UDP

En este caso QUIC es el que hace confiable la comunicación, obviamente UDP no puesto que UDP no es orientado a la conexión ni está pensado para esto, así que dejamos para QUIC encriptación, autenticación, establecimiento de sesión, control de flujo, corrección de errores y control de la congestión.

Con QUIC tenemos soporte para los streams en el protocolo de transporte, esta es una diferencia importante porque con HTTP/2 los streams, la multiplexación, va a nivel de aplicación, ahora a nivel de transporte.

Al tener los streams independientes a nivel de transporte eliminamos por completo el problema del Head of Line Blocking porque cada paquete sabe a qué stream pertenece de forma que cada stream es independiente a los demás.

También hay que tener muy claro que QUIC es un protocolo de transporte y aunque a día de hoy esté muy relacionado con HTTP hay que tener en cuenta que QUIC podría funcionar con cualquier otro protocolo de aplicación, no está enlazado a HTTP más que nada porque ya de primeras la IETF decidió separarlo y trabajar con el QUIC de la capa de transporte.

HTTP/3

Y después de todo esto que te he contado por fin vamos a empezar a hablar de HTTP/3 que no es más que HTTP sobre QUIC.

En HTTP/3 lo que se hace es más sencillo que en HTTP/2 porque la parte de multiplexación se encarga QUIC.

Una cosa muy interesante es que QUIC implementa TLS 1.3, pero claro ese TLS al estar dentro de QUIC es sobre UDP, esto no deja de ser una curiosidad a tener en cuenta porque cuando hablamos de TLS lo normal es hablar de TLS sobre TCP.

En cuanto a las diferencias entre HTTP/2 y HTTP/3 además de destacar que HTTP/2 va sobre TCP y HTTP/3 sobre QUIC, la que más interesante me parece es la del tratamiento de los Handshake gracias al 0-RTT handshake (zero round trip time resumption).

Aunque el 0-RTT no es una característica de HTTP/3 sino de TLS1.3, así que podría ser habilitado en un servicio de HTTP/2 que utilizara TLS1.3, aunque claro hay una discusión todavía abierta sobre el problema del 0-RTT data replication y por eso a día de hoy no es normal encontrarlos en servidores con HTTP/2.

Si te parece bien me gustaría ahora plantear un ejemplo práctico. Abres tu navegador porque quieres leer las notas de este programa y pones en tu navegador https://www.eduardocollado.com.

Genial, https es puerto 443 sobre TCP, y si tengo el servidor con http/3 ¿qué pasa? porque http/3 hemos dicho que funciona sobre UDP y mi ordenador va a intentar conectarse a un puerto de TCP. Pues a mi que me llamen loco pero a priori veo un problema, mi navegador se quiere conectar por TCP pero el servicio es QUIC sobre UDP, así que el puerto será UDP.

Bien, para este caso hay una solución bastante sencilla que es una redirección llamada alternative-service (alt-svc), que viene descrito en la RFC7838 de Abril de 2016.

En la cual le indicamos al cliente que el servidor ofrece servicio http/3 y que lo ofrece en el puerto UDP que corresponda, que aunque no sea estándar se suele ofrecer en el puerto 443/UDP, aunque como tenemos esta cabecera no es necesario ofrecer ese puerto.

La response header de Alt-Svc indicará servidor y puerto, ojo, el servidor no tiene porqué ser el mismo.

Lecturas complementarias:

QUIC Redefining Internet Transport