Índice

HTTP/2 — Protocolos binarios

Por que HTTP/2?

HTTP/1.1 esta basado en texto. Cada solicitud se ve asi:

GET /index.html HTTP/1.1\r\n
Host: example.com\r\n
Accept: text/html\r\n
\r\n

Esto tiene dos problemas. Primero, las cabeceras se envian como texto plano en cada solicitud — incluso cuando se repiten. Segundo, HTTP/1.1 permite solo una solicitud a la vez por conexion TCP. Si necesitas cargar 10 recursos, o abres 10 conexiones o esperas cada respuesta antes de enviar la siguiente solicitud.

HTTP/2 resuelve ambos problemas con una capa de enmarcado binario:

Estructura del frame

Todo en HTTP/2 es un frame. Cada frame tiene una cabecera de 9 bytes:

+-----------------------------------------------+
|                Length (24 bits)                |
+---------------+---------------+---------------+
|   Type (8)    |   Flags (8)   |
+-+-------------+---------------+---------------+
|R|         Stream Identifier (31 bits)         |
+-+---------------------------------------------+
|                Frame Payload ...               |
+-----------------------------------------------+

Tipos de frame

TipoIDProposito
DATA0Cuerpo de solicitud/respuesta
HEADERS1Cabeceras HTTP (comprimidas con HPACK)
SETTINGS4Configuracion de conexion
PING6Keep-alive / medicion de latencia
GOAWAY7Cierre graceful
WINDOW_UPDATE8Control de flujo
RST_STREAM3Cancelar un stream

Streams y multiplexacion

Un stream es un par logico de solicitud/respuesta dentro de una conexion. Los streams tienen IDs numericos:

Multiples streams pueden estar activos simultaneamente. Un cliente envia HEADERS en el stream 1, luego HEADERS en el stream 3, sin esperar respuestas. El servidor envia respuestas en cualquier orden.

Compresion de cabeceras HPACK

HTTP/2 comprime las cabeceras usando una tabla estatica de 61 pares comunes de nombre-valor. Por ejemplo:

IndiceNombreValor
2:methodGET
4:path/
8:status200
13:status404

En lugar de enviar :status: 200 como 12 bytes de texto, HPACK envia un solo byte: 0x88 (representacion indexada de la entrada 8). Esto reduce la sobrecarga de cabeceras dramaticamente.

Prefacio de conexion

Una conexion HTTP/2 comienza con el cliente enviando una cadena magica de 24 bytes:

PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n

Seguida de un frame SETTINGS. El servidor responde con su propio SETTINGS y un ACK. Este handshake establece los parametros de conexion. En modo h2c (texto claro), no se necesita TLS.

Construir un servidor HTTP/2 en Nyx

Nyx proporciona std/http2.nx para servidores HTTP/2. La API esta basada en callbacks:

import "std/http2"

fn on_request(method: String, path: String, headers: Array, body: String) -> Array {
    if path == "/" {
        let hdrs: Array = ["content-type", "text/html"]
        return [200, hdrs, "<h1>Hello from HTTP/2!</h1>"]
    }
    let hdrs: Array = ["content-type", "text/plain"]
    return [404, hdrs, "Not Found"]
}

fn main() -> int {
    h2_serve(3000, 4, on_request)
    return 0
}

El callback recibe el metodo, la ruta, las cabeceras (como un array plano [clave1, valor1, clave2, valor2, ...]) y el cuerpo. Devuelve un array de tres elementos: [estado, cabeceras, cuerpo].

Probar con curl

Usa curl --http2-prior-knowledge para conectar via h2c:

$ curl --http2-prior-knowledge http://localhost:3000/
<h1>Hello from HTTP/2!</h1>

El flag --http2-prior-knowledge le indica a curl que use HTTP/2 directamente sin un handshake de upgrade.

Que hace Nyx internamente

La implementacion de HTTP/2 esta dividida entre C y Nyx:

Este enfoque hibrido — C para operaciones a nivel de bytes, Nyx para la logica del protocolo — es el mismo patron usado para WebSockets, TCP y el parser RESP.

Resumen

← Anterior: Colas de mensajes con nyx-queue Siguiente: Construyendo una base de datos — nyx-db →