13. Conditional Requests (Requêtes conditionnelles)
Une requête conditionnelle est une requête HTTP qui inclut un ou plusieurs champs d'en-tête de requête indiquant une précondition à tester avant d'appliquer la méthode de requête à la ressource cible. La section 13.2 définit quand les préconditions sont évaluées et l'ordre de leur priorité lorsque plusieurs préconditions sont présentes.
Les requêtes GET conditionnelles constituent le mécanisme le plus efficace pour les mises à jour du cache HTTP [CACHING]. Les conditions peuvent également être appliquées aux méthodes de changement d'état, telles que PUT et DELETE, pour éviter le problème de "mise à jour perdue" : un client écrase accidentellement le travail d'un autre client qui agissait en parallèle.
13.1. Preconditions (Préconditions)
Les préconditions sont généralement définies par rapport à un état de la ressource cible dans son ensemble (son ensemble de valeurs actuelles) ou l'état observé dans une représentation précédemment obtenue (une valeur dans cet ensemble). Si une ressource possède plusieurs représentations actuelles, chacune avec son propre état observable, une précondition supposera que la correspondance de chaque requête à la représentation sélectionnée (section 3.2) est cohérente dans le temps. Quoi qu'il en soit, si la correspondance est incohérente ou si le serveur est incapable de sélectionner une représentation appropriée, aucun dommage ne résultera lorsque la précondition est évaluée à false.
Chaque précondition définie ci-dessous comprend une comparaison entre un ensemble de validateurs obtenus à partir de représentations antérieures de la ressource cible et l'état actuel des validateurs pour la représentation sélectionnée (section 8.8). Par conséquent, ces préconditions évaluent si l'état de la ressource cible a changé depuis un état donné connu du client. L'effet d'une telle évaluation dépend de la sémantique de la méthode et du choix de la condition, comme défini dans la section 13.2.
D'autres préconditions, définies par d'autres spécifications en tant que champs d'extension, peuvent imposer des conditions à tous les destinataires, l'état de la ressource cible en général, ou un groupe de ressources. Par exemple, le champ d'en-tête "If" dans WebDAV peut rendre une requête conditionnelle à divers aspects de plusieurs ressources, tels que les verrous ([WEBDAV], section 10.4), si le destinataire comprend et implémente ce champ.
L'extensibilité des préconditions n'est possible que lorsque la précondition peut être ignorée en toute sécurité si elle est inconnue (comme If-Modified-Since), lorsque le déploiement peut être assumé pour un cas d'utilisation donné, ou lorsque l'implémentation est signalée par une autre propriété de la ressource cible. Cela encourage l'accent mis sur les normes communes avec un déploiement partagé.
13.1.1. If-Match
Le champ d'en-tête "If-Match" rend la méthode de requête conditionnelle au fait que le serveur d'origine destinataire dispose d'au moins une représentation actuelle de la ressource cible, lorsque la valeur du champ est "*", ou qu'il dispose d'une représentation actuelle de la ressource cible qui possède un tag d'entité correspondant à un membre de la liste des tags d'entité fournis dans la valeur du champ.
Un serveur d'origine DOIT utiliser la fonction de comparaison forte lors de la comparaison des tags d'entité pour If-Match (section 8.8.3.2), car le client souhaite que cette précondition empêche l'application de la méthode s'il y a eu un changement dans les données de représentation.
If-Match = "*" / #entity-tag
Exemples :
If-Match: "xyzzy"
If-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
If-Match: *
If-Match est le plus souvent utilisé avec les méthodes de changement d'état (par exemple, POST, PUT, DELETE) pour empêcher les écrasements accidentels lorsque plusieurs agents utilisateurs peuvent agir en parallèle sur la même ressource (c'est-à-dire pour éviter le problème de "mise à jour perdue"). En général, il peut être utilisé avec toute méthode impliquant la sélection ou la modification d'une représentation pour interrompre la requête si le tag d'entité actuel de la représentation sélectionnée n'est pas un membre de la valeur du champ If-Match.
Lorsqu'un serveur d'origine reçoit une requête qui sélectionne une représentation et que cette requête inclut un champ d'en-tête If-Match, le serveur d'origine DOIT évaluer la condition If-Match conformément à la section 13.2 avant d'exécuter la méthode.
Pour évaluer un champ d'en-tête If-Match reçu :
-
Si la valeur du champ est "*", la condition est vraie si le serveur d'origine dispose d'une représentation actuelle pour la ressource cible.
-
Si la valeur du champ est une liste de tags d'entité, la condition est vraie si l'un des tags listés correspond au tag d'entité de la représentation sélectionnée.
-
Sinon, la condition est fausse.
Un serveur d'origine qui évalue une condition If-Match NE DOIT PAS exécuter la méthode demandée si la condition est évaluée à false. Au lieu de cela, le serveur d'origine PEUT indiquer que la requête conditionnelle a échoué en répondant avec un code d'état 412 (Precondition Failed).
Alternativement, si la requête est une opération de changement d'état qui semble avoir déjà réussi sur la ressource cible, un serveur d'origine PEUT répondre avec un code d'état 2xx (Successful) (c'est-à-dire que le changement d'état a déjà réussi car l'état de la ressource est déjà ce qui était attendu) si un ou plusieurs tags d'entité listés dans la valeur du champ If-Match correspondent au tag d'entité de la représentation sélectionnée.
Un client qui fournira ultérieurement un champ d'en-tête If-Match DEVRAIT d'abord obtenir un ou plusieurs tags d'entité dans une requête précédente, généralement en obtenant une représentation à partir du champ d'en-tête ETag (section 8.8.3) de la représentation.
13.1.2. If-None-Match
Le champ d'en-tête "If-None-Match" rend la méthode de requête conditionnelle au fait que le serveur d'origine destinataire ne dispose pas d'une représentation actuelle de la ressource cible, lorsque la valeur du champ est "*", ou qu'il dispose d'une représentation actuelle de la ressource cible qui ne possède pas un tag d'entité correspondant à l'un de ceux fournis dans la valeur du champ.
Un destinataire DOIT utiliser la fonction de comparaison faible lors de la comparaison des tags d'entité pour If-None-Match (section 8.8.3.2), car les tags d'entité faibles peuvent être utilisés pour la validation du cache même s'il y a eu des changements dans les données de représentation qui sont sémantiquement insignifiants.
If-None-Match = "*" / #entity-tag
Exemples :
If-None-Match: "xyzzy"
If-None-Match: W/"xyzzy"
If-None-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
If-None-Match: W/"xyzzy", W/"r2d2xxxx", W/"c3piozzzz"
If-None-Match: *
If-None-Match est principalement utilisé dans deux situations :
-
Avec GET ou HEAD pour mettre à jour une représentation mise en cache qui ne possède pas de tag d'entité. Si un serveur d'origine reçoit une requête pour If-None-Match avec GET ou HEAD, il DEVRAIT l'évaluer conformément à la section 13.2.
-
Avec d'autres méthodes pour empêcher une modification par inadvertance d'une représentation existante. Si une requête entraînerait autre chose que la création ou le remplacement d'une représentation sans précondition, et que le serveur dispose d'une représentation actuelle pour cette ressource, un client DEVRAIT envoyer une valeur de champ If-None-Match de "*".
Lorsqu'un serveur d'origine reçoit une requête qui sélectionne une représentation et que cette requête inclut un champ d'en-tête If-None-Match, le serveur d'origine DOIT évaluer la condition If-None-Match conformément à la section 13.2 avant d'exécuter la méthode.
Pour évaluer un champ d'en-tête If-None-Match reçu :
-
Si la valeur du champ est "*", la condition est fausse si le serveur d'origine dispose d'une représentation actuelle pour la ressource cible.
-
Si la valeur du champ est une liste de tags d'entité, la condition est fausse si l'un des tags listés correspond faiblement (section 8.8.3.2) au tag d'entité de la représentation sélectionnée.
-
Sinon, la condition est vraie.
Un serveur d'origine qui évalue une condition If-None-Match :
-
Si la méthode de requête est GET ou HEAD et que la condition est évaluée à false, le serveur d'origine DEVRAIT générer une réponse 304 (Not Modified).
-
Si la méthode de requête n'est pas GET ou HEAD et que la condition est évaluée à false, le serveur d'origine DOIT générer une réponse 412 (Precondition Failed).
-
Sinon (c'est-à-dire que la condition est vraie), le serveur d'origine DEVRAIT traiter la requête normalement.
13.1.3. If-Modified-Since
Le champ d'en-tête "If-Modified-Since" rend une méthode de requête GET ou HEAD conditionnelle au fait que la date de modification de la représentation sélectionnée est plus récente que la date et l'heure fournies dans la valeur du champ.
If-Modified-Since = HTTP-date
Exemple :
If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
Lorsqu'un destinataire est un serveur d'origine et que If-Modified-Since est un champ d'en-tête de requête sur une méthode GET ou HEAD, le destinataire DEVRAIT envoyer une réponse 304 (Not Modified) si la date Last-Modified de la représentation sélectionnée est antérieure ou égale à la date fournie dans le champ d'en-tête If-Modified-Since, sauf si l'évaluation conformément à la section 13.2 donnerait une réponse différente.
Un destinataire DOIT ignorer If-Modified-Since si la requête contient un champ d'en-tête If-None-Match ; la condition dans If-None-Match est considérée comme un remplacement plus précis de la condition dans If-Modified-Since, et les deux ne sont conditionnellement compatibles que lorsqu'elles sont évaluées indépendamment.
Un destinataire DEVRAIT ignorer le champ d'en-tête If-Modified-Since si la date fournie dans la valeur du champ est invalide ou dans le futur.
13.1.4. If-Unmodified-Since
Le champ d'en-tête "If-Unmodified-Since" rend la méthode de requête conditionnelle au fait que la date de dernière modification de la représentation sélectionnée est antérieure ou égale à la date fournie dans la valeur du champ.
If-Unmodified-Since = HTTP-date
Exemple :
If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT
Lorsqu'un destinataire est un serveur d'origine et que If-Unmodified-Since est un champ d'en-tête de requête sur une méthode de requête autre que GET ou HEAD, le destinataire DEVRAIT traiter la requête normalement si la date Last-Modified de la représentation sélectionnée est antérieure ou égale à la date fournie dans le champ d'en-tête If-Unmodified-Since. Sinon, le destinataire DEVRAIT envoyer une réponse 412 (Precondition Failed), sauf si l'évaluation conformément à la section 13.2 donnerait une réponse différente.
Un destinataire DOIT ignorer If-Unmodified-Since si la requête contient un champ d'en-tête If-Match ; la condition dans If-Match est considérée comme un remplacement plus précis de la condition dans If-Unmodified-Since, et les deux ne sont conditionnellement compatibles que lorsqu'elles sont évaluées indépendamment.
Un destinataire DEVRAIT ignorer le champ d'en-tête If-Unmodified-Since si la date fournie dans la valeur du champ est invalide ou dans le futur.
13.1.5. If-Range
Le champ d'en-tête "If-Range" fournit une condition spéciale pour les requêtes Range (section 14) : si le validateur fourni correspond au validateur actuel de la représentation sélectionnée, alors traiter le champ d'en-tête Range comme d'habitude, en retournant un ou plusieurs contenus partiels. Si le validateur ne correspond pas, alors ignorer le champ d'en-tête Range et retourner la représentation sélectionnée complète.
If-Range = entity-tag / HTTP-date
Un client NE DOIT PAS générer un champ d'en-tête If-Range dans une requête qui ne contient pas un champ d'en-tête Range.
Un serveur DOIT ignorer un champ d'en-tête If-Range reçu dans une requête qui ne contient pas un champ d'en-tête Range.
L'intention de If-Range est de permettre à un client de mettre à jour efficacement une représentation incomplète mise en cache lorsqu'elle est devenue obsolète. Si le champ d'en-tête If-Range n'était pas présent, une représentation incomplète mise en cache forcerait le client à la revalider (en utilisant une requête conditionnelle avec If-Match ou If-Unmodified-Since) et à ne demander les parties manquantes que si la revalidation montre qu'elle est toujours actuelle, ou bien à remplacer toute la représentation mise en cache. Le champ d'en-tête If-Range permet au client d'éviter ce trajet supplémentaire en demandant soit les parties actuelles, soit une représentation complète dans une seule requête.
Un serveur évalue la condition If-Range en utilisant la fonction de comparaison forte (section 8.8.3.2) lorsque la valeur du champ est un tag d'entité. Lorsque la valeur du champ est une date HTTP, le serveur la compare à la valeur du champ Last-Modified de la représentation sélectionnée, correspondant si les valeurs de timestamp sont exactement égales.
Un champ d'en-tête If-Range DEVRAIT être utilisé uniquement avec soit If-Unmodified-Since et une date Last-Modified, soit If-Match et un tag d'entité qui correspond fortement.
13.2. Evaluation of Preconditions (Évaluation des préconditions)
13.2.1. When to Evaluate (Quand évaluer)
Sauf lorsque la définition d'une précondition indique le contraire, un serveur DOIT évaluer les préconditions de requête reçues lorsqu'il reçoit une requête qui sélectionne une représentation, avant d'exécuter la méthode, car leur évaluation peut influencer l'exécution de la méthode.
Une conséquence de l'évaluation des préconditions avant d'exécuter la méthode est que différentes préconditions reçues après que la méthode a déjà commencé à s'exécuter n'auront pas d'impact sur cette exécution ou sa sémantique de réponse.
Ces préconditions peuvent être évaluées à différentes étapes de sélection. En pratique, les validateurs pour la "représentation sélectionnée" sont souvent disponibles avant d'exécuter la méthode, de sorte que les préconditions peuvent être évaluées avant de créer ou de modifier une représentation.
13.2.2. Precedence of Preconditions (Priorité des préconditions)
Lorsque plusieurs champs d'en-tête de requête conditionnelle sont présents dans une seule requête, l'ordre dans lequel les préconditions sont appliquées devient important. En pratique, les champs qui opèrent sur l'état de la ressource cible sont souvent déployés ensemble, comme If-Unmodified-Since utilisé avec If-Match, ou If-Modified-Since utilisé avec If-None-Match. Cependant, des combinaisons incohérentes de champs d'en-tête de précondition peuvent être présentes.
Un serveur DOIT évaluer les préconditions de requête reçues dans l'ordre suivant :
-
Lorsque le destinataire est le serveur d'origine et que If-Match est présent, évaluer la précondition If-Match et répondre avec un code d'état 412 (Precondition Failed) si elle est évaluée à false.
-
Lorsque le destinataire est le serveur d'origine, que If-Match est absent et que If-Unmodified-Since est présent, évaluer la précondition If-Unmodified-Since et répondre avec un code d'état 412 (Precondition Failed) si elle est évaluée à false.
-
Lorsque If-None-Match est présent, évaluer la précondition If-None-Match et répondre avec un code d'état 304 (Not Modified) (pour GET/HEAD) ou un code d'état 412 (Precondition Failed) (pour d'autres méthodes) si elle est évaluée à false.
-
Lorsque le destinataire est le serveur d'origine, que la méthode est GET ou HEAD, que If-None-Match est absent et que If-Modified-Since est présent, évaluer la précondition If-Modified-Since et répondre avec un code d'état 304 (Not Modified) si elle est évaluée à false.
-
Lorsque la méthode est GET, que le destinataire a une requête valide pour un champ d'en-tête Range et que If-Range est présent, traiter le champ d'en-tête Range si le validateur correspond au validateur actuel de la représentation sélectionnée ; sinon, ignorer le champ d'en-tête Range et répondre avec une réponse 200 (OK) et la représentation sélectionnée complète.
-
Sinon, toutes les conditions ont été satisfaites, donc exécuter l'action demandée normalement et générer une réponse appropriée.
Un serveur qui génère l'un des codes d'état de réponse ci-dessus à la suite du traitement DEVRAIT générer une représentation de l'état de la ressource cible dans la charge utile de la réponse si l'origine de la requête n'est pas fiable.
Toute extension aux champs d'en-tête If-Match et If-Unmodified-Since doit mettre à jour de manière équivalente cet algorithme d'évaluation de précondition pour maintenir un comportement cohérent.