Aller au contenu principal

16. Comportement du proxy (Proxy Behavior)

16.1 Aperçu (Overview)​

Un proxy SIP est un élément qui route les requêtes SIP vers un serveur d'agent utilisateur (UAS) et les réponses SIP vers un client d'agent utilisateur (UAC). Une requête peut traverser plusieurs proxies avant d'atteindre le UAS. Chaque proxy prend une décision de routage et modifie la requête avant de la transférer à l'élément suivant. Les réponses sont routées à travers la même série de proxies, en sens inverse, jusqu'à ce qu'elles atteignent le UAC.

Être un proxy est un rôle logique qu'un élément SIP peut jouer. Lorsqu'une requête arrive, un élément capable de jouer le rôle de proxy doit d'abord déterminer s'il doit répondre lui-même à la requête. Par exemple, la requête peut être mal formée ou le proxy peut exiger des informations d'identification du client avant d'agir en tant que proxy. L'élément peut répondre avec n'importe quel code d'erreur approprié (PEUT). S'il répond directement à la requête, cet élément joue le rôle de UAS et doit se comporter conformément à la section 8.2.

Un proxy PEUT fonctionner en mode avec état (stateful) ou sans état (stateless) pour chaque nouvelle requête. S'il est sans état, le proxy agit comme un simple élément de transfert. Il prend des décisions de ciblage et de routage basées sur la requête, et transfère la requête à un seul élément en aval. Toutes les réponses reçues sont simplement transférées en amont. Un proxy sans état supprime toute information sur le message après l'avoir transféré. Un proxy avec état mémorise des informations (en particulier l'état de transaction) sur chaque requête reçue et sur toute requête envoyée suite au traitement de cette requête. Il utilise ces informations pour influencer le traitement des messages futurs liés à cette requête. Un proxy avec état PEUT « fork » (router vers plusieurs destinations) une requête. Les requêtes transférées vers plusieurs emplacements DOIVENT être traitées avec état.

Selon les circonstances, un proxy PEUT transférer une requête avec état de transaction via un transport avec état (comme TCP) sans conserver l'état de transaction. Par exemple, un proxy PEUT transférer une requête de manière sans état de transaction entre deux connexions TCP tant qu'il inclut dans le message suffisamment d'informations pour transférer la réponse via la même connexion par laquelle la requête est arrivée. Les requêtes transférées entre différents types de transport, où le TU doit assumer un rôle actif pour garantir la livraison fiable sur l'un des transports, DOIVENT être transférées avec état de transaction.

Qu'il fonctionne avec ou sans état, un proxy PEUT passer à un comportement sans état à tout moment pendant le traitement de la requête, à condition de ne pas avoir fait quelque chose qui empêche d'être sans état dès le départ (comme le fork ou la génération d'une réponse 100). Lors de cette transition, il supprime simplement tout l'état. Un proxy NE DOIT PAS initier de requête CANCEL.

Que le proxy fonctionne avec ou sans état, la majeure partie du traitement de la requête est identique. Les sous-sections suivantes sont décrites du point de vue d'un proxy avec état. La dernière section indique où un proxy sans état se comporte différemment.

16.2 Proxy avec état (Stateful Proxy)​

Lorsqu'il est avec état, le proxy est un moteur de traitement de transactions SIP pur. Son comportement est modélisé ici en termes de transactions serveur et client définies à la section 17. Un proxy avec état possède, associées à une ou plusieurs transactions client, des transactions serveur gérées par un composant de traitement de proxy de niveau supérieur (voir figure 3, appelé cœur du proxy). Les requêtes entrantes sont traitées par la transaction serveur. La requête issue de la transaction serveur est passée au cœur du proxy. Le cœur du proxy détermine où router la requête (un ou plusieurs emplacements de saut suivant). L'envoi de la requête vers chaque emplacement de saut suivant est traité par une transaction client associée. Le cœur du proxy collecte les réponses des transactions client et les utilise pour envoyer les réponses sur la transaction serveur.

Pour chaque nouvelle requête, un proxy avec état crée une nouvelle transaction serveur. Toutes les retransmissions de la requête sont traitées par cette transaction serveur conformément à la section 17. Le cœur du proxy DOIT se comporter comme un UAS en envoyant une réponse provisoire immédiate (telle que 100 Trying) sur cette transaction serveur, comme décrit à la section 8.2.6. Par conséquent, un proxy avec état NE DOIT PAS générer de réponse 100 (Trying) pour une requête non INVITE.

C'est un modèle du comportement du proxy, et non un modèle logiciel. Les implémentations sont libres d'adopter toute approche qui reproduit le comportement externe défini par ce modèle.

Pour toute nouvelle requête (y compris les méthodes inconnues), un élément souhaitant proxifier la requête DOIT :

  1. Valider la requête (section 16.3)

2. Prétraiter les informations de routage (section 16.4)

3. Déterminer les cibles de la requête (section 16.5)

+--------------------+
| | +---+
| | | C |
| | | T |
| | +---+
+---+ | Proxy | +---+ CT = Client Transaction
| S | | "Higher" Layer | | C |
| T | | | | T | ST = Server Transaction
+---+ | | +---+
| | +---+
| | | C |
| | | T |
| | +---+
+--------------------+

Figure 3 : Modèle de proxy avec état

4. Transférer la requête vers chaque cible (section 16.6)

5. Traiter toutes les réponses (section 16.7)

16.3 Validation de la requête (Request Validation)​

Avant qu'un élément proxifie une requête, il DOIT valider la validité du message. Un message valide DOIT passer les contrôles suivants.

  1. Syntaxe raisonnable (Reasonable Syntax)

2. Schéma d'URI (URI scheme)

3. Max-Forwards

4. (Optionnel) Détection de boucle (Loop Detection)

5. Proxy-Require

6. Proxy-Authorization

Si l'un de ces contrôles échoue, l'élément DOIT se comporter en tant que serveur d'agent utilisateur (voir section 8.2) et répondre avec un code d'erreur.

Un proxy n'est pas tenu de détecter les requêtes fusionnées (merged), et NE DOIT PAS les traiter comme une condition d'erreur. L'extrémité recevant la requête résout la fusion conformément à la section 8.2.2.2.

  1. Contrôle de syntaxe raisonnable (Reasonable syntax check)

    La requête DOIT être formatée de manière suffisante pour être traitée par la transaction serveur. Tous les composants impliqués dans les étapes de validation de requête ou de transfert de requête ultérieures DOIVENT être formatés de manière suffisante. Les autres composants DOIVENT être ignorés, que leur format soit correct ou non, et ne pas être modifiés lors du transfert du message. Par exemple, un élément ne rejette pas une requête parce que le champ d'en-tête Date est mal formé. De même, un proxy ne supprime pas un champ d'en-tête Date mal formé avant de transférer la requête.

    Ce protocole est conçu pour être étendu. Les extensions futures peuvent définir de nouvelles méthodes ou champs d'en-tête à tout moment. Un élément NE DOIT PAS refuser de proxifier une requête parce qu'elle contient des méthodes ou des champs d'en-tête inconnus.

  2. Contrôle du schéma d'URI (URI scheme check)

    Si le Request-URI est une URI dont le proxy ne comprend pas le schéma, le proxy DOIT rejeter la requête avec une réponse 416 (Unsupported URI Scheme).

  3. Contrôle Max-Forwards

    Le champ d'en-tête Max-Forwards (section 20.22) est utilisé pour limiter le nombre d'éléments qu'une requête SIP peut traverser.

    Si la requête ne contient pas de champ d'en-tête Max-Forwards, ce contrôle réussit.

    Si la requête contient un champ d'en-tête Max-Forwards dont la valeur est supérieure à zéro, le contrôle réussit.

    Si la requête contient un champ d'en-tête Max-Forwards dont la valeur est zéro (0), l'élément NE DOIT PAS transférer la requête. Si la requête est destinée à OPTIONS, l'élément PEUT agir comme destinataire final et y répondre conformément à la section 11. Sinon, l'élément DOIT renvoyer une réponse 483 (Too many hops).

  4. Contrôle optionnel de détection de boucle (Optional Loop Detection check)

    Un élément PEUT vérifier la présence de boucles de transfert avant de transférer une requête. Si la requête contient un champ d'en-tête Via avec une valeur sent-by égale à celle que le proxy a précédemment définie, la requête a déjà été transférée par cet élément. La requête a bouclé ou bien a légitimement spiralé à travers l'élément. Pour déterminer si la requête a bouclé, l'élément PEUT exécuter le calcul du paramètre branch décrit à l'étape 8 de la section 16.6 sur ce message et le comparer au paramètre reçu dans ce champ Via. Si les paramètres correspondent, la requête a bouclé. S'ils diffèrent, la requête a spiralé et le traitement se poursuit. Si une boucle est détectée, l'élément PEUT renvoyer une réponse 482 (Loop Detected).

  5. Contrôle Proxy-Require

    Les extensions futures de ce protocole peuvent introduire des fonctionnalités nécessitant un traitement spécial par les proxies. Les extrémités incluent un champ d'en-tête Proxy-Require dans les requêtes utilisant ces fonctionnalités, indiquant au proxy de ne pas traiter la requête à moins que la fonctionnalité ne soit comprise.

    Si la requête contient un champ d'en-tête Proxy-Require (section 20.29) avec un ou plusieurs option-tag que cet élément ne comprend pas, l'élément DOIT renvoyer une réponse 420 (Bad Extension). La réponse DOIT inclure un champ d'en-tête Unsupported (section 20.40) énumérant les option-tag que l'élément n'a pas compris.

  6. Contrôle Proxy-Authorization

    Si un élément exige des informations d'identification avant de transférer une requête, il DOIT l'inspecter conformément à la section 22.3. Cette section définit également ce que l'élément doit faire en cas d'échec de l'inspection.

16.4 Préparation de la requête pour le routage (Preparing the Request for Routing)​

Avant de transférer la requête, l'élément DOIT inspecter et modifier les champs d'en-tête affectant le routage. Le champ d'en-tête Record-Route (section 20.30) reste dans la requête tel quel. De plus, l'élément DOIT exécuter les étapes suivantes :

  1. Si la requête contient un champ d'en-tête Route (section 20.34) et que sa première valeur (la plus haute) ne désigne pas l'élément, l'élément passe à la section 16.6 sans modifier la requête. L'élément n'insère pas de valeur Record-Route dans la requête. L'élément transfère la requête telle quelle à l'élément suivant.

Note : le fait que la première valeur Route ne désigne pas l'élément signifie que l'élément traite un champ Route inséré par un élément antérieur n'implémentant pas le loose routing.

2. Si la requête contient un champ d'en-tête Route (section 20.34) et que sa première valeur désigne l'élément :

Si l'élément prend en charge le loose routing, l'élément DOIT supprimer la première valeur du champ d'en-tête Route. Les procédures de loose routing s'appliquent.

Si l'élément n'implémente pas le loose routing, l'élément DOIT appliquer les procédures de strict routing de la RFC 2543.

3. Enfin, l'élément PEUT ajouter à la requête une valeur Record-Route le désignant lui-même.

16.5 Détermination des cibles de la requête (Determining Request Targets)​

Lorsqu'un élément traite une requête créant un dialogue (par exemple INVITE), il DOIT initialiser l'ensemble de routage (route set) du dialogue. L'ensemble de routage est initialisé lorsque l'élément insère une valeur Record-Route dans la requête.

Lorsqu'un élément traite une requête créant un dialogue, il DOIT transférer la requête vers un ou plusieurs emplacements. Cela s'appelle l'ensemble des cibles (target set).

La façon dont l'élément détermine les cibles dépend du type de requête (créant un dialogue ou dans un dialogue) et de savoir si le Request-URI indique un domaine géré par l'élément.

  1. Si la requête ne contient pas de champ d'en-tête Route, l'élément DOIT vérifier si l'URI indiquée par le Request-URI désigne une ressource qu'il possède. Si l'URI indique une ressource dans un domaine géré par l'élément, il DOIT remplacer la valeur du Request-URI par un ensemble représentant l'emplacement de cette ressource (par exemple les Contacts enregistrés ou l'agent personnel de la ressource). Cela se fait généralement en exécutant le service de localisation de l'élément. L'emplacement peut provenir d'un enregistrement (section 10), d'une redirection ou d'autres moyens.

Si le Request-URI n'indique pas une ressource d'un domaine géré, l'élément place le Request-URI dans l'ensemble des cibles.

2. Si la requête contient un champ d'en-tête Route, l'élément DOIT définir l'ensemble des cibles à l'emplacement indiqué par la première valeur (la plus haute) du champ d'en-tête Route. Si l'élément implémente le loose routing, la première valeur du champ Route a déjà été supprimée (à l'étape 2 de la section 16.4), donc la valeur Route suivante (si elle existe) devient l'ensemble des cibles. L'URI du Request-URI n'est pas utilisée pour calculer l'ensemble des cibles.

Pour une requête dans un dialogue (par exemple BYE), l'élément DOIT définir l'ensemble des cibles à la première valeur de l'ensemble de routage du dialogue. L'URI cible distante du dialogue n'est pas utilisée pour calculer l'ensemble des cibles.

L'élément PEUT appliquer des contrôles de politique locale à l'ensemble des cibles avant de transférer. L'élément PEUT modifier l'ensemble des cibles pour récursiver lors de la réception d'une réponse 3xx.

16.6 Transfert de la requête (Forwarding the Request)​

Avant de transférer (ou proxifier) une requête, l'élément DOIT exécuter les étapes suivantes pour chaque destination de son ensemble de cibles :

  1. Créer une copie (Make a copy)

     L'élément crée une copie de la requête reçue et la modifie lors des étapes suivantes. L'élément NE DOIT PAS modifier directement la requête reçue. Cela permet à l'élément de transférer la requête d'origine en cas d'erreur ou d'anomalie.

  2. Échanger l'adresse multicast contre un hôte multicast-capable (Swap multicast address for a multicast-capable host)

     Si la partie hôte du Request-URI est l'adresse d'un groupe IP multicast, l'élément PEUT remplacer la partie hôte par une adresse unicast d'un hôte multicast-capable capable d'écouter le groupe et de traiter la requête. Cela empêche les autres hôtes du groupe multicast de recevoir et de traiter une copie de la requête.

  3. Ajouter une valeur Record-Route si nécessaire (Add a Record-Route value if necessary)

     Si l'élément insère une valeur Record-Route, il DOIT insérer au début de la copie une nouvelle valeur Record-Route égale à l'URI suivante :

        o Si l'élément a reçu la requête via UDP mais l'envoie via TCP, l'URI DOIT être une SIP URI et inclure le nom d'hôte ou l'adresse IP (et le port optionnel) de l'élément ainsi qu'un paramètre transport indiquant le transport écouté. Si l'élément a initialement reçu en UDP et envoie via TCP, l'URI DOIT utiliser le schéma sip.

        o Si l'élément a reçu la requête via TCP et l'envoie via UDP, l'URI DOIT être une SIP URI et inclure le nom d'hôte ou l'adresse IP (et le port optionnel) de l'élément ainsi qu'un paramètre transport=udp.

        o Si l'élément a reçu via TLS et envoie via une connexion non TLS (ou inversement), l'URI DOIT être une SIPS URI ou une SIP URI selon que le transport de réception était TLS.

        o Sinon, l'élément PEUT utiliser une SIP URI ou SIPS URI contenant son nom d'hôte ou son adresse IP (et le port optionnel). L'élément PEUT écouter sur un port différent de celui par lequel la requête est arrivée. L'élément PEUT inclure un paramètre transport indiquant ses capacités.

     L'élément DOIT inclure le paramètre lr dans l'URI qu'il insère dans le champ Record-Route (voir section 19.1.1).

  4. Traiter les informations de routage (Process routing information)

     Si l'élément implémente le loose routing, il ne modifie pas le Request-URI. Sinon, s'il est un strict router, l'élément DOIT copier la première valeur du champ Route dans le Request-URI et la supprimer du champ Route. L'élément NE DOIT PAS modifier les paramètres de cette URI de quelque manière que ce soit avant de la placer dans le Request-URI.

     L'élément PEUT vérifier si l'une des valeurs du champ Route le désigne. Si c'est le cas, il PEUT la supprimer.

  5. Ajouter le Request-URI à la copie (Add the Request-URI to the copy)

     Si l'élément est un strict router et que le Request-URI de la copie provient de la première valeur du champ Route, il DOIT la supprimer du champ Route.

  6. Décrémenter Max-Forwards (Decrement Max-Forwards)

     Si la copie ne contient pas de champ Max-Forwards, l'élément DOIT le régler à 70. Sinon, l'élément DOIT décrémenter la valeur du champ de 1.

  7. Déterminer l'adresse, le port et le transport du saut suivant (Determine the next-hop address, port, and transport)

     L'élément détermine, pour un membre de l'ensemble des cibles, l'adresse, le port et le transport.

     Si l'ensemble des cibles était une valeur Route, l'adresse, le port et le transport sont déterminés en résolvant cette URI selon les procédures de l'annexe C de la RFC 2543.

     Si l'ensemble des cibles était le Request-URI, les procédures de la RFC 3263 sont appliquées en utilisant la méthode et le Request-URI.

  8. Ajouter son propre Via à la copie (Add own Via to the copy)

     L'élément DOIT ajouter au début du champ Via de la copie une nouvelle valeur Via contenant son adresse sent-by. L'adresse DOIT être l'endroit où l'élément écoute sur ce transport, et il DOIT garantir qu'il recevra la réponse via cette connexion.

     La valeur Via DOIT inclure le paramètre branch que l'élément a choisi lors de l'envoi de la requête vers cette destination sur ce transport.

     Le paramètre branch DOIT être unique pour toutes les requêtes envoyées par l'élément (sauf CANCEL et ACK non 2xx). Cela exige l'unicité dans l'espace et le temps. Pour calculer ce paramètre branch, l'élément DOIT hacher une partie spécifique de la requête (une chaîne commençant par le magic cookie « z9hG4bK » de la RFC 3261).

     Lorsqu'un proxy transfère une requête, il crée une copie contenant toutes les valeurs reçues (y compris le Request-URI) et y ajoute son Via. Tous les paramètres constituant la syntaxe de la requête et tout champ d'en-tête affectant le routage ou l'admission DOIVENT être inclus dans le calcul de hachage. Cela est nécessaire pour distinguer une requête bouclant d'une requête dont les paramètres de routage ont changé avant de revenir à ce serveur.

     La méthode de requête NE DOIT PAS être incluse dans le calcul du paramètre branch. En particulier, les requêtes CANCEL et ACK (pour réponses non 2xx) DOIVENT avoir la même valeur branch que la requête correspondante qu'elles annulent ou confirment. Le paramètre branch est utilisé pour corréler ces requêtes au serveur (voir sections 17.2.3 et 9.2).

  9. Ajouter un champ Content-Length si nécessaire (Add a Content-Length header field if necessary)

     Si la requête est envoyée au saut suivant via un transport en flux et que la copie ne contient pas de champ Content-Length, le proxy DOIT en insérer un avec la valeur correcte pour le corps de la requête (section 20.14).

  10. Transférer la requête (Forward Request)

      Un proxy avec état DOIT créer une nouvelle transaction client pour cette requête comme décrit à la section 17.1 et ordonner à la transaction d'envoyer la requête via l'adresse, le port et le transport déterminés à l'étape 7.

  11. Régler le minuteur C (Set timer C)

      Pour gérer le cas où une requête INVITE ne génère jamais de réponse finale, le TU utilise un minuteur appelé minuteur C. Le minuteur C DOIT être réglé pour chaque transaction client lorsqu'une requête INVITE est proxifiée. Le minuteur DOIT être supérieur à 3 minutes. La section 16.7 point 2 explique comment ce minuteur est mis à jour avec les réponses provisoires, et la section 16.8 explique le traitement lors de son déclenchement.

16.7 Traitement des réponses (Response Processing)​

Lorsqu'un élément reçoit une réponse, il tente d'abord de localiser une transaction client (section 17.1.3) correspondant à la réponse. S'il n'en trouve pas, l'élément DOIT traiter la réponse (même s'il s'agit d'une réponse d'information) comme un proxy sans état (décrit ci-dessous). Si une correspondance est trouvée, la réponse est remise à la transaction client.

  Transférer les réponses pour lesquelles aucune transaction client (ou plus généralement aucune connaissance d'une requête associée envoyée) n'est trouvée améliore la robustesse. En particulier, cela garantit que les réponses 2xx « tardives » aux requêtes INVITE sont correctement transférées.

Lorsque les transactions client remettent les réponses à la couche proxy, le traitement suivant DOIT avoir lieu :

  1. Trouver le contexte de réponse approprié

2. Mettre à jour le minuteur C pour les réponses provisoires

3. Supprimer le Via le plus haut

4. Ajouter la réponse au contexte de réponse

5. Vérifier si cette réponse doit être transférée immédiatement

6. Choisir si nécessaire la meilleure réponse finale du contexte de réponse

Si aucune réponse finale n'a été transférée après la fin de toutes les transactions client associées au contexte de réponse, le proxy DOIT choisir et transférer la meilleure réponse parmi celles qu'il a vues jusqu'à présent.

Le traitement suivant DOIT être effectué sur chaque réponse transférée. Il est probable que plusieurs réponses à chaque requête soient transférées : au moins chaque provisoire et une réponse finale.

  7. Agréger les valeurs de champ d'en-tête Authorization si nécessaire

8. Réécrire éventuellement les valeurs de champ Record-Route

9. Transférer la réponse

10. Générer les requêtes CANCEL nécessaires

Chacune des étapes ci-dessus est détaillée ci-dessous :

  1. Trouver le contexte (Find Context)

     Le proxy localise le « contexte de réponse » qu'il a créé avant de transférer la requête d'origine à l'aide de la clé décrite à la section 16.6. Les étapes de traitement restantes ont lieu dans ce contexte.

  2. Mettre à jour le minuteur C pour les réponses provisoires (Update timer C for provisional responses)

     Pour une transaction INVITE, si la réponse est une réponse provisoire avec un code d'état de 101 à 199 inclus (c'est-à-dire autre que 100), le proxy DOIT réinitialiser le minuteur C de cette transaction client. Le minuteur PEUT être réinitialisé à une valeur différente, mais cette valeur DOIT être supérieure à 3 minutes.

  3. Via

     Le proxy supprime la valeur la plus haute du champ d'en-tête Via de la réponse.

     S'il ne reste aucune valeur Via dans la réponse, la réponse était destinée à cet élément et NE DOIT PAS être transférée. Le reste du traitement de cette section n'est pas effectué sur ce message ; à la place, les règles de traitement UAC de la section 8.1.3 sont suivies (le traitement de la couche transport a déjà eu lieu).

     Cela se produit, par exemple, lorsque l'élément génère des requêtes CANCEL comme décrit à la section 10.

  4. Ajouter la réponse au contexte (Add response to context)

     Les réponses finales reçues sont stockées dans le contexte de réponse jusqu'à ce qu'une réponse finale soit générée sur la transaction serveur associée à ce contexte. La réponse peut être candidate pour la meilleure réponse finale à renvoyer sur cette transaction serveur. Les informations de cette réponse peuvent être nécessaires pour former la meilleure réponse, même si cette réponse n'est pas choisie.

     Si le proxy choisit de récursiver sur un contact quelconque d'une réponse 3xx en l'ajoutant à l'ensemble des cibles, il DOIT le supprimer de la réponse avant d'ajouter la réponse au contexte de réponse. Cependant, un proxy NE DEVRAIT PAS récursiver vers une URI non SIPS si le Request-URI de la requête d'origine était une URI SIPS. Si le proxy récurse sur tous les contacts d'une réponse 3xx, il NE DEVRAIT PAS ajouter la réponse sans contact résultante au contexte de réponse.

     Supprimer le contact avant d'ajouter la réponse au contexte de réponse empêche l'élément en amont suivant de réessayer un emplacement déjà tenté par ce proxy.

     Les réponses 3xx peuvent contenir un mélange d'URI SIP, SIPS et non SIP. Un proxy peut choisir de récursiver sur les URI SIP et SIPS et de placer le reste dans le contexte de réponse pour être renvoyé, éventuellement dans la réponse finale.

     Si un proxy reçoit une réponse 416 (Unsupported URI Scheme) à une requête dont le schéma du Request-URI n'était pas SIP, mais que le schéma de la requête reçue à l'origine était SIP ou SIPS (c'est-à-dire que le proxy a changé le schéma de SIP ou SIPS vers autre chose en proxifiant la requête), le proxy DEVRAIT ajouter une nouvelle URI à l'ensemble des cibles. Cette URI DEVRAIT être une version SIP URI de l'URI non SIP qui vient d'être essayée. Dans le cas de l'URL tel, cela s'obtient en plaçant la partie telephone-subscriber de l'URL tel dans la partie user de la SIP URI, et en fixant le hostpart au domaine où la requête précédente a été envoyée. Voir la section 19.1.6 pour plus de détails sur la formation de SIP URI à partir d'URL tel.

     Comme pour une réponse 3xx, si un proxy « récurse » sur le 416 en essayant une URI SIP ou SIPS à la place, la réponse 416 NE DEVRAIT PAS être ajoutée au contexte de réponse.

  5. Vérifier la réponse pour le transfert (Check response for forwarding)

     Jusqu'à ce qu'une réponse finale soit envoyée sur la transaction serveur, les réponses suivantes DOIVENT être transférées immédiatement :

     - Toute réponse provisoire autre que 100 (Trying)

     - Toute réponse 2xx

     Si une réponse 6xx est reçue, elle n'est pas transférée immédiatement, mais le proxy avec état DEVRAIT annuler toutes les transactions client en attente comme décrit à la section 10, et il NE DOIT PAS créer de nouvelles branches dans ce contexte.

     C'est un changement par rapport à la RFC 2543, qui imposait au proxy de transférer immédiatement la réponse 6xx. Pour une transaction INVITE, cette approche avait le problème qu'une réponse 2xx pouvait arriver sur une autre branche, auquel cas le proxy devrait transférer le 2xx. Le résultat était que le UAC pouvait recevoir une réponse 6xx suivie d'une réponse 2xx, ce qui ne devrait jamais être autorisé. Selon les nouvelles règles, à la réception d'un 6xx, un proxy émet une requête CANCEL, ce qui entraîne généralement des réponses 487 de toutes les transactions client en cours, puis le 6xx est transféré en amont.

     Après qu'une réponse finale a été envoyée sur la transaction serveur, les réponses suivantes DOIVENT être transférées immédiatement :

     - Toute réponse 2xx à une requête INVITE

     Un proxy avec état NE DOIT PAS transférer immédiatement toute autre réponse. En particulier, un proxy avec état NE DOIT PAS transférer une réponse 100 (Trying). Les réponses candidates à un transfert ultérieur comme « meilleure » réponse ont été collectées comme décrit à l'étape « Ajouter la réponse au contexte ».

     Toute réponse choisie pour un transfert immédiat DOIT être traitée comme décrit aux étapes « Agréger les valeurs de champ Authorization » jusqu'à « Record-Route ».

     Cette étape, combinée à la suivante, garantit qu'un proxy avec état transférera exactement une réponse finale à une requête non INVITE, et soit exactement une réponse non 2xx, soit une ou plusieurs réponses 2xx à une requête INVITE.

  6. Choisir la meilleure réponse (Choosing the best response)

     Un proxy avec état DOIT envoyer une réponse finale au contexte de réponse de la transaction serveur si aucune réponse finale n'a été transférée immédiatement par les règles ci-dessus et que toutes les transactions client de ce contexte ont été terminées.

     Le proxy avec état DOIT choisir la meilleure réponse finale parmi celles reçues et stockées dans le contexte de réponse.

     S'il n'y a aucune réponse finale dans le contexte, le proxy DOIT envoyer une réponse 408 (Request Timeout) à la transaction serveur.

     Sinon, le proxy DOIT transférer une réponse parmi les réponses stockées dans le contexte de réponse. Il DOIT choisir parmi les réponses de classe 6xx si elles existent dans le contexte. S'il n'y a pas de réponse de classe 6xx, le proxy DEVRAIT choisir parmi la classe de réponse la plus basse stockée dans le contexte de réponse. Le proxy PEUT sélectionner n'importe quelle réponse dans cette classe choisie. Le proxy DEVRAIT donner la préférence aux réponses fournissant des informations affectant le renvoi de cette requête, telles que 401, 407, 415, 420 et 484 si la classe 4xx est choisie.

     Un proxy qui reçoit une réponse 503 (Service Unavailable) NE DEVRAIT PAS la transférer en amont à moins qu'il ne puisse déterminer que toute requête ultérieure qu'il pourrait proxifier générera également un 503. En d'autres termes, transférer un 503 signifie que le proxy sait qu'il ne peut servir aucune requête, pas seulement celle du Request-URI ayant généré le 503. Si la seule réponse reçue est un 503, le proxy DEVRAIT générer une réponse 500 et la transférer en amont.

     La réponse transférée DOIT être traitée comme décrit aux étapes « Agréger les valeurs de champ Authorization » jusqu'à « Record-Route ».

     Par exemple, si un proxy transfère une requête vers 4 emplacements et reçoit les réponses 503, 407, 501 et 404, il peut choisir de transférer la réponse 407 (Proxy Authentication Required).

     Les réponses 1xx et 2xx peuvent intervenir dans l'établissement de dialogues. Lorsqu'une requête ne contient pas de tag To, le tag To de la réponse est utilisé par le UAC pour distinguer plusieurs réponses à une requête créant un dialogue. Un proxy NE DOIT PAS insérer un tag dans le champ To d'une réponse 1xx ou 2xx si la requête n'en contenait pas. Un proxy NE DOIT PAS modifier le tag dans le champ To d'une réponse 1xx ou 2xx.

     Comme un proxy ne peut insérer un tag dans le champ To d'une réponse 1xx à une requête n'en contenant pas, il ne peut pas émettre de réponses provisoires non 100 de lui-même. Cependant, il peut brancher la requête vers un UAS partageant le même élément que le proxy. Ce UAS peut renvoyer ses propres réponses provisoires, entrant dans un dialogue précoce avec l'initiateur de la requête. Le UAS n'a pas à être un processus distinct du proxy. Il pourrait être un UAS virtuel implémenté dans le même espace de code que le proxy.

     Les réponses 3-6xx sont livrées saut par saut. En émettant une réponse 3-6xx, l'élément agit effectivement comme un UAS, émettant sa propre réponse, généralement basée sur les réponses reçues des éléments en aval. Un élément DEVRAIT préserver le tag To lorsqu'il transfère simplement une réponse 3-6xx à une requête ne contenant pas de tag To.

     Un proxy NE DOIT PAS modifier le tag To dans toute réponse transférée à une requête contenant un tag To.

     Bien que cela ne fasse aucune différence pour les éléments en amont si le proxy remplace le tag To dans une réponse 3-6xx transférée, conserver le tag d'origine peut aider au débogage.

     Lorsque le proxy agrège des informations de plusieurs réponses, choisir un tag To parmi elles est arbitraire, et générer un nouveau tag To peut faciliter le débogage. Cela se produit, par exemple, en combinant les défis 401 (Unauthorized) et 407 (Proxy Authentication Required), ou en combinant des valeurs Contact de réponses 3xx non chiffrées et non authentifiées.

  7. Agréger les valeurs de champ Authorization (Aggregate Authorization Header Field Values)

     Si la réponse sélectionnée est une 401 (Unauthorized) ou 407 (Proxy Authentication Required), le proxy DOIT collecter toutes les valeurs de champ WWW-Authenticate et Proxy-Authenticate des autres réponses 401 et 407 reçues jusqu'à présent dans ce contexte de réponse et les ajouter à cette réponse sans modification avant le transfert. La réponse 401 ou 407 résultante pourrait avoir plusieurs valeurs de champ WWW-Authenticate ET Proxy-Authenticate.

     Cela est nécessaire car l'une ou toutes les destinations vers lesquelles la requête a été transférée peuvent avoir demandé des informations d'identification. Le client doit recevoir tous ces défis et fournir les identifiants pour chacun lorsqu'il renvoie la requête. La motivation de ce comportement est fournie à la section 26.

  8. Record-Route

     Si la réponse sélectionnée contient une valeur de champ Record-Route initialement fournie par ce proxy, le proxy PEUT choisir de réécrire la valeur avant de transférer la réponse. Cela permet au proxy de fournir des URI différents pour lui-même aux éléments en amont et en aval suivants. Un proxy peut choisir d'utiliser ce mécanisme pour n'importe quelle raison. Par exemple, c'est utile pour les hôtes multihédias.

     Si le proxy a reçu la requête via TLS et l'a envoyée via une connexion non TLS, le proxy DOIT réécrire l'URI dans le champ Record-Route en une SIPS URI. Si le proxy a reçu la requête via une connexion non TLS et l'a envoyée via TLS, le proxy DOIT réécrire l'URI dans le champ Record-Route en une SIP URI.

     La nouvelle URI fournie par le proxy DOIT satisfaire les mêmes contraintes sur les URI placées dans les champs Record-Route des requêtes (voir étape 4 de la section 16.6) avec les modifications suivantes :

     L'URI NE DEVRAIT PAS contenir le paramètre transport à moins que le proxy ne sache que l'élément en amont suivant (par opposition à l'aval) qui sera sur le chemin des requêtes ultérieures prend en charge ce transport.

     Lorsqu'un proxy décide de modifier le champ Record-Route dans la réponse, l'une des opérations qu'il effectue est de localiser la valeur Record-Route qu'il a insérée. Si la requête a spiralé et que le proxy a inséré une valeur Record-Route à chaque itération de la spirale, localiser la bonne valeur dans la réponse (qui doit être la bonne itération dans le sens inverse) est délicat. Les règles ci-dessus recommandent qu'un proxy souhaitant réécrire les valeurs Record-Route insère des URI suffisamment distinctes dans le champ Record-Route afin que la bonne puisse être sélectionnée pour la réécriture. Un mécanisme recommandé pour cela est que le proxy ajoute un identifiant unique de l'instance de proxy à la partie user de l'URI.

     Lorsque la réponse arrive, le proxy modifie le premier Record-Route dont l'identifiant correspond à l'instance de proxy. La modification aboutit à une URI sans cette donnée ajoutée à la partie user de l'URI. À l'itération suivante, le même algorithme (trouver la valeur Record-Route la plus haute avec le paramètre) extraira correctement la valeur Record-Route suivante insérée par ce proxy.

     Toutes les réponses à une requête à laquelle un proxy ajoute une valeur Record-Route ne contiendront pas nécessairement un champ Record-Route. Si la réponse contient un champ Record-Route, il contiendra la valeur ajoutée par le proxy.

  9. Transférer la réponse (Forward response)

     Après avoir effectué le traitement décrit aux étapes « Agréger les valeurs de champ Authorization » jusqu'à « Record-Route », le proxy PEUT effectuer toute manipulation spécifique à une fonctionnalité sur la réponse sélectionnée. Le proxy NE DOIT PAS ajouter, modifier ou supprimer le corps du message. Sauf indication contraire, le proxy NE DOIT PAS supprimer d'autres valeurs de champ d'en-tête que la valeur Via discutée à l'article 3 de la section 16.7. En particulier, le proxy NE DOIT PAS supprimer un paramètre « received » qu'il aurait pu ajouter à la valeur Via suivante lors du traitement de la requête associée à cette réponse. Le proxy DOIT passer la réponse à la transaction serveur associée au contexte de réponse. Cela entraînera l'envoi de la réponse vers l'emplacement maintenant indiqué dans la valeur Via la plus haute. Si la transaction serveur n'est plus disponible pour gérer la transmission, l'élément DOIT transférer la réponse sans état en l'envoyant au transport serveur. La transaction serveur peut indiquer un échec d'envoi ou signaler un timeout dans sa machine à états. Ces erreurs seraient journalisées à des fins de diagnostic, mais le protocole n'exige aucune action corrective du proxy.

     Le proxy DOIT maintenir le contexte de réponse jusqu'à ce que toutes ses transactions associées aient été terminées, même après avoir transféré une réponse finale.

  10. Générer des CANCEL (Generate CANCELs)

      Si la réponse transférée était une réponse finale, le proxy DOIT générer une requête CANCEL pour toutes les transactions client en attente associées à ce contexte de réponse. Un proxy DEVRAIT également générer une requête CANCEL pour toutes les transactions client en attente associées à ce contexte de réponse lorsqu'il reçoit une réponse 6xx. Une transaction client en attente est celle qui a reçu une réponse provisoire mais pas de réponse finale (elle est dans l'état proceeding) et pour laquelle aucun CANCEL associé n'a été généré. La génération de requêtes CANCEL est décrite à la section 9.1.

      L'exigence d'annuler les transactions client en attente lors du transfert d'une réponse finale ne garantit pas qu'un point de terminaison ne recevra pas plusieurs réponses 200 (OK) à un INVITE. Des réponses 200 (OK) sur plusieurs branches peuvent être générées avant que les requêtes CANCEL ne puissent être envoyées et traitées. De plus, il est raisonnable de s'attendre à ce qu'une extension future remplace cette exigence d'émission de CANCEL.

16.8 Traitement du minuteur C (Processing Timer C)​

Si le minuteur C se déclenche, le proxy DOIT soit le réinitialiser avec la valeur de son choix, soit terminer la transaction client. Si la transaction client a reçu une réponse provisoire, le proxy DOIT générer une requête CANCEL correspondant à cette transaction. Si la transaction client n'a pas reçu de réponse provisoire, le proxy DOIT se comporter comme si la transaction avait reçu une réponse 408 (Request Timeout).

Permettre au proxy de réinitialiser le minuteur lui permet d'étendre dynamiquement la durée de vie de la transaction en fonction des conditions actuelles (telles que l'utilisation) lors du déclenchement.

16.9 Gestion des erreurs de transport (Handling Transport Errors)​

Si la couche transport notifie à un proxy une erreur lorsqu'il tente de transférer une requête (voir section 18.4), le proxy DOIT se comporter comme si la requête transférée avait reçu une réponse 503 (Service Unavailable).

Si le proxy est notifié d'une erreur lors du transfert d'une réponse, il abandonne la réponse. Le proxy NE DEVRAIT PAS annuler les transactions client en attente associées à ce contexte de réponse à cause de cette notification.

  Si un proxy annule ses transactions client en attente, un seul client malveillant ou défectueux peut faire échouer toutes les transactions via son champ Via.

16.10 Traitement de CANCEL (CANCEL Processing)​

Un proxy avec état PEUT générer un CANCEL vers toute autre requête qu'il a générée à tout moment (sous réserve de recevoir une réponse provisoire à cette requête comme décrit à la section 9.1). Un proxy DOIT annuler toute transaction client en attente associée à un contexte de réponse lorsqu'il reçoit une requête CANCEL correspondante.

Un proxy avec état PEUT générer des requêtes CANCEL pour les transactions client INVITE en attente en fonction de l'expiration du champ Expires de l'INVITE. Cependant, cela est généralement inutile puisque les points de terminaison concernés s'occuperont de signaler la fin de la transaction.

Bien qu'une requête CANCEL soit traitée dans un proxy avec état par sa propre transaction serveur, aucun nouveau contexte de réponse n'est créé pour elle. Au lieu de cela, la couche proxy recherche dans ses contextes de réponse existants la transaction serveur gérant la requête associée à ce CANCEL. Si un contexte de réponse correspondant est trouvé, l'élément DOIT immédiatement renvoyer une réponse 200 (OK) à la requête CANCEL. Dans ce cas, l'élément agit comme un serveur d'agent utilisateur défini à la section 8.2. En outre, l'élément DOIT générer des requêtes CANCEL pour toutes les transactions client en attente du contexte comme décrit à l'étape 10 de la section 16.7.

Si aucun contexte de réponse n'est trouvé, l'élément ne possède aucune connaissance de la requête à laquelle appliquer le CANCEL. Il DOIT transférer la requête CANCEL sans état (il a peut-être transféré la requête associée sans état précédemment).

16.11 Proxy sans état (Stateless Proxy)​

Lorsqu'il agit sans état, un proxy est un simple transmetteur de messages. Une grande partie du traitement effectué sans état est identique à celui effectué avec état. Les différences sont détaillées ici.

Un proxy sans état n'a aucune notion de transaction, ni du contexte de réponse utilisé pour décrire le comportement du proxy avec état. Au lieu de cela, le proxy sans état prend les messages, requêtes et réponses, directement de la couche transport (voir section 18). Par conséquent, les proxies sans état ne retransmettent pas de messages de leur propre chef. Ils transfèrent cependant toutes les retransmissions reçues (ils ne peuvent pas distinguer une retransmission du message d'origine). De plus, lors du traitement d'une requête sans état, un élément NE DOIT PAS générer sa propre réponse 100 (Trying) ou toute autre réponse provisoire.

Un proxy sans état DOIT valider une requête comme décrit à la section 16.3.

Un proxy sans état DOIT suivre les étapes de traitement de requête des sections 16.4 à 16.5 avec l'exception suivante :

  o Un proxy sans état DOIT choisir une et une seule cible parmi l'ensemble des cibles. Ce choix NE DOIT reposer que sur des champs du message et des propriétés invariantes dans le temps du serveur. En particulier, une requête retransmise DOIT être transférée vers la même destination à chaque traitement. De plus, les requêtes CANCEL et ACK non routées DOIVENT générer le même choix que leur INVITE associée.

Un proxy sans état DOIT suivre les étapes de traitement de requête de la section 16.6 avec les exceptions suivantes :

  o L'exigence d'identifiants branch uniques dans l'espace et le temps s'applique également aux proxies sans état. Cependant, un proxy sans état ne peut pas simplement utiliser un générateur de nombres aléatoires pour calculer la première composante de l'identifiant branch, comme décrit à l'étape 8 de la section 16.6. Cela est dû au fait que les retransmissions d'une requête doivent avoir la même valeur, et un proxy sans état ne peut pas distinguer une retransmission de la requête d'origine. Par conséquent, la composante du paramètre branch qui le rend unique DOIT être la même à chaque transfert d'une requête retransmise. Ainsi, pour un proxy sans état, le paramètre branch DOIT être calculé comme une fonction combinatoire de paramètres de message invariants par retransmission.

     Le proxy sans état PEUT utiliser toute technique qu'il souhaite pour garantir l'unicité de ses identifiants branch entre les transactions. Cependant, la procédure suivante est recommandée. Le proxy examine l'identifiant branch dans le champ Via le plus haut de la requête reçue. S'il commence par le magic cookie, la première composante de l'identifiant branch de la requête sortante est calculée comme un hachage de l'identifiant branch reçu. Sinon, la première composante est calculée comme un hachage du Via le plus haut, du tag dans le champ To, du tag dans le champ From, du champ Call-ID, du numéro CSeq (mais pas de la méthode) et du Request-URI de la requête reçue. L'un de ces champs variera toujours entre deux transactions différentes.

  o Toutes les autres transformations de message spécifiées à la section 16.6 DOIVENT entraîner la même transformation d'une requête retransmise. En particulier, si le proxy insère une valeur Record-Route ou pousse des URI dans le champ Route, il DOIT placer les mêmes valeurs dans les retransmissions de la requête. Comme pour le paramètre Via branch, cela implique que les transformations DOIVENT être basées sur une configuration invariante dans le temps ou des propriétés invariantes par retransmission de la requête.

  o Un proxy sans état détermine où transférer la requête comme décrit pour les proxies avec état à l'article 10 de la section 16.6. La requête est envoyée directement à la couche transport au lieu de passer par une transaction client.

     Comme un proxy sans état doit transférer les requêtes retransmises vers la même destination et ajouter des paramètres branch identiques à chacune, il ne peut utiliser que des informations du message lui-même et des données de configuration invariantes dans le temps pour ces calculs. Si l'état de configuration n'est pas invariant dans le temps (par exemple si une table de routage est mise à jour), les requêtes susceptibles d'être affectées par le changement peuvent ne pas être transférées sans état pendant un intervalle égal à la fenêtre de timeout de transaction avant ou après le changement. La méthode de traitement des requêtes concernées pendant cet intervalle est une décision d'implémentation. Une solution courante est de les transférer avec état de transaction.

Les proxies sans état NE DOIVENT PAS effectuer de traitement spécial pour les requêtes CANCEL. Elles sont traitées par les règles ci-dessus comme toute autre requête. En particulier, un proxy sans état applique le même traitement de champ Route aux requêtes CANCEL qu'à toute autre requête.

Le traitement des réponses décrit à la section 16.7 ne s'applique pas à un proxy agissant sans état. Lorsqu'une réponse arrive à un proxy sans état, le proxy DOIT inspecter la valeur sent-by dans la première (la plus haute) valeur du champ Via. Si cette adresse correspond au proxy (elle est égale à une valeur que ce proxy a insérée dans des requêtes précédentes), le proxy DOIT supprimer cette valeur du champ de la réponse et transférer le résultat vers l'emplacement indiqué dans la valeur Via suivante. Le proxy NE DOIT PAS ajouter, modifier ou supprimer le corps du message. Sauf indication contraire, le proxy NE DOIT PAS supprimer d'autres valeurs de champ d'en-tête. Si l'adresse ne correspond pas au proxy, le message DOIT être ignoré silencieusement.

16.12 Résumé du traitement de routage du proxy (Summary of Proxy Route Processing)​

En l'absence de politique locale contraire, le traitement qu'un proxy effectue sur une requête contenant un champ d'en-tête Route peut être résumé dans les étapes suivantes.

  1. Le proxy inspectera le Request-URI. S'il indique une ressource appartenant à ce proxy, le proxy le remplacera par les résultats de l'exécution d'un service de localisation. Sinon, le proxy ne modifiera pas le Request-URI.

2. Le proxy inspectera l'URI dans la première valeur du champ Route. Si elle indique ce proxy, le proxy la supprime du champ Route (ce nœud de routage a été atteint).

3. Le proxy transférera la requête vers la ressource indiquée par l'URI dans la première valeur du champ Route ou dans le Request-URI s'il n'y a pas de champ Route. Le proxy détermine l'adresse, le port et le transport à utiliser lors du transfert de la requête en appliquant les procédures de [4] à cette URI.

Si aucun élément strict-routing n'est rencontré sur le chemin de la requête, le Request-URI indiquera toujours la cible de la requête.

16.12.1 Exemples (Examples)​

16.12.1.1 Trapèze SIP de base (Basic SIP Trapezoid)​

Ce scénario est le trapèze SIP de base, U1 -> P1 -> P2 -> U2, les deux proxies effectuant un record-routing. Voici le flux.

U1 envoie :

  INVITE sip:[email protected] SIP/2.0
Contact: sip:[email protected]

à P1. P1 est un proxy de sortie. P1 n'est pas responsable de domain.com, il le recherche donc dans le DNS et l'envoie là. Il ajoute également une valeur Record-Route :

  INVITE sip:[email protected] SIP/2.0
Contact: sip:[email protected]
      Record-Route: `<sip:p1.example.com;lr>`

P2 reçoit cela. Il est responsable de domain.com, il exécute donc un service de localisation et réécrit le Request-URI. Il ajoute également une valeur Record-Route. Il n'y a pas de champ Route, il résout donc le nouveau Request-URI pour déterminer où envoyer la requête :

  INVITE sip:[email protected] SIP/2.0
Contact: sip:[email protected]
Record-Route: `<sip:p2.domain.com;lr>`
Record-Route: `<sip:p1.example.com;lr>`

L'appelé sur u2.domain.com reçoit cela et répond avec un 200 OK :

  SIP/2.0 200 OK
Contact: sip:[email protected]
Record-Route: `<sip:p2.domain.com;lr>`
Record-Route: `<sip:p1.example.com;lr>`

L'appelé sur u2 définit également l'URI cible distante de son état de dialogue à sip:[email protected] et son ensemble de routage à :

  (`<sip:p2.domain.com;lr>`,`<sip:p1.example.com;lr>`)

Cela est transféré par P2 vers P1 vers U1 normalement. Maintenant, U1 définit l'URI cible distante de son état de dialogue à sip:[email protected] et son ensemble de routage à :

  (`<sip:p1.example.com;lr>`,`<sip:p2.domain.com;lr>`)

Comme tous les éléments de l'ensemble de routage contiennent le paramètre lr, U1 construit la requête BYE suivante :

  BYE sip:[email protected] SIP/2.0
Route: `<sip:p1.example.com;lr>`,`<sip:p2.domain.com;lr>`

Comme tout autre élément (y compris les proxies), il résout l'URI dans la première valeur du champ Route via le DNS pour déterminer où envoyer la requête. Cela va à P1. P1 remarque qu'il n'est pas responsable de la ressource indiquée dans le Request-URI, il ne le modifie donc pas. Il voit qu'il est la première valeur dans le champ Route, il la supprime donc et transfère la requête à P2 :

  BYE sip:[email protected] SIP/2.0
Route: `<sip:p2.domain.com;lr>`

P2 remarque également qu'il n'est pas responsable de la ressource indiquée par le Request-URI (il est responsable de domain.com, pas de u2.domain.com), il ne le modifie donc pas. Il se voit dans la première valeur du champ Route, il la supprime donc et transfère ce qui suit à u2.domain.com basé sur une recherche DNS du Request-URI :

  BYE sip:[email protected] SIP/2.0

16.12.1.2 Traversée d'un proxy strict-routing (Traversing a Strict-Routing Proxy)​

Dans ce scénario, un dialogue est établi à travers quatre proxies, chacun ajoutant des valeurs Record-Route. Le troisième proxy implémente les procédures strict-routing spécifiées dans la RFC 2543 et de nombreux documents de travail.

  U1->P1->P2->P3->P4->U2

L'INVITE arrivant à U2 contient :

  INVITE sip:[email protected] SIP/2.0
Contact: sip:[email protected]
Record-Route: `<sip:p4.domain.com;lr>`
Record-Route: `<sip:p3.middle.com>`
Record-Route: `<sip:p2.example.com;lr>`
Record-Route: `<sip:p1.example.com;lr>`

Ce à quoi U2 répond avec un 200 OK. Plus tard, U2 envoie la requête BYE suivante à P4 basée sur la première valeur du champ Route.

  BYE sip:[email protected] SIP/2.0
Route: `<sip:p4.domain.com;lr>`
Route: `<sip:p3.middle.com>`
Route: `<sip:p2.example.com;lr>`
Route: `<sip:p1.example.com;lr>`

P4 n'est pas responsable de la ressource indiquée dans le Request-URI, il la laisse donc tranquille. Il remarque qu'il est l'élément dans la première valeur du champ Route, il la supprime donc. Il prépare alors l'envoi de la requête basée sur la valeur Route désormais première sip:p3.middle.com, mais remarque que cette URI ne contient pas le paramètre lr, il reformate donc la requête avant l'envoi :

  BYE sip:p3.middle.com SIP/2.0
Route: `<sip:p2.example.com;lr>`
Route: `<sip:p1.example.com;lr>`
Route: `<sip:[email protected]>`

P3 est un strict router, il transfère donc ce qui suit à P2 :

  BYE sip:p2.example.com;lr SIP/2.0
Route: `<sip:p1.example.com;lr>`
Route: `<sip:[email protected]>`

P2 voit que le request-URI est une valeur qu'il a placée dans un champ Record-Route, il réécrit donc la requête avant un traitement supplémentaire :

  BYE sip:[email protected] SIP/2.0
Route: `<sip:p1.example.com;lr>`

P2 n'est pas responsable de u1.example.com, il envoie donc la requête à P1 basé sur la résolution de la valeur du champ Route.

P1 remarque sa présence dans la valeur Route la plus haute, il la supprime donc, ce qui donne :

  BYE sip:[email protected] SIP/2.0

Comme P1 n'est pas responsable de u1.example.com et qu'il n'y a pas de champ Route, P1 transférera la requête vers u1.example.com basé sur le Request-URI.

16.12.1.3 Réécriture des valeurs de champ Record-Route (Rewriting Record-Route Header Field Values)​

Dans ce scénario, U1 et U2 sont dans des espaces de noms privés différents et entrent dans un dialogue via un proxy P1, qui agit comme passerelle entre les espaces de noms.

  U1->P1->U2

U1 envoie :

  INVITE sip:[email protected] SIP/2.0
Contact: `<sip:[email protected]>`

P1 utilise son service de localisation et envoie ce qui suit à U2 :

  INVITE sip:[email protected] SIP/2.0
Contact: `<sip:[email protected]>`
Record-Route: `<sip:gateway.rightprivatespace.com;lr>`

U2 renvoie ce 200 (OK) à P1 :

  SIP/2.0 200 OK
Contact: `<sip:[email protected]>`
Record-Route: `<sip:gateway.rightprivatespace.com;lr>`

P1 réécrit son paramètre Record-Route pour fournir une valeur utile à U1, et envoie ce qui suit à U1 :

  SIP/2.0 200 OK
Contact: `<sip:[email protected]>`
Record-Route: `<sip:gateway.leftprivatespace.com;lr>`

Plus tard, U1 envoie la requête BYE suivante à P1 :

  BYE sip:[email protected] SIP/2.0
Route: `<sip:gateway.leftprivatespace.com;lr>`

que P1 transfère à U2 sous la forme :

  BYE sip:[email protected] SIP/2.0