Passa al contenuto principale

2. Trasferimenti a blocchi

Come discusso nell'introduzione, ci sono buone ragioni per limitare la dimensione dei datagrammi nelle reti vincolate:

  • dalla dimensione massima del datagramma (~ 64 KiB per UDP)

  • dal desiderio di evitare la frammentazione IP (MTU di 1280 per IPv6)

  • dal desiderio di evitare la frammentazione del livello di adattamento (60-80 byte per 6LoWPAN [RFC4919])

Quando una rappresentazione di risorsa è più grande di quanto possa essere trasferita comodamente nel payload di un singolo datagramma CoAP, è possibile utilizzare un'opzione Block per indicare un trasferimento a blocchi. Poiché i payload possono essere inviati sia con le richieste che con le risposte, questa specifica fornisce due opzioni separate per ciascuna direzione di trasferimento del payload. Nel denominare queste opzioni (per i trasferimenti a blocchi così come nella Sezione 4), utilizziamo il numero 1 ("Block1", "Size1") per fare riferimento al trasferimento della rappresentazione della risorsa che riguarda la richiesta, e il numero 2 ("Block2", "Size2") per fare riferimento al trasferimento della rappresentazione della risorsa per la risposta.

Di seguito, il termine "payload" verrà utilizzato per il contenuto effettivo di un singolo messaggio CoAP, ovvero un singolo blocco trasferito, mentre il termine "corpo (body)" verrà utilizzato per l'intera rappresentazione della risorsa che viene trasferita in modo frammentato (a blocchi). L'opzione Content-Format si applica al corpo, non al payload; in particolare, i confini tra i blocchi possono trovarsi in punti che non separano intere unità in termini di struttura, codifica o codifica del contenuto utilizzata dal Content-Format. (Allo stesso modo, l'opzione ETag definita nella Sezione 5.10.6 di [RFC7252] si applica all'intera rappresentazione della risorsa e quindi al corpo della risposta.)

Nella maggior parte dei casi, tutti i blocchi trasferiti per un corpo (tranne l'ultimo) avranno la stessa dimensione. (Se la prima richiesta utilizza una dimensione del blocco maggiore di quella preferita dal ricevitore, le richieste successive utilizzeranno la dimensione del blocco preferita.) La dimensione del blocco non è fissata dal protocollo. Per mantenere l'implementazione il più semplice possibile, le opzioni Block supportano solo un piccolo intervallo di dimensioni dei blocchi potenza di due, da 2**4 (16) a 2**10 (1024) byte. Poiché i corpi spesso non si divideranno uniformemente nella dimensione del blocco potenza di due scelta, non è necessario raggiungere la dimensione nel blocco finale (ma anche per il blocco finale, la dimensione potenza di due scelta sarà comunque indicata nel campo dimensione del blocco dell'opzione Block).

2.1. Le opzioni Block2 e Block1

+-----+---+---+---+---+--------+--------+--------+---------+
| No. | C | U | N | R | Name | Format | Length | Default |
+-----+---+---+---+---+--------+--------+--------+---------+
| 23 | C | U | - | - | Block2 | uint | 0-3 | (nessuno)|
| | | | | | | | | |
| 27 | C | U | - | - | Block1 | uint | 0-3 | (nessuno)|
+-----+---+---+---+---+--------+--------+--------+---------+

Tabella 1: Numeri di opzioni Block

Entrambe le opzioni Block1 e Block2 possono essere presenti sia nei messaggi di richiesta che di risposta. In entrambi i casi, l'opzione Block1 riguarda il payload della richiesta e l'opzione Block2 riguarda il payload della risposta.

Quindi, per i metodi definiti in [RFC7252], Block1 è utile con le richieste POST e PUT portatrici di payload e le loro risposte. Block2 è utile con le richieste GET, POST e PUT e le loro risposte portatrici di payload (2.01, 2.02, 2.04 e 2.05 -- vedere la Sezione 5.5 di [RFC7252]).

Laddove Block1 è presente in una richiesta o Block2 in una risposta (ovvero in quel messaggio al cui payload si riferisce) indica un trasferimento a blocchi e descrive come questo specifico payload a blocchi fa parte dell'intero corpo trasferito ("uso descrittivo"). Laddove è presente nella direzione opposta, fornisce un controllo aggiuntivo su come quel payload verrà formato o è stato elaborato ("uso di controllo").

L'implementazione di una delle opzioni Block è intesa come facoltativa. Tuttavia, quando è presente in un messaggio CoAP, DEVE essere elaborata (o il messaggio rifiutato); pertanto, è identificata come un'opzione Critica (Critical). Entrambe le opzioni Block NON DEVONO comparire più di una volta in un singolo messaggio.

2.2. Struttura di un'opzione Block

Potrebbe essere necessario trasferire tre elementi di informazione in un'opzione Block (Block1 o Block2):

  • la dimensione del blocco (SZX);

  • se seguono altri blocchi (M);

  • il numero relativo del blocco (NUM) all'interno di una sequenza di blocchi con la dimensione data.

Il valore dell'opzione Block è un intero senza segno di dimensione variabile (da 0 a 3 byte) (uint, vedere la Sezione 3.2 di [RFC7252]). Questo valore intero codifica questi tre campi, vedere la Figura 1. (A causa delle regole di codifica uint CoAP, quando tutti NUM, M e SZX sono zero, verrà inviato un intero di zero byte.)

     0
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
| NUM |M| SZX |
+-+-+-+-+-+-+-+-+

0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NUM |M| SZX |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

0 1 2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NUM |M| SZX |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figura 1: Valore dell'opzione Block

La dimensione del blocco è codificata utilizzando un intero senza segno a tre bit (0 per 2**4 byte a 6 per 2**10 byte), che chiamiamo "SZX" ("esponente di dimensione"); la dimensione effettiva del blocco è quindi "2**(SZX + 4)". SZX viene trasferito nei tre bit meno significativi del valore dell'opzione (ovvero "val & 7" dove "val" è il valore dell'opzione).

Il quarto bit meno significativo, il bit M o "more" ("val & 8"), indica se seguono altri blocchi o se il trasferimento a blocchi corrente è l'ultimo blocco trasferito.

Il valore dell'opzione diviso per sedici (il campo NUM) è il numero di sequenza del blocco attualmente trasferito, a partire da zero. Il trasferimento corrente riguarda quindi i "size" byte a partire dal byte "NUM << (SZX + 4)".

Nota di implementazione: Per comodità di implementazione, "(val & ~0xF) << (val & 7)", ovvero il valore dell'opzione con gli ultimi 4 bit mascherati, spostato a sinistra del valore di SZX, fornisce la posizione in byte del primo byte del blocco trasferito.

Più specificamente, all'interno del valore dell'opzione di un'opzione Block1 o Block2, il significato dei campi dell'opzione è definito come segue:

NUM: : Numero di blocco, che indica il numero di blocco richiesto o fornito. Il numero di blocco 0 indica il primo blocco di un corpo (ovvero, a partire dal primo byte del corpo).

M: : Flag More ("non ultimo blocco"). Per l'uso descrittivo, questo flag, se non impostato, indica che il payload in questo messaggio è l'ultimo blocco nel corpo; quando impostato, indica che sono disponibili uno o più blocchi aggiuntivi. Quando un'opzione Block2 viene utilizzata in una richiesta per recuperare un numero di blocco specifico ("uso di controllo"), il bit M DEVE essere inviato come zero e ignoré alla ricezione. (In un'opzione Block1 in una risposta, il flag M viene utilizzato per indicare l'atomicità, vedere di seguito.)

SZX: : Dimensione del blocco. La dimensione del blocco è rappresentata come un intero senza segno a tre bit che indica la dimensione di un blocco alla potenza di due. Pertanto, dimensione del blocco = 2**(SZX + 4). I valori consentiti di SZX sono da 0 a 6, ovvero la dimensione minima del blocco è 2**(0+4) = 16 e la massima è 2**(6+4) = 1024. Il valore 7 per SZX (che indicherebbe una dimensione del blocco di 2048) è riservato, ovvero NON DEVE essere inviato e DEVE portare a un codice di risposta 4.00 Bad Request alla ricezione in una richiesta.

Non esiste un valore predefinito per le opzioni Block1 e Block2. L'assenza di una di queste opzioni equivale a un valore di opzione pari a 0 rispetto al valore di NUM e M che potrebbe essere fornito nell'opzione, ovvero indica che il blocco corrente è il primo e unico blocco del trasferimento (numero di blocco 0, bit M non impostato). Tuttavia, a differenza del valore esplicito 0, che indicherebbe un SZX pari a 0 e quindi un valore di dimensione di 16 byte, nessuna dimensione esplicita specifica è implicata dall'assenza dell'opzione -- la dimensione è lasciata non specificata. (Come per qualsiasi uint, il valore esplicito 0 è indicato in modo efficiente da un'opzione di lunghezza zero; questo, quindi, è diverso nella semantica dall'assenza dell'opzione.)

2.3. Opzioni Block nelle richieste e nelle risposte

Le opzioni Block vengono utilizzate in uno dei tre ruoli seguenti:

  • In uso descrittivo, ovvero un'opzione Block2 in una risposta (come una risposta 2.05 per GET), o un'opzione Block1 in una richiesta (un PUT o POST):

    • Il campo NUM nel valore dell'opzione descrive quale numero di blocco è contenuto nel payload di questo messaggio.

    • Il bit M indica se è necessario trasferire ulteriori blocchi per completare il trasferimento di quel corpo.

    • La dimensione del blocco implicata da SZX DEVE corrispondere alla dimensione del payload in byte, se il bit M è impostato. (SZX non regola la dimensione del payload se M non è impostato). Per Block2, se la richiesta suggeriva un valore maggiore di SZX, la richiesta successiva DEVE spostare SZX verso il basso alla dimensione indicata nella risposta. (L'effetto è che, se il server utilizza la minore tra (1) la sua dimensione del blocco preferita e (2) la dimensione del blocco richiesta, tutti i blocchi per un corpo utilizzano la stessa dimensione del blocco.)

  • Un'opzione Block2 in uso di controllo in una richiesta (ad esempio, GET):

    • Il campo NUM nell'opzione Block2 fornisce il numero di blocco del payload che si richiede venga restituito nella risposta.

    • In questo caso, il bit M non ha alcuna funzione e DEVE essere impostato a zero.

    • La dimensione del blocco fornita (SZX) suggerisce una dimensione del blocco (nel caso del numero di blocco 0) o ripete la dimensione del blocco dei blocchi precedenti ricevuti (nel caso di un numero di blocco diverso da zero).

  • Un'opzione Block1 in uso di controllo in una risposta (ad esempio, una risposta 2.xx per una richiesta PUT o POST):

    • Il campo NUM dell'opzione Block1 indica quale numero di blocco viene confermato.

    • Se il bit M era impostato nella richiesta, il server può scegliere se agire su ogni blocco separatamente, senza memoria, o se gestire la richiesta per l'intero corpo in modo atomico, o qualsiasi combinazione dei due.

      • Se il bit M è impostato anche nella risposta, indica che questa risposta non porta il codice di risposta finale alla richiesta, ovvero il server raccoglie ulteriori blocchi dallo stesso endpoint e prevede di implementare la richiesta in modo atomico (ad esempio, agisce solo alla ricezione dell'ultimo blocco di payload). In questo caso, la risposta NON DEVE portare un'opzione Block2.

      • Al contrario, se il bit M non è impostato anche se era impostato nella richiesta, indica che la richiesta a blocchi è stata attuata ora specificamente per questo blocco e la risposta porta la risposta finale a questa richiesta (e a tutte le precedenti con il bit M impostato nell'opzione Block1 della risposta in questa sequenza di trasferimenti a blocchi); ci si aspetta che il client continui a inviare ulteriori blocchi, il cui metodo di richiesta può o meno essere attuato anche per blocco. (Si noti che la risorsa è ora in uno stato parzialmente aggiornato; questo approccio è appropriato solo laddove esporre tale stato intermedio è accettabile. Il client può ridurre la finestra continuando rapidamente ad aggiornare la risorsa o, in caso di errore, riavviando l'aggiornamento.)

    • Infine, la dimensione del blocco SZX fornita in un'opzione Block1 di controllo indica la dimensione del blocco più grande preferita dal server per i trasferimenti verso la risorsa che è uguale o inferiore a quella utilizzata nello scambio iniziale; il client DOVREBBE utilizzare questa dimensione del blocco o una più piccola in tutte le ulteriori richieste nella sequenza di trasferimento, anche se ciò significa modificare la dimensione del blocco (e possibilmente ridimensionare il numero di blocco di conseguenza) da ora in poi.

Utilizzando una o entrambe le opzioni Block, una singola operazione REST può essere suddivisa in più scambi di messaggi CoAP. Come specificato in [RFC7252], ciascuno di questi scambi di messaggi utilizza il proprio ID messaggio CoAP.

L'opzione Content-Format inviata con le richieste o le risposte DEVE riflettere il Content-Format dell'intero corpo. Se i blocchi di un corpo di risposta arrivano con diverse opzioni Content-Format, spetta al client decidere come gestire questo errore (in genere interromperà qualsiasi trasferimento a blocchi in corso). Se i blocchi di una richiesta arrivano a un server con opzioni Content-Format non corrispondenti, il server NON DEVE assemblarli in una singola richiesta; ciò di solito porta a una risposta di errore 4.08 (Request Entity Incomplete, Sezione 2.9.2) sul blocco non corrispondente.

2.4. Utilizzo dell'opzione Block2

Quando a una richiesta viene data risposta con una risposta contenente un'opzione Block2 con il bit M impostato, il richiedente può recuperare blocchi aggiuntivi della rappresentazione della risorsa inviando ulteriori richieste con le stesse opzioni della richiesta iniziale e un'opzione Block2 che fornisce il numero di blocco e la dimensione del blocco desiderati. In una richiesta, il client DEVE impostare il bit M di un'opzione Block2 a zero e il server DEVE ignorarlo alla ricezione.

Per influenzare la dimensione del blocco utilizzata in una risposta, il richiedente PUÒ anche utilizzare l'opzione Block2 nella richiesta iniziale, fornendo la dimensione desiderata, un numero di blocco pari a zero e un bit M pari a zero. Un server DEVE utilizzare la dimensione del blocco indicata o una dimensione inferiore. Eventuali ulteriori richieste a blocchi per blocchi oltre il primo DEVONO indicare la stessa dimensione del blocco utilizzata dal server nella risposta per la prima richiesta che ha fornito una dimensione desiderata utilizzando un'opzione Block2.

Una volta che l'opzione Block2 viene utilizzata dal richiedente ed è stata ricevuta una prima risposta con una dimensione del blocco possibilmente regolata, tutte le ulteriori richieste in un singolo trasferimento a blocchi alla fine convergeranno sull'utilizzo della stessa dimensione, tranne per il fatto che potrebbe non esserci abbastanza contenuto per riempire l'ultimo blocco (quello restituito con il bit M non impostato). (Si noti che il client potrebbe iniziare a utilizzare l'opzione Block2 in una seconda richiesta dopo che una prima richiesta senza un'opzione Block2 ha generato un'opzione Block2 nella risposta.) Il server utilizza la dimensione del blocco indicata nell'opzione di richiesta o una dimensione inferiore, ma il richiedente DEVE prendere nota della dimensione del blocco effettiva utilizzata nella risposta che riceve alla sua richiesta iniziale e procedere a utilizzarla nelle richieste successive. Il comportamento del server DEVE garantire che questo comportamento del client si traduca nella stessa dimensione del blocco per tutte le risposte in una sequenza (tranne l'ultima con il bit M non impostato e possibilmente la prima se la richiesta iniziale non conteneva un'opzione Block2).

I trasferimenti a blocchi possono essere utilizzati per ottenere (GET) risorse le cui rappresentazioni sono interamente statiche (che non cambiano affatto nel tempo, come in uno schema che descrive un dispositivo) o per risorse che cambiano dinamicamente. In quest'ultimo caso, l'opzione Block2 DOVREBBE essere utilizzata insieme all'opzione ETag ([RFC7252], Sezione 5.10.6), per garantire che i blocchi riassemblati provengano dalla stessa versione della rappresentazione: il server DOVREBBE includere un'opzione ETag in ogni risposta. Se è disponibile un'opzione ETag, il client, durante il riassemblaggio della rappresentazione dai blocchi scambiati, DEVE confrontare le opzioni ETag. Se le opzioni ETag non corrispondono in un trasferimento GET, il richiedente ha la possibilità di tentare di recuperare valori aggiornati per i blocchi che ha recuperato per primi. Per ridurre al minimo l'inefficienza risultante, il server PUÒ memorizzare nella cache il valore corrente di una rappresentazione per una sequenza di richieste in corso. (Il server può identificare la sequenza dalla combinazione dell'endpoint richiedente e dell'URI che è lo stesso in ogni richiesta a blocchi.) Si noti bene che questa specifica non richiede al server di stabilire alcuno stato; tuttavia, i server che offrono risorse che cambiano rapidamente possono quindi rendere impossibile per un client recuperare un insieme coerente di blocchi. I client che desiderano recuperare tutti i blocchi di una risorsa DOVREBBERO sforzarsi di farlo senza indebito ritardo. I server possono aspettarsi pienamente di essere liberi di scartare qualsiasi stato memorizzato nella cache dopo un periodo di EXCHANGE_LIFETIME ([RFC7252], Sezione 4.8.2) dopo l'ultimo accesso allo stato, tuttavia, non è richiesto di mantenere sempre lo stato per così tanto tempo.

L'opzione Block2 non fornisce alcun modo per un singolo endpoint di eseguire più operazioni di trasferimento del payload di risposta a blocchi (ad esempio, GET) che procedono contemporaneamente sulla stessa risorsa. Questo è raramente un requisito, ma come soluzione alternativa, un client può variare la chiave della cache (ad esempio, utilizzando uno dei diversi URI che accedono alle risorse con la stessa semantica o variando un'opzione elettiva sicura per il proxy).

2.5. Utilizzo dell'opzione Block1

In una richiesta con un payload di richiesta (ad esempio, PUT o POST), l'opzione Block1 si riferisce al payload nella richiesta (uso descrittivo).

In risposta a una richiesta con un payload (ad esempio, un trasferimento PUT o POST), la dimensione del blocco indicata nell'opzione Block1 indica la preferenza della dimensione del blocco del server per questa risorsa (uso di controllo). Ovviamente, a questo punto il primo blocco è già stato trasferito dal client senza beneficiare di questa conoscenza. Tuttavia, il client DOVREBBE prestare attenzione alla preferenza indicata e, per tutti gli ulteriori blocchi, utilizzare la dimensione del blocco preferita dal server o una più piccola. Si noti che qualsiasi riduzione della dimensione del blocco può significare che la seconda richiesta inizia con un numero di blocco maggiore di uno, poiché la prima richiesta ha già trasferito più blocchi come conteggiati nella dimensione più piccola.

Per contrastare gli effetti della frammentazione del livello di adattamento sulla probabilità di consegna dei pacchetti, un client potrebbe voler rinunciare a ritrasmettere una richiesta con un payload relativamente grande anche prima che sia stato raggiunto MAX_RETRANSMIT, e provare a riformulare la richiesta come un trasferimento a blocchi con un payload più piccolo. Si noti che questo nuovo tentativo è quindi una nuova transazione a livello di messaggio e richiede un nuovo ID messaggio. (A causa dell'incertezza sul fatto che la richiesta o la conferma siano andate perse, questa strategia è utile principalmente per le richieste idempotenti.)

In un trasferimento a blocchi di un payload di richiesta (ad esempio, un PUT o POST) che si intende implementare in modo atomico sul server, la creazione/sostituzione effettiva avviene nel momento in cui viene ricevuto il blocco finale, ovvero un blocco con il bit M non impostato nell'opzione Block1. In questo caso, tutte le risposte di successo ai blocchi non finali portano il codice di risposta 2.31 (Continue, Sezione 2.9.1). Se non tutti i blocchi precedenti sono disponibili sul server al momento dell'elaborazione del blocco finale, il trasferimento fallisce e DEVE essere restituito il codice di errore 4.08 (Request Entity Incomplete, Sezione 2.9.2). Un server PUÒ anche restituire un codice di errore 4.08 per qualsiasi trasferimento Block1 (finale o non finale) che non è in sequenza; pertanto, i client che non dispongono di meccanismi specifici per gestire questo caso DOVREBBERO sempre iniziare con il blocco zero e inviare i blocchi successivi in ordine.

Un motivo per cui un client potrebbe incontrare un codice di errore 4.08 è che il server è già scaduto e ha scartato il corpo della richiesta parziale in fase di assemblaggio. I client DOVREBBERO sforzarsi di inviare tutti i blocchi di una richiesta senza indebito ritardo. I server possono aspettarsi pienamente di essere liberi di scartare qualsiasi corpo di richiesta parziale quando è trascorso un periodo di EXCHANGE_LIFETIME ([RFC7252], Sezione 4.8.2) dopo il trasferimento del blocco più recente; tuttavia, non è richiesto a un server di mantenere sempre il corpo della richiesta parziale per così tanto tempo.

Il codice di errore 4.13 (Request Entity Too Large) può essere restituito in qualsiasi momento da un server che non dispone attualmente delle risorse per memorizzare i blocchi per un trasferimento di payload di richiesta a blocchi che intenderebbe implementare in modo atomico. (Si noti che una risposta 4.13 a una richiesta che non impiega Block1 è un suggerimento per il client di provare a inviare Block1, e una risposta 4.13 con un SZX più piccolo nella sua opzione Block1 rispetto a quanto richiesto è un suggerimento per provare un SZX più piccolo.)

Un trasferimento a blocchi di un payload di richiesta che viene implementato in modo stateless sul server rischia di lasciare la risorsa su cui si opera in uno stato incoerente mentre il trasferimento è ancora in corso o quando il client non completa il trasferimento. Questa caratteristica è più vicina a quella dei file system remoti che a quella di HTTP, dove lo stato viene sempre mantenuto sul server durante un trasferimento. Tecniche ben note dall'accesso ai file condivisi (ad esempio, risorse temporanee specifiche del client) possono essere utilizzate per mitigare questa differenza da HTTP.

L'opzione Block1 non fornisce alcun modo per un singolo endpoint di eseguire più operazioni di trasferimento del payload di richiesta a blocchi (ad esempio, PUT o POST) che procedono contemporaneamente sulla stessa risorsa. L'avvio di una nuova sequenza di richieste a blocchi verso la stessa risorsa (prima che una vecchia sequenza dallo stesso endpoint fosse terminata) sovrascrive semplicemente il contesto che il server potrebbe ancora mantenere. (Questo è probabilmente esattamente ciò che si desidera in questo caso -- il client potrebbe semplicemente aver riavviato e perso la conoscenza della sequenza precedente.)

2.6. Combinazione dei trasferimenti a blocchi con l'opzione Observe

L'opzione Observe fornisce un modo per un client di essere informato sulle modifiche nel tempo di una risorsa [RFC7641]. Le risorse osservate dai client possono essere più grandi di quanto possano essere comodamente elaborate o trasferite in un messaggio CoAP. Le seguenti regole si applicano alla combinazione di trasferimenti a blocchi con notifiche.

Le relazioni di osservazione si applicano sempre a un'intera risorsa; l'opzione Block2 non fornisce un modo per osservare un singolo blocco di una risorsa.

Come per i trasferimenti GET di base, il client può indicare la dimensione del blocco desiderata in un'opzione Block2 nella richiesta GET che stabilisce o rinnova la relazione di osservazione. Se il server supporta i trasferimenti a blocchi, DOVREBBE prendere nota della dimensione del blocco e applicarla come dimensione massima a tutte le notifiche/risposte risultanti dalla richiesta GET (fino a quando il client non viene rimosso dall'elenco degli osservatori o la voce in quell'elenco viene aggiornata dal server che riceve una nuova richiesta GET per la risorsa dal client).

Quando invia una notifica 2.05 (Content), il server invia solo il primo blocco della rappresentazione. Il client recupera il resto della rappresentazione come se avesse causato questa prima risposta con una richiesta GET, ovvero utilizzando ulteriori richieste GET con opzioni Block2 contenenti valori NUM maggiori di zero. (Ciò si traduce nel trasferimento dell'intera rappresentazione, anche se solo alcuni dei blocchi sono cambiati rispetto a una notifica precedente.)

Come per altre risorse che cambiano dinamicamente, per garantire che i blocchi riassemblati provengano dalla stessa versione della rappresentazione, il server DOVREBBE includere un'opzione ETag in ogni risposta e il client che riassembla DEVE confrontare le opzioni ETag (Sezione 2.4). Ancor più che per il caso generale di Block2, i client che desiderano recuperare tutti i blocchi di una risorsa di cui sono stati informati con un primo blocco DOVREBBERO sforzarsi di farlo senza indebito ritardo.

Vedere la Sezione 3.4 per esempi.

2.7. Combinazione di Block1 e Block2

Negli scambi PUT e in particolare in quelli POST, sia il corpo della richiesta che il corpo della risposta possono essere sufficientemente grandi da richiedere l'uso di trasferimenti a blocchi. Innanzitutto, il trasferimento Block1 del corpo della richiesta procede come di consueto. Nello scambio dell'ultima fetta di questo trasferimento a blocchi, la risposta porta la prima fetta del trasferimento Block2 (NUM è zero). Per continuare questo trasferimento Block2, il client continua a inviare richieste simili alle richieste nella fase Block1, ma omette le opzioni Block1 e include un'opzione di richiesta Block2 con NUM diverso da zero.

I trasferimenti Block2 che recuperano il corpo della risposta per una richiesta che ha utilizzato Block1 DEVONO essere eseguiti in ordine sequenziale.

2.8. Combinazione di Block2 con Multicast

Un client può utilizzare l'opzione Block2 in una richiesta GET multicast con NUM = 0 per aiutare a limitare la dimensione della risposta.

Allo stesso modo, una risposta a una richiesta GET multicast può utilizzare un'opzione Block2 con NUM = 0 se la rappresentazione è grande o per limitare ulteriormente la dimensione della risposta.

In entrambi i casi, il client recupera eventuali ulteriori blocchi utilizzando scambi unicast; nelle richieste unicast, il client DOVREBBE prestare attenzione a qualsiasi preferenza di dimensione del blocco indicata dal server nella risposta alla richiesta multicast.

Altri usi delle opzioni Block in combinazione con i messaggi multicast sono oggetto di ulteriori studi.

2.9. Codici di risposta

Oltre ai codici di risposta definiti in [RFC7252], questa specifica definisce due codici di risposta ed estende il significato di uno.

2.9.1. 2.31 Continue

Questo nuovo codice di stato di successo indica che il trasferimento di questo blocco del corpo della richiesta è riuscito e che il server incoraggia l'invio di ulteriori blocchi, ma che non è ancora possibile determinare un risultato finale dell'intera richiesta a blocchi. Nessun payload viene restituito con questo codice di risposta.

2.9.2. 4.08 Request Entity Incomplete

Questo nuovo codice di stato di errore client indica che il server non ha ricevuto i blocchi del corpo della richiesta di cui ha bisogno per procedere. Il client non ha inviato tutti i blocchi, non li ha inviato nell'ordine richiesto dal server o li ha inviati abbastanza tempo fa che il server li ha già scartati.

(Si noti che un motivo per non avere i blocchi necessari a portata di mano potrebbe essere una mancata corrispondenza del Content-Format, vedere la Sezione 2.3. Nota di implementazione: Un server può rifiutare un trasferimento Block1 con questo codice quando NUM != 0 e viene indicato un Content-Format diverso da quello previsto dallo stato corrente della risorsa. Se implementa il trasferimento in modo stateless, può far corrispondere il Content-Format del blocco con quello della risorsa esistente. Se implementa il trasferimento in modo atomico, può far corrispondere il blocco con il pezzo di rappresentazione parzialmente riassemblato che sostituirà lo stato della risorsa.)

2.9.3. 4.13 Request Entity Too Large

Nella Sezione 5.9.2.9 di [RFC7252], il codice di risposta 4.13 (Request Entity Too Large) è definito come HTTP 413 "Request Entity Too Large". [RFC7252] raccomanda inoltre che questa risposta DOVREBBE includere un'opzione Size1 (Sezione 4) per indicare la dimensione massima dell'entità di richiesta che il server è in grado e disposto a gestire, a meno che il server non sia in grado di rendere disponibili queste informazioni.

La presente specifica consente al server di restituire questo codice di risposta in qualsiasi momento durante un trasferimento Block1 per indicare che attualmente non dispone delle risorse per memorizzare blocchi per un trasferimento che intenderebbe implementare in modo atomico. Consente inoltre al server di restituire una risposta 4.13 a una richiesta che non impiega Block1 come suggerimento per il client di provare a inviare Block1. Infine, una risposta 4.13 a una richiesta con un'opzione Block1 (uso di controllo, vedere la Sezione 2.3) in cui la risposta porta un SZX più piccolo nella sua opzione Block1 è un suggerimento per provare quel SZX più piccolo.

2.10. Considerazioni sulla memorizzazione nella cache

Questa specifica tenta di lasciare aperta una varietà di strategie di implementazione per le cache, in particolare quelle nei proxy di memorizzazione nella cache. Ad esempio, una cache è libera di memorizzare nella cache i blocchi individualmente, ma potrebbe anche attendere di ottenere la rappresentazione completa prima di servirne parti. La memorizzazione nella cache parziale può essere più efficiente in un cross-proxy (equivalente a un proxy HTTP in streaming). Un blocco memorizzato nella cache (risposta parzialmente memorizzata nella cache) può essere utilizzato al posto di una risposta completa per soddisfare una richiesta a blocchi presentata a una cache. Si noti che blocchi diversi possono avere valori Max-Age diversi, poiché vengono trasferiti in momenti diversi. Una risposta con un blocco aggiorna la freschezza della rappresentazione completa. I singoli blocchi possono essere convalidati e la convalida di un singolo blocco convalida la rappresentazione completa. Una risposta con un'opzione Block1 in uso di controllo con il bit M impostato invalida le risposte memorizzate nella cache per l'URI di destinazione.

Una cache o un proxy che combina le risposte (ad esempio, per dividere i blocchi in una richiesta o aumentare la dimensione del blocco in una risposta, o un cross-proxy) potrebbe dover combinare le risposte 2.31 e 2.01/2.04; un server stateless potrebbe rispondere con 2.01 solo sul primo blocco Block1 trasferito, il che domina qualsiasi risposta 2.04 per i blocchi successivi.

If-None-Match funziona correttamente solo su richieste Block1 con (NUM=0) e NON DEVE essere utilizzato su richieste Block1 con NUM != 0.