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:
- Multiplexacion — multiples solicitudes y respuestas se intercalan en una sola conexion TCP.
- Compresion de cabeceras (HPACK) — las cabeceras se comprimen usando una tabla estatica y codificacion Huffman.
- Formato binario — sin sobrecarga de parseo de texto.
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 ... | +-----------------------------------------------+
- Length — tamano del payload en bytes (maximo 16.384 por defecto).
- Type — que tipo de frame es.
- Flags — flags especificas del tipo (ej. END_STREAM, END_HEADERS).
- Stream ID — a que stream pertenece este frame (0 para nivel de conexion).
Tipos de frame
| Tipo | ID | Proposito |
|---|---|---|
| DATA | 0 | Cuerpo de solicitud/respuesta |
| HEADERS | 1 | Cabeceras HTTP (comprimidas con HPACK) |
| SETTINGS | 4 | Configuracion de conexion |
| PING | 6 | Keep-alive / medicion de latencia |
| GOAWAY | 7 | Cierre graceful |
| WINDOW_UPDATE | 8 | Control de flujo |
| RST_STREAM | 3 | Cancelar un stream |
Streams y multiplexacion
Un stream es un par logico de solicitud/respuesta dentro de una conexion. Los streams tienen IDs numericos:
- IDs impares (1, 3, 5, ...) — solicitudes iniciadas por el cliente.
- IDs pares (2, 4, 6, ...) — server push.
- Stream 0 — frames a nivel de conexion (SETTINGS, PING, GOAWAY).
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:
| Indice | Nombre | Valor |
|---|---|---|
| 2 | :method | GET |
| 4 | :path | / |
| 8 | :status | 200 |
| 13 | :status | 404 |
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:
runtime/http2.c— E/S de frames, codificacion/decodificacion HPACK, tablas Huffman (todas las operaciones binarias en C por rendimiento).std/http2.nx— maquina de estados del protocolo, validacion del prefacio de conexion, bucle de despacho de frames, construccion de respuestas (toda la logica en 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
- HTTP/2 reemplaza el protocolo de texto de HTTP/1.1 con enmarcado binario.
- La multiplexacion permite multiples solicitudes en una sola conexion TCP.
- HPACK comprime cabeceras usando una tabla estatica y codificacion Huffman.
- Los frames tienen una cabecera de 9 bytes: longitud, tipo, flags, stream ID.
h2_serve(port, workers, callback)inicia un servidor HTTP/2.- Prueba con
curl --http2-prior-knowledge.