Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

Mon livre « Cyberstructure »

Ève

RFC 7233: Hypertext Transfer Protocol (HTTP/1.1): Range Requests

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : R. Fielding (Adobe), Y. Lafon (W3C), J. Reschke (greenbytes)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF httpbis
Première rédaction de cet article le 15 juin 2014


Parmi les fonctions du protocole HTTP 1.1 qui ont eu droit à un RFC spécifique, les intervalles. C'est la possibilité de récupérer en HTTP, non pas la totalité d'une ressource mais une partie, un intervalle (range) de celle-ci. Ce RFC les décrivait mais a été ensuite supplanté par le RFC 9110.

Cette fonction est utile, par exemple, lorsqu'un transfert est interrompu en cours de route et qu'on voudrait pouvoir reprendre le téléchargement au point où il s'était arrêté, et non pas bêtement depuis le début. C'est possible avec le protocole rsync, comment faire avec HTTP ? Le client lit la partie déjà téléchargée, note sa taille, et demande au serveur le reste, en utilisant les intervalles. D'autres usages sont possibles comme de ne récupérer qu'une partie d'un document quand on n'a pas la possibilité de le traiter en entier. Attention, toutefois, ces intervalles sont optionnels pour les serveurs HTTP et un serveur qui ne les gère pas va vous envoyer toutes les données, même si vous n'aviez demandé qu'une partie.

Voici un exemple d'utilisation de ces intervalles avec le client HTTP curl et son option -r (--range en version longue). Ici, on récupère la fin du fichier, à partir du 20 001 ème octet (on compte en partant de zéro), et jusqu'à la fin :


% curl  -v --range "20000-" http://www.bortzmeyer.org/images/moi.jpg > moi-partiel.jpg

> GET /images/moi.jpg HTTP/1.1
> Range: bytes=20000-

< HTTP/1.1 206 Partial Content
< Accept-Ranges: bytes
< Content-Length: 34907
< Content-Range: bytes 20000-54906/54907
...

Vous avez vu les en-têtes utilisés pour décrire les intervalles. Notez qu'avec curl, on peut aussi mettre directement les en-têtes (par exemple --header "Range: bytes=20000-" au lieu de --range "20000-") mais c'est déconseillé car cela ne corrige pas les erreurs de syntaxe.

Maintenant, comment cela fonctionne t-il sur le câble, lorsqu'on examine le trafic HTTP ? D'abord, un mot sur les unités utilisées. L'en-tête Range: peut indiquer l'intervalle en octets, comme plus haut, ou dans d'autres unités (pour l'instant, aucune n'a été normalisée, lorsque ce sera le cas, elles seront ajoutées dans le registre IANA). L'avantage des octets est qu'ils conviennent à tous les types de ressources, les représentations des ressources étant transférées sous forme d'un flot d'octets. L'inconvénient est qu'ils ne tiennent pas compte de la syntaxe sous-jacente de la ressource. Par exemple, pour un fichier CSV, il serait sans doute plus pratique d'indiquer l'intervalle en nombre de lignes, pour permettre de récupérer un fichier non corrompu, mais cela supposerait un serveur HTTP qui connaisse la syntaxe CSV. Autre exemple d'une limite des octets : pour un fichier texte seul dont le jeu de caractères est Unicode, le nombre de caractères serait certainement une unité plus pertinente que le nombre d'octets (avec des octets, on risque de récupérer un fichier où certains caractères ne soient pas complets). Mais les serveurs HTTP ne savent pas forcément analyser les encodages d'Unicode, comme UTF-8.

Les intervalles peuvent être ouverts ou fermés. Un exemple d'intervalle fermé est bytes=500-999 qui spécifie le deuxième groupe de 500 octets de la ressource, de l'octet 500 (inclus) à l'octet 999 (inclus aussi). Un intervalle ouvert est bytes=-999 qui indique les 999 derniers octets du fichier (notez que le 999 n'a donc pas du tout la même signification selon qu'il y a un chiffre avant le tiret ou pas). On peut indiquer plusieurs intervalles discontinus, par exemple bytes=500-600,601-999. Ces intervalles doivent être dans l'ordre croissant et n'ont pas le droit de se recouvrir. Attention, un client facétieux ou malveillant peut utiliser des chiffres très grands pour un intervalle ou bien des intervalles qui se recoupent, ce qui, dans au moins un cas avec Apache, a mené à une faille de sécurité (voir aussi la section 6.1 sur ce problème de sécurité).

Le serveur peut indiquer quelles unités il accepte pour les intervalles avec l'en-tête Accept-Ranges:, par exemple :

Accept-Ranges: bytes

Le client, pour indiquer qu'il ne demande qu'une partie de la représentation d'une ressource, utilise, on l'a vu dans l'exemple plus haut, l'en-tête Range:. Combiné avec la requête GET, cet en-tête indique que le serveur, s'il est d'accord, s'il gère l'unité indiquée, et si la syntaxe est correcte, peut n'envoyer que la partie demandée. Ces en-têtes spécifiques aux requêtes avec intervalle sont stockés dans le registre IANA des en-têtes.

Un cas un peu plus compliqué est celui où le client a récupéré une partie d'une ressource, la ressource a été modifiée sur le serveur, le client veut récupérer le reste. Les intervalles demandées par le client ne signifient alors plus rien. Un mécanisme peu connu existe pour traiter ce cas : l'en-tête If-Range:, suivi d'un validateur (cf. RFC 7232) dit au serveur « envoie-moi seulement l'intervalle, s'il n'y a pas eu de changement depuis ce validateur, ou bien tout le fichier sinon ».

Quelles sont les réponses spécifiques aux requêtes avec intervalles ? La section 4 en donne la liste (elles ne sont que deux, dans les autres cas, le code de retour est un classique, comme par exemple 200 pour un transfert complet réussi, et sont dans le registre IANA). D'abord, il y a 206 qui signifie un succès (classe = 2) mais qui prévient que, comme demandé, seule une partie du contenu a été envoyé. Le serveur doit inclure un en-tête Content-Range: dans la réponse, indiquant ce qui a été réellement envoyé (regardez l'exemple curl au début). Si plusieurs intervalles étaient spécifiés dans la requête, le résultat est transporté dans une structure MIME de type multipart/byteranges décrite dans l'annexe A. Chaque partie de la réponse aura son propre Content-Range: indiquant où elle se situe dans la ressource originale.

L'autre code de retour possible est 416 qui indique une erreur (classe = 4) car l'intervalle indiqué n'est pas admissible. Par exemple, il y a recouvrement entre les intervalles, ou bien l'octet de départ est situé après la fin du fichier. Attention, rappelez-vous que les intervalles sont optionnels, un serveur peut ignorer l'en-tête Range: et, dans ce cas, répondre systématiquement avec un 200 en envoyant tout le contenu de la ressource.

Les changements depuis le RFC 2616 ? L'annexe B en fait la liste mais elle est courte, notre nouveau RFC est surtout une reformulation, avec peu de changements : insistance sur la liberté du serveur à honorer ou pas les requêtes avec intervalles, précisions sur les validateurs acceptables, création du registre des unités - même s'il ne compte pour l'instant qu'une seule unité, bytes...


Téléchargez le RFC 7233

Version PDF de cette page (mais vous pouvez aussi imprimer depuis votre navigateur, il y a une feuille de style prévue pour cela)

Source XML de cette page (cette page est distribuée sous les termes de la licence GFDL)