2. Transferts par blocs
Comme discuté dans l'introduction, il existe de bonnes raisons de limiter la taille des datagrammes dans les réseaux contraints :
-
par la taille maximale du datagramme (~ 64 KiB pour UDP)
-
par le désir d'éviter la fragmentation IP (MTU de 1280 pour IPv6)
-
par le désir d'éviter la fragmentation de la couche d'adaptation (60-80 octets pour 6LoWPAN [RFC4919])
Lorsqu'une représentation de ressource est plus grande que ce qui peut être transféré confortablement dans la charge utile d'un seul datagramme CoAP, une option Block peut être utilisée pour indiquer un transfert par blocs. Comme les charges utiles peuvent être envoyées à la fois avec les requêtes et avec les réponses, cette spécification fournit deux options distinctes pour chaque direction de transfert de charge utile. En nommant ces options (pour les transferts par blocs ainsi que dans la section 4), nous utilisons le numéro 1 ("Block1", "Size1") pour faire référence au transfert de la représentation de ressource qui concerne la requête, et le numéro 2 ("Block2", "Size2") pour faire référence au transfert de la représentation de ressource pour la réponse.
Dans ce qui suit, le terme "charge utile (payload)" sera utilisé pour le contenu réel d'un seul message CoAP, c'est-à-dire un seul bloc transféré, tandis que le terme "corps (body)" sera utilisé pour la représentation entière de la ressource qui est transférée de manière fragmentée (par blocs). L'option Content-Format s'applique au corps, pas à la charge utile ; en particulier, les limites entre les blocs peuvent se trouver à des endroits qui ne séparent pas des unités entières en termes de structure, d'encodage ou de codage de contenu utilisé par le Content-Format. (De même, l'option ETag définie dans la section 5.10.6 de [RFC7252] s'applique à la représentation entière de la ressource, et donc au corps de la réponse.)
Dans la plupart des cas, tous les blocs transférés pour un corps (sauf le dernier) seront de la même taille. (Si la première requête utilise une taille de bloc plus grande que celle préférée par le récepteur, les requêtes ultérieures utiliseront la taille de bloc préférée.) La taille de bloc n'est pas fixée par le protocole. Pour garder l'implémentation aussi simple que possible, les options Block ne prennent en charge qu'une petite plage de tailles de blocs en puissance de deux, de 2**4 (16) à 2**10 (1024) octets. Comme les corps ne se diviseront souvent pas uniformément dans la taille de bloc en puissance de deux choisie, la taille ne doit pas nécessairement être atteinte dans le dernier bloc (mais même pour le dernier bloc, la taille en puissance de deux choisie sera toujours indiquée dans le champ taille de bloc de l'option Block).
2.1. Les options Block2 et Block1
+-----+---+---+---+---+--------+--------+--------+---------+
| No. | C | U | N | R | Name | Format | Length | Default |
+-----+---+---+---+---+--------+--------+--------+---------+
| 23 | C | U | - | - | Block2 | uint | 0-3 | (none) |
| | | | | | | | | |
| 27 | C | U | - | - | Block1 | uint | 0-3 | (none) |
+-----+---+---+---+---+--------+--------+--------+---------+
Tableau 1 : Numéros d'options Block
Les options Block1 et Block2 peuvent être présentes à la fois dans les messages de requête et de réponse. Dans les deux cas, l'option Block1 concerne la charge utile de la requête et l'option Block2 concerne la charge utile de la réponse.
Par conséquent, pour les méthodes définies dans [RFC7252], Block1 est utile avec les requêtes POST et PUT portant une charge utile et leurs réponses. Block2 est utile avec les requêtes GET, POST et PUT et leurs réponses portant une charge utile (2.01, 2.02, 2.04 et 2.05 -- voir la section 5.5 de [RFC7252]).
Lorsque Block1 est présent dans une requête ou Block2 dans une réponse (c'est-à-dire dans ce message à la charge utile duquel il se rapporte), il indique un transfert par blocs et décrit comment cette charge utile spécifique par blocs fait partie du corps entier transféré ("usage descriptif"). Lorsqu'il est présent dans la direction opposée, il fournit un contrôle supplémentaire sur la façon dont cette charge utile sera formée ou a été traitée ("usage de contrôle").
L'implémentation de l'une ou l'autre option Block est destinée à être facultative. Cependant, lorsqu'elle est présente dans un message CoAP, elle DOIT être traitée (ou le message rejeté) ; par conséquent, elle est identifiée comme une option Critique (Critical). L'une ou l'autre option Block NE DOIT PAS apparaître plus d'une fois dans un seul message.
2.2. Structure d'une option Block
Trois éléments d'information peuvent devoir être transférés dans une option Block (Block1 ou Block2) :
-
la taille du bloc (SZX) ;
-
si d'autres blocs suivent (M) ;
-
le numéro relatif du bloc (NUM) dans une séquence de blocs de la taille donnée.
La valeur de l'option Block est un entier non signé de taille variable (0 à 3 octets) (uint, voir la section 3.2 de [RFC7252]). Cette valeur entière encode ces trois champs, voir Figure 1. (En raison des règles d'encodage uint CoAP, lorsque tous NUM, M et SZX sont à zéro, un entier de zéro octet sera envoyé.)
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 1 : Valeur de l'option Block
La taille du bloc est encodée à l'aide d'un entier non signé de trois bits (0 pour 2**4 octets à 6 pour 2**10 octets), que nous appelons "SZX" ("exposant de taille") ; la taille réelle du bloc est alors "2**(SZX + 4)". SZX est transféré dans les trois bits de poids faible de la valeur de l'option (c'est-à-dire "val & 7" où "val" est la valeur de l'option).
Le quatrième bit de poids faible, le bit M ou "more" ("val & 8"), indique si d'autres blocs suivent ou si le transfert par blocs actuel est le dernier bloc transféré.
La valeur de l'option divisée par seize (le champ NUM) est le numéro de séquence du bloc actuellement transféré, en commençant par zéro. Le transfert actuel concerne donc les "size" octets commençant à l'octet "NUM << (SZX + 4)".
Note d'implémentation : Pour faciliter l'implémentation, "(val & ~0xF) << (val & 7)", c'est-à-dire la valeur de l'option avec les 4 derniers bits masqués, décalée vers la gauche de la valeur de SZX, donne la position en octets du premier octet du bloc transféré.
Plus spécifiquement, dans la valeur d'option d'une option Block1 ou Block2, la signification des champs d'option est définie comme suit :
NUM: : Numéro de bloc, indiquant le numéro de bloc demandé ou fourni. Le numéro de bloc 0 indique le premier bloc d'un corps (c'est-à-dire commençant par le premier octet du corps).
M: : Drapeau More ("pas le dernier bloc"). Pour un usage descriptif, ce drapeau, s'il n'est pas défini, indique que la charge utile dans ce message est le dernier bloc du corps ; lorsqu'il est défini, il indique qu'il y a un ou plusieurs blocs supplémentaires disponibles. Lorsqu'une option Block2 est utilisée dans une requête pour récupérer un numéro de bloc spécifique ("usage de contrôle"), le bit M DOIT être envoyé à zéro et ignoré à la réception. (Dans une option Block1 dans une réponse, le drapeau M est utilisé pour indiquer l'atomicité, voir ci-dessous.)
SZX: : Taille de bloc. La taille de bloc est représentée sous la forme d'un entier non signé de trois bits indiquant la taille d'un bloc à la puissance de deux. Ainsi, taille de bloc = 2**(SZX + 4). Les valeurs autorisées de SZX sont de 0 à 6, c'est-à-dire que la taille de bloc minimale est 2**(0+4) = 16 et la taille maximale est 2**(6+4) = 1024. La valeur 7 pour SZX (qui indiquerait une taille de bloc de 2048) est réservée, c'est-à-dire NE DOIT PAS être envoyée et DOIT conduire à un code de réponse 4.00 Bad Request lors de la réception dans une requête.
Il n'y a pas de valeur par défaut pour les options Block1 et Block2. L'absence de l'une de ces options équivaut à une valeur d'option de 0 en ce qui concerne la valeur de NUM et M qui pourrait être donnée dans l'option, c'est-à-dire qu'elle indique que le bloc actuel est le premier et le seul bloc du transfert (numéro de bloc 0, bit M non défini). Cependant, contrairement à la valeur explicite 0, qui indiquerait un SZX de 0 et donc une valeur de taille de 16 octets, aucune taille explicite spécifique n'est impliquée par l'absence de l'option -- la taille est laissée non spécifiée. (Comme pour tout uint, la valeur explicite 0 est indiquée efficacement par une option de longueur nulle ; cela est donc différent sémantiquement de l'absence de l'option.)
2.3. Options Block dans les requêtes et les réponses
Les options Block sont utilisées dans l'un des trois rôles suivants :
-
En usage descriptif, c'est-à-dire une option Block2 dans une réponse (comme une réponse 2.05 pour GET), ou une option Block1 dans une requête (un PUT ou un POST) :
-
Le champ NUM dans la valeur de l'option décrit quel numéro de bloc est contenu dans la charge utile de ce message.
-
Le bit M indique si d'autres blocs doivent être transférés pour compléter le transfert de ce corps.
-
La taille de bloc impliquée par SZX DOIT correspondre à la taille de la charge utile en octets, si le bit M est défini. (SZX ne régit pas la taille de la charge utile si M n'est pas défini). Pour Block2, si la requête suggérait une valeur plus grande de SZX, la prochaine requête DOIT ramener SZX à la taille donnée dans la réponse. (L'effet est que, si le serveur utilise la plus petite de (1) sa taille de bloc préférée et (2) la taille de bloc demandée, tous les blocs d'un corps utilisent la même taille de bloc.)
-
-
Une option Block2 en usage de contrôle dans une requête (par exemple, GET) :
-
Le champ NUM dans l'option Block2 donne le numéro de bloc de la charge utile dont le retour est demandé dans la réponse.
-
Dans ce cas, le bit M n'a aucune fonction et DOIT être mis à zéro.
-
La taille de bloc donnée (SZX) suggère une taille de bloc (dans le cas du numéro de bloc 0) ou répète la taille de bloc des blocs précédents reçus (dans le cas d'un numéro de bloc non nul).
-
-
Une option Block1 en usage de contrôle dans une réponse (par exemple, une réponse 2.xx pour une requête PUT ou POST) :
-
Le champ NUM de l'option Block1 indique quel numéro de bloc est acquitté.
-
Si le bit M était défini dans la requête, le serveur peut choisir d'agir sur chaque bloc séparément, sans mémoire, ou de traiter la requête pour le corps entier de manière atomique, ou tout mélange des deux.
-
Si le bit M est également défini dans la réponse, cela indique que cette réponse ne porte pas le code de réponse final à la requête, c'est-à-dire que le serveur collecte d'autres blocs du même point de terminaison et prévoit d'implémenter la requête de manière atomique (par exemple, n'agit qu'à la réception du dernier bloc de charge utile). Dans ce cas, la réponse NE DOIT PAS porter d'option Block2.
-
Inversement, si le bit M n'est pas défini alors qu'il était défini dans la requête, cela indique que la requête par blocs a été exécutée maintenant spécifiquement pour ce bloc, et la réponse porte la réponse finale à cette requête (and à toutes les précédentes avec le bit M défini dans l'option Block1 de la réponse dans cette séquence de transferts par blocs) ; le client est toujours censé continuer à envoyer d'autres blocs, dont la méthode de requête peut ou non être également exécutée par bloc. (Notez que la ressource est maintenant dans un état partiellement mis à jour ; cette approche n'est appropriée que lorsque l'exposition d'un tel état intermédiaire est acceptable. Le client peut réduire la fenêtre en continuant rapidement à mettre à jour la ressource ou, en cas d'échec, en redémarrant la mise à jour.)
-
-
Enfin, la taille de bloc SZX donnée dans une option Block1 de contrôle indique la plus grande taille de bloc préférée par le serveur pour les transferts vers la ressource qui est identique ou inférieure à celle utilisée dans l'échange initial ; le client DEVRAIT utiliser cette taille de bloc ou une taille inférieure dans toutes les requêtes ultérieures de la séquence de transfert, même si cela signifie changer la taille de bloc (et éventuellement mettre à l'échelle le numéro de bloc en conséquence) à partir de maintenant.
-
En utilisant une ou les deux options Block, une seule opération REST peut être divisée en plusieurs échanges de messages CoAP. Comme spécifié dans [RFC7252], chacun de ces échanges de messages utilise son propre ID de message CoAP.
L'option Content-Format envoyée avec les requêtes ou les réponses DOIT refléter le Content-Format du corps entier. Si des blocs d'un corps de réponse arrivent avec des options Content-Format différentes, c'est au client de décider comment gérer cette erreur (il abandonnera généralement tout transfert par blocs en cours). Si des blocs d'une requête arrivent à un serveur avec des options Content-Format discordantes, le serveur NE DOIT PAS les assembler en une seule requête ; cela conduit généralement à une réponse d'erreur 4.08 (Request Entity Incomplete, Section 2.9.2) sur le bloc discordant.
2.4. Utilisation de l'option Block2
Lorsqu'une requête reçoit une réponse portant une option Block2 avec le bit M défini, le demandeur peut récupérer des blocs supplémentaires de la représentation de la ressource en envoyant d'autres requêtes avec les mêmes options que la requête initiale et une option Block2 donnant le numéro de bloc et la taille de bloc souhaités. Dans une requête, le client DOIT mettre le bit M d'une option Block2 à zéro et le serveur DOIT l'ignorer à la réception.
Pour influencer la taille de bloc utilisée dans une réponse, le demandeur PEUT également utiliser l'option Block2 sur la requête initiale, en donnant la taille souhaitée, un numéro de bloc de zéro et un bit M de zéro. Un serveur DOIT utiliser la taille de bloc indiquée ou une taille inférieure. Toute autre requête par blocs pour des blocs au-delà du premier DOIT indiquer la même taille de bloc que celle utilisée par le serveur dans la réponse à la première requête qui a donné une taille souhaitée à l'aide d'une option Block2.
Une fois que l'option Block2 est utilisée par le demandeur et qu'une première réponse a été reçue avec une taille de bloc éventuellement ajustée, toutes les autres requêtes dans un seul transfert par blocs convergeront finalement vers l'utilisation de la même taille, sauf qu'il peut ne pas y avoir assez de contenu pour remplir le dernier bloc (celui renvoyé avec le bit M non défini). (Notez que le client peut commencer à utiliser l'option Block2 dans une deuxième requête après qu'une première requête sans option Block2 a abouti à une option Block2 dans la réponse.) Le serveur utilise la taille de bloc indiquée dans l'option de requête ou une taille inférieure, mais le demandeur DOIT prendre note de la taille de bloc réelle utilisée dans la réponse qu'il reçoit à sa requête initiale et continuer à l'utiliser dans les requêtes ultérieures. Le comportement du serveur DOIT garantir que ce comportement du client aboutit à la même taille de bloc pour toutes les réponses d'une séquence (sauf pour la dernière avec le bit M non défini, et éventuellement la première si la requête initiale ne contenait pas d'option Block2).
Les transferts par blocs peuvent être utilisés pour obtenir (GET) des ressources dont les représentations sont entièrement statiques (ne changeant pas du tout au fil du temps, comme dans un schéma décrivant un appareil), ou pour des ressources changeant dynamiquement. Dans ce dernier cas, l'option Block2 DEVRAIT être utilisée conjointement avec l'option ETag ([RFC7252], section 5.10.6), pour garantir que les blocs réassemblés proviennent de la même version de la représentation : Le serveur DEVRAIT inclure une option ETag dans chaque réponse. Si une option ETag est disponible, le client, lors du réassemblage de la représentation à partir des blocs échangés, DOIT comparer les options ETag. Si les options ETag ne correspondent pas dans un transfert GET, le demandeur a la possibilité de tenter de récupérer de nouvelles valeurs pour les blocs qu'il a récupérés en premier. Pour minimiser l'inefficacité résultante, le serveur PEUT mettre en cache la valeur actuelle d'une représentation pour une séquence de requêtes en cours. (Le serveur peut identifier la séquence par la combinaison du point de terminaison demandeur et de l'URI étant la même dans chaque requête par blocs.) Notez bien que cette spécification n'exige pas que le serveur établisse un état quelconque ; cependant, les serveurs qui offrent des ressources changeant rapidement peuvent ainsi rendre impossible pour un client de récupérer un ensemble cohérent de blocs. Les clients qui souhaitent récupérer tous les blocs d'une ressource DEVRAIENT s'efforcer de le faire sans délai excessif. Les serveurs peuvent s'attendre pleinement à être libres de rejeter tout état mis en cache après une période de EXCHANGE_LIFETIME ([RFC7252], section 4.8.2) après le dernier accès à l'état, cependant, il n'y a aucune exigence de toujours conserver l'état aussi longtemps.
L'option Block2 ne fournit aucun moyen pour un seul point de terminaison d'effectuer plusieurs opérations de transfert de charge utile de réponse par blocs (par exemple, GET) procédant simultanément vers la même ressource. C'est rarement une exigence, mais comme solution de contournement, un client peut faire varier la clé de cache (par exemple, en utilisant l'un des plusieurs URI accédant aux ressources avec la même sémantique, ou en faisant varier une option élective compatible avec les proxys).
2.5. Utilisation de l'option Block1
Dans une requête avec une charge utile de requête (par exemple, PUT ou POST), l'option Block1 fait référence à la charge utile dans la requête (usage descriptif).
En réponse à une requête avec une charge utile (par exemple, un transfert PUT ou POST), la taille de bloc donnée dans l'option Block1 indique la préférence de taille de bloc du serveur pour cette ressource (usage de contrôle). Évidemment, à ce stade, le premier bloc a déjà été transféré par le client sans bénéficier de cette connaissance. Néanmoins, le client DEVRAIT tenir compte de la préférence indiquée et, pour tous les autres blocs, utiliser la taille de bloc préférée par le serveur ou une taille inférieure. Notez que toute réduction de la taille de bloc peut signifier que la deuxième requête commence par un numéro de bloc supérieur à un, car la première requête a déjà transféré plusieurs blocs comptés dans la taille inférieure.
Pour contrer les effets de la fragmentation de la couche d'adaptation sur la probabilité de livraison des paquets, un client peut vouloir renoncer à retransmettre une requête avec une charge utile relativement importante même avant que MAX_RETRANSMIT n'ait été atteint, et essayer de reformuler la requête comme un transfert par blocs avec une charge utile plus petite. Notez que cette nouvelle tentative est alors une nouvelle transaction de couche message et nécessite un nouvel ID de message. (En raison de l'incertitude quant à savoir si la requête ou l'accusé de réception a été perdu, cette stratégie est surtout utile pour les requêtes idempotentes.)
Dans un transfert par blocs d'une charge utile de requête (par exemple, un PUT ou un POST) qui est destiné à être implémenté de manière atomique au niveau du serveur, la création/le remplacement réel a lieu au moment où le dernier bloc, c'est-à-dire un bloc avec le bit M non défini dans l'option Block1, est reçu. Dans ce cas, toutes les réponses de succès aux blocs non finaux portent le code de réponse 2.31 (Continue, Section 2.9.1). Si tous les blocs précédents ne sont pas disponibles sur le serveur au moment du traitement du dernier bloc, le transfert échoue et le code d'erreur 4.08 (Request Entity Incomplete, Section 2.9.2) DOIT être retourné. Un serveur PEUT également renvoyer un code d'erreur 4.08 pour tout transfert Block1 (final ou non final) qui n'est pas en séquence ; par conséquent, les clients qui n'ont pas de mécanismes spécifiques pour gérer ce cas DEVRAIENT toujours commencer par le bloc zéro et envoyer les blocs suivants dans l'ordre.
Une raison pour laquelle un client pourrait rencontrer un code d'erreur 4.08 est que le serveur a déjà expiré et rejeté le corps de requête partiel en cours d'assemblage. Les clients DEVRAIENT s'efforcer d'envoyer tous les blocs d'une requête sans délai excessif. Les serveurs peuvent s'attendre pleinement à être libres de rejeter tout corps de requête partiel lorsqu'une période de EXCHANGE_LIFETIME ([RFC7252], Section 4.8.2) s'est écoulée après le transfert du bloc le plus récent ; cependant, il n'y a aucune exigence pour un serveur de toujours conserver le corps de requête partiel aussi longtemps.
Le code d'erreur 4.13 (Request Entity Too Large) peut être renvoyé à tout moment par un serveur qui ne dispose pas actuellement des ressources pour stocker des blocs pour un transfert de charge utile de requête par blocs qu'il aurait l'intention d'implémenter de manière atomique. (Notez qu'une réponse 4.13 à une requête qui n'utilise pas Block1 est un indice pour le client d'essayer d'envoyer Block1, et une réponse 4.13 avec un SZX plus petit dans son option Block1 que demandé est un indice pour essayer un SZX plus petit.)
Un transfert par blocs d'une charge utile de requête qui est implémenté de manière sans état au niveau du serveur est susceptible de laisser la ressource sur laquelle on opère dans un état incohérent pendant que le transfert est toujours en cours ou lorsque le client ne termine pas le transfert. Cette caractéristique est plus proche de celle des systèmes de fichiers distants que de celle de HTTP, où l'état est toujours conservé sur le serveur pendant un transfert. Des techniques bien connues de l'accès aux fichiers partagés (par exemple, des ressources temporaires spécifiques au client) peuvent être utilisées pour atténuer cette différence par rapport à HTTP.
L'option Block1 ne fournit aucun moyen pour un seul point de terminaison d'effectuer plusieurs opérations de transfert de charge utile de requête par blocs (par exemple, PUT ou POST) procédant simultanément vers la même ressource. Démarrer une nouvelle séquence de requêtes par blocs vers la même ressource (avant qu'une ancienne séquence du même point de terminaison ne soit terminée) écrase simplement le contexte que le serveur peut encore conserver. (C'est probablement exactement ce que l'on veut dans ce cas -- le client peut simplement avoir redémarré et perdu sa connaissance de la séquence précédente.)
2.6. Combinaison des transferts par blocs avec l'option Observe
L'option Observe fournit un moyen pour un client d'être notifié des changements au fil du temps d'une ressource [RFC7641]. Les ressources observées par les clients peuvent être plus grandes que ce qui peut être traité ou transféré confortablement dans un message CoAP. Les règles suivantes s'appliquent à la combinaison des transferts par blocs avec les notifications.
Les relations d'observation s'appliquent toujours à une ressource entière ; l'option Block2 ne fournit pas un moyen d'observer un seul bloc d'une ressource.
Comme pour les transferts GET de base, le client peut indiquer sa taille de bloc souhaitée dans une option Block2 dans la requête GET établissant ou renouvelant la relation d'observation. Si le serveur prend en charge les transferts par blocs, il DEVRAIT prendre note de la taille de bloc et l'appliquer comme taille maximale à toutes les notifications/réponses résultant de la requête GET (jusqu'à ce que le client soit retiré de la liste des observateurs ou que l'entrée dans cette liste soit mise à jour par le serveur recevant une nouvelle requête GET pour la ressource de la part du client).
Lors de l'envoi d'une notification 2.05 (Content), le serveur n'envoie que le premier bloc de la représentation. Le client récupère le reste de la représentation comme s'il avait provoqué cette première réponse par une requête GET, c'est-à-dire en utilisant des requêtes GET supplémentaires avec des options Block2 contenant des valeurs NUM supérieures à zéro. (Cela entraîne le transfert de la représentation entière, même si seulement certains des blocs ont changé par rapport à une notification précédente.)
Comme pour les autres ressources changeant dynamiquement, pour garantir que les blocs réassemblés proviennent de la même version de la représentation, le serveur DEVRAIT inclure une option ETag dans chaque réponse, et le client réassemblant DOIT comparer les options ETag (Section 2.4). Plus encore que pour le cas général de Block2, les clients qui souhaitent récupérer tous les blocs d'une ressource dont ils ont été notifiés avec un premier bloc DEVRAIENT s'efforcer de le faire sans délai excessif.
Voir la section 3.4 pour des exemples.
2.7. Combinaison de Block1 et Block2
Dans les échanges PUT et particulièrement dans les échanges POST, le corps de la requête et le corps de la réponse peuvent être suffisamment volumineux pour nécessiter l'utilisation de transferts par blocs. Tout d'abord, le transfert Block1 du corps de la requête se déroule comme d'habitude. Lors de l'échange de la dernière tranche de ce transfert par blocs, la réponse porte la première tranche du transfert Block2 (NUM est zéro). Pour continuer ce transfert Block2, le client continue d'envoyer des requêtes similaires aux requêtes de la phase Block1, mais omet les options Block1 et inclut une option de requête Block2 avec un NUM non nul.
Les transferts Block2 qui récupèrent le corps de réponse pour une requête qui a utilisé Block1 DOIVENT être effectués dans l'ordre séquentiel.
2.8. Combinaison de Block2 avec la multidiffusion (Multicast)
Un client peut utiliser l'option Block2 dans une requête GET multidiffusion avec NUM = 0 pour aider à limiter la taille de la réponse.
De même, une réponse à une requête GET multidiffusion peut utiliser une option Block2 avec NUM = 0 si la représentation est grande, ou pour limiter davantage la taille de la réponse.
Dans les deux cas, le client récupère tout autre bloc à l'aide d'échanges monodiffusion (unicast) ; dans les requêtes monodiffusion, le client DEVRAIT tenir compte de toute préférence de taille de bloc indiquée par le serveur dans la réponse à la requête multidiffusion.
D'autres utilisations des options Block conjointement avec les messages multidiffusion sont à l'étude.
2.9. Codes de réponse
Au-delà des codes de réponse définis dans [RFC7252], cette spécification définit deux codes de réponse et étend la signification d'un.
2.9.1. 2.31 Continue
Ce nouveau code d'état de succès indique que le transfert de ce bloc du corps de la requête a réussi et que le serveur encourage l'envoi d'autres blocs, mais qu'un résultat final de l'ensemble de la requête par blocs ne peut pas encore être déterminé. Aucune charge utile n'est renvoyée avec ce code de réponse.
2.9.2. 4.08 Request Entity Incomplete
Ce nouveau code d'état d'erreur client indique que le serveur n'a pas reçu les blocs du corps de la requête dont il a besoin pour continuer. Le client n'a pas envoyé tous les blocs, ne les a pas envoyés dans l'ordre requis par le serveur, ou les a envoyés il y a assez longtemps pour que le serveur les ait déjà rejetés.
(Notez qu'une raison pour ne pas avoir les blocs nécessaires à portée de main peut être une discordance de Content-Format, voir Section 2.3. Note d'implémentation : Un serveur peut rejeter un transfert Block1 avec ce code lorsque NUM != 0 et qu'un Content-Format différent est indiqué par rapport à ce qui est attendu de l'état actuel de la ressource. S'il implémente le transfert de manière sans état, il peut faire correspondre le Content-Format du bloc à celui de la ressource existante. S'il implémente le transfert de manière atomique, il peut faire correspondre le bloc au morceau de représentation partiellement réassemblé qui va remplacer l'état de la ressource.)
2.9.3. 4.13 Request Entity Too Large
Dans la section 5.9.2.9 de [RFC7252], le code de réponse 4.13 (Request Entity Too Large) est défini comme HTTP 413 "Request Entity Too Large". [RFC7252] recommande également que cette réponse DEVRAIT inclure une option Size1 (Section 4) pour indiquer la taille maximale de l'entité de requête que le serveur est capable et disposé à gérer, à moins que le serveur ne soit pas en mesure de rendre cette information disponible.
La présente spécification permet au serveur de renvoyer ce code de réponse à tout moment pendant un transfert Block1 pour indiquer qu'il ne dispose pas actuellement des ressources pour stocker des blocs pour un transfert qu'il aurait l'intention d'implémenter de manière atomique. Elle permet également au serveur de renvoyer une réponse 4.13 à une requête qui n'emploie pas Block1 comme indice pour le client d'essayer d'envoyer Block1. Enfin, une réponse 4.13 à une requête avec une option Block1 (usage de contrôle, voir Section 2.3) où la réponse porte un SZX plus petit dans son option Block1 est un indice pour essayer ce SZX plus petit.
2.10. Considérations sur la mise en cache
Cette spécification tente de laisser une variété de stratégies d'implémentation ouvertes pour les caches, en particulier ceux des proxys de mise en cache. Par exemple, un cache est libre de mettre en cache les blocs individuellement, mais pourrait également attendre d'obtenir la représentation complète avant d'en servir des parties. La mise en cache partielle peut être plus efficace dans un cross-proxy (équivalent à un proxy HTTP de streaming). Un bloc mis en cache (réponse partiellement mise en cache) peut être utilisé à la place d'une réponse complète pour satisfaire une requête par blocs présentée à un cache. Notez que différents blocs peuvent avoir des valeurs Max-Age différentes, car ils sont transférés à des moments différents. Une réponse avec un bloc met à jour la fraîcheur de la représentation complète. Les blocs individuels peuvent être validés, et la validation d'un seul bloc valide la représentation complète. Une réponse avec une option Block1 en usage de contrôle avec le bit M défini invalide les réponses mises en cache pour l'URI cible.
Un cache ou un proxy qui combine des réponses (par exemple, pour diviser des blocs dans une requête ou augmenter la taille de bloc dans une réponse, ou un cross-proxy) peut avoir besoin de combiner des réponses 2.31 et 2.01/2.04 ; un serveur sans état peut répondre par 2.01 uniquement sur le premier bloc Block1 transféré, ce qui domine toute réponse 2.04 pour les blocs ultérieurs.
If-None-Match ne fonctionne correctement que sur les requêtes Block1 avec (NUM=0) et NE DOIT PAS être utilisé sur les requêtes Block1 avec NUM != 0.