Passa al contenuto principale

5. Data Framing (Incorniciamento dei dati)

Il protocollo WebSocket utilizza frame per trasmettere dati. Questo capitolo definisce il formato e le regole di elaborazione per i frame WebSocket.

5.1 Overview (Panoramica)

Una volta stabilita una connessione WebSocket, il client e il server possono trasmettere dati bidirezionalmente. I dati vengono trasmessi sotto forma di una serie di frame.

Concetti chiave:

  • Frame: L'unità di trasmissione di base, contenente un'intestazione e un payload
  • Message (Messaggio): Dati a livello di applicazione che possono consistere in uno o più frame
  • Fragmentation (Frammentazione): I messaggi di grandi dimensioni possono essere inviati in più frame

5.2 Base Framing Protocol (Protocollo di incorniciamento di base)

Struttura del frame

 0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+

Descrizione dei campi

FIN (1 bit)

  • 0: Questo non è l'ultimo frame del messaggio (seguono altri frame)
  • 1: Questo è l'ultimo frame del messaggio (o l'unico frame)
Esempio di frammentazione del messaggio:
Frame 1: FIN=0, Opcode=0x1 (Text), Data="Hello "
Frame 2: FIN=0, Opcode=0x0 (Continuation), Data="World"
Frame 3: FIN=1, Opcode=0x0 (Continuation), Data="!"

Messaggio completo: "Hello World!"

RSV1, RSV2, RSV3 (1 bit ciascuno)

  • Riservati per le estensioni
  • DEVE essere 0 se non è stata negoziata alcuna estensione
  • DEVE chiudere la connessione se viene ricevuto un valore diverso da zero senza estensione definita

Opcode (4 bit)

Definisce il tipo di frame:

OpcodeTipoDescrizione
0x0ContinuationFrame di continuazione (frame successivi di un messaggio frammentato)
0x1TextFrame di testo (codificato UTF-8)
0x2BinaryFrame binario
0x3-0x7-Riservato (frame di dati)
0x8CloseFrame di chiusura
0x9PingFrame Ping
0xAPongFrame Pong
0xB-0xF-Riservato (frame di controllo)

MASK (1 bit)

  • Client verso server: DEVE essere 1
  • Server verso client: DEVE essere 0

Se MASK=1, Payload Data deve essere mascherato utilizzando Masking-key.

Payload Length (7 bit, 7+16 bit o 7+64 bit)

Codifica della lunghezza del payload:

  • 0-125: Questa è la lunghezza effettiva
  • 126: I successivi 16 bit (2 byte) sono la lunghezza effettiva (ordine dei byte di rete)
  • 127: I successivi 64 bit (8 byte) sono la lunghezza effettiva (ordine dei byte di rete)
Esempio:
Lunghezza del payload = 100 byte
→ Payload len = 100 (codifica diretta)

Lunghezza del payload = 1000 byte
→ Payload len = 126
→ Extended payload length = 1000 (16 bit)

Lunghezza del payload = 100000 byte
→ Payload len = 127
→ Extended payload length = 100000 (64 bit)

Masking-key (0 o 4 byte)

Se MASK=1, contiene 32 bit (4 byte) di chiave di mascheramento.

Payload Data (x+y byte)

Dati del payload = Extension Data + Application Data

  • Extension Data: Lunghezza x, determinata dalla negoziazione dell'estensione, predefinito 0
  • Application Data: Lunghezza y, dati effettivi dell'applicazione

5.3 Client-to-Server Masking (Mascheramento client-server)

Perché il mascheramento è richiesto?

Motivo di sicurezza: Prevenire attacchi di avvelenamento della cache. Alcuni proxy intermedi potrebbero memorizzare nella cache in modo errato i frame WebSocket; il mascheramento garantisce l'imprevedibilità dei dati.

Algoritmo di mascheramento

I client DEVONO utilizzare il seguente algoritmo per mascherare tutti i frame inviati al server:

1. Genera una chiave di mascheramento casuale a 32 bit
2. Posiziona la chiave di mascheramento nel campo Masking-key dell'intestazione del frame
3. Applica la maschera a ogni byte di Payload Data:

transformed-octet-i = original-octet-i XOR masking-key[i MOD 4]

Implementazione dell'algoritmo (JavaScript):

function maskData(data, maskingKey) {
const masked = new Uint8Array(data.length);
for (let i = 0; i < data.length; i++) {
masked[i] = data[i] ^ maskingKey[i % 4];
}
return masked;
}

// Esempio
const data = Buffer.from('Hello');
const maskingKey = Buffer.from([0x37, 0xfa, 0x21, 0x3d]);
const masked = maskData(data, maskingKey);

// Decodifica (utilizzando lo stesso algoritmo)
const unmasked = maskData(masked, maskingKey); // 'Hello'

Punti chiave:

  • XOR è auto-inverso: (A XOR B) XOR B = A
  • Il server utilizza lo stesso algoritmo per decodificare
  • Deve utilizzare una nuova chiave casuale per ogni frame inviato

5.4 Fragmentation (Frammentazione)

I messaggi di grandi dimensioni possono essere inviati in più frame.

Regole di frammentazione

  1. Primo frame: FIN=0, Opcode=tipo di dati (0x1 o 0x2)
  2. Frame intermedi: FIN=0, Opcode=0x0 (Continuation)
  3. Ultimo frame: FIN=1, Opcode=0x0 (Continuation)

Esempio di frammentazione

Invio del messaggio "Hello World!" in tre frame:

Frame 1:
FIN = 0
Opcode = 0x1 (Text)
Payload = "Hello "

Frame 2:
FIN = 0
Opcode = 0x0 (Continuation)
Payload = "World"

Frame 3:
FIN = 1
Opcode = 0x0 (Continuation)
Payload = "!"

Vincoli di frammentazione

  • I frame di controllo (Close, Ping, Pong) NON DEVONO essere frammentati
  • I frame di controllo possono essere inseriti tra i frame di dati frammentati
  • I frammenti devono essere inviati e ricevuti in ordine

5.5 Control Frames (Frame di controllo)

I frame di controllo vengono utilizzati per comunicare lo stato della connessione. Intervallo Opcode: 0x8-0xF.

5.5.1 Close (Frame di chiusura)

  • Opcode: 0x8
  • Può includere codice di chiusura e motivo
  • Vedere il capitolo 7 per i dettagli

5.5.2 Ping (Frame Ping)

  • Opcode: 0x9
  • Scopo: Rilevamento del battito cardiaco, verificare se la connessione è attiva
  • Può trasportare dati dell'applicazione (max 125 byte)
  • Il destinatario DEVE rispondere con un frame Pong
Client → Server: Ping (Opcode=0x9)
Server → Client: Pong (Opcode=0xA, stesso Payload)

5.5.3 Pong (Frame Pong)

  • Opcode: 0xA
  • Scopo: Rispondere al frame Ping
  • DEVE contenere lo stesso Payload del frame Ping
  • Può anche essere inviato in modo proattivo (battito cardiaco non sollecitato)

Regole dei frame di controllo

  1. Lunghezza massima del Payload: 125 byte
  2. NON DEVONO essere frammentati
  3. Possono essere inseriti tra i frame di dati frammentati

5.6 Data Frames (Frame di dati)

I frame di dati trasmettono dati di applicazione o di estensione. Intervallo Opcode: 0x0-0x2, 0x3-0x7 riservati.

Text Frame (Frame di testo)

  • Opcode: 0x1
  • Il Payload DEVE essere testo codificato UTF-8 valido
  • DEVE chiudere la connessione se viene ricevuto UTF-8 non valido

Binary Frame (Frame binario)

  • Opcode: 0x2
  • Il Payload può essere dati binari arbitrari
  • Il livello applicazione è responsabile dell'interpretazione

5.7 Examples (Esempi)

Frame di testo singolo non mascherato

0x81 0x05 0x48 0x65 0x6c 0x6c 0x6f
│ │ └─────────┬────────────┘
│ │ └─ "Hello" (5 byte)
│ └─ Payload len = 5
└─ FIN=1, Opcode=0x1 (Text)

Frame di testo singolo mascherato

0x81 0x85 0x37 0xfa 0x21 0x3d 0x7f 0x9f 0x4d 0x51 0x58
│ │ └─────┬────────┘ └──────┬───────────┘
│ │ │ └─ "Hello" mascherato
│ │ └─ Chiave di mascheramento
│ └─ MASK=1, Payload len = 5
└─ FIN=1, Opcode=0x1 (Text)

Messaggio frammentato

Frame 1: 0x01 0x03 0x48 0x65 0x6c   // FIN=0, Text, "Hel"
Frame 2: 0x80 0x02 0x6c 0x6f // FIN=1, Continuation, "lo"

Messaggio completo: "Hello"

Frame Ping

0x89 0x05 0x48 0x65 0x6c 0x6c 0x6f
│ │ └─────────┬────────────┘
│ │ └─ "Hello" (dati opzionali)
│ └─ Payload len = 5
└─ FIN=1, Opcode=0x9 (Ping)

5.8 Extensibility (Estensibilità)

Il protocollo può essere esteso tramite:

  1. Opcode: 0x3-0x7 e 0xB-0xF riservati per uso futuro
  2. Bit RSV: Riservati per uso delle estensioni
  3. Extension Data: Le estensioni possono aggiungere dati prima del Payload

Le estensioni devono essere negoziate tramite handshake (Sec-WebSocket-Extensions).