2. Caractères (Characters)
Ce chapitre définit les jeux de caractères, les mécanismes d'encodage et les règles de traitement utilisés dans les URI.
Fondamentaux de l'encodage des caractères
La syntaxe URI fournit une méthode pour encoder des données dans une séquence de caractères, probablement dans le but d'identifier une ressource.
Hiérarchie d'encodage:
Ressource → Caractères URI → Octets → Transmission/Stockage
Jeu de caractères: Les URI sont basés sur le jeu de caractères US-ASCII, composé de chiffres, de lettres et de quelques symboles graphiques
2.1. Encodage en pourcentage (Percent-Encoding)
Objectif
Un mécanisme d'encodage en pourcentage est utilisé pour représenter un octet de données dans un composant lorsque le caractère correspondant à cet octet est en dehors de l'ensemble autorisé ou est utilisé comme délimiteur.
Format d'encodage
pct-encoded = "%" HEXDIG HEXDIG
Format: Un encodage en pourcentage consiste en un caractère pourcent "%" suivi de deux chiffres hexadécimaux représentant la valeur numérique de cet octet
Exemples
| Caractère | Binaire | Hexadécimal | Encodage en pourcentage |
|---|---|---|---|
| Espace | 00100000 | 0x20 | %20 |
| ! | 00100001 | 0x21 | %21 |
| # | 00100011 | 0x23 | %23 |
| é (français) | - | 0xC3A9 | %C3%A9 |
Règles de casse
Équivalence: Les chiffres hexadécimaux majuscules 'A' à 'F' sont équivalents aux chiffres minuscules 'a' à 'f'
Normalisation: Deux URI qui ne diffèrent que par la casse des chiffres hexadécimaux utilisés dans les octets encodés en pourcentage sont équivalents
Recommandation: Les producteurs et normalisateurs d'URI devraient (SHOULD) utiliser des chiffres hexadécimaux majuscules pour tous les encodages en pourcentage
Recommandé: %2F %3A %5B
Non recommandé: %2f %3a %5b
2.2. Caractères réservés (Reserved Characters)
Définition
Les URI incluent des composants et sous-composants délimités par des caractères de l'ensemble "réservé". Ces caractères sont appelés "réservés" car ils peuvent (ou ne peuvent pas) être définis comme délimiteurs.
Ensemble de caractères réservés
reserved = gen-delims / sub-delims
gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
/ "*" / "+" / "," / ";" / "="
Classification
Délimiteurs généraux (gen-delims)
| Caractère | Objectif | Exemple |
|---|---|---|
| : | Sépare le schéma et l'autorité | http: |
| / | Séparateur de chemin | /path/to/resource |
| ? | Séparateur de requête | ?key=value |
| # | Séparateur de fragment | #section |
| [ ] | Limites d'adresse IPv6 | [2001:db8::1] |
| @ | Séparateur d'informations utilisateur | user@host |
Sous-délimiteurs (sub-delims)
| Caractère | Utilisation courante |
|---|---|
| ! $ ' ( ) * | Séparation de sous-composants dans le chemin ou la requête |
| + | Représentation alternative de l'espace |
| , | Séparateur de liste |
| ; | Séparateur de paramètre |
| = | Séparateur clé-valeur |
| & | Séparateur de paramètre de requête |
Règles d'encodage
Gestion des conflits: Si les données d'un composant URI entrent en conflit avec l'objectif d'un caractère réservé en tant que délimiteur, alors les données en conflit doivent (MUST) être encodées en pourcentage avant la formation de l'URI
Exemples:
Chemin contenant le caractère "?":
Original: /path/file?.txt
Encodé: /path/file%3F.txt
Requête contenant le caractère "&":
Original: ?name=Tom&Jerry
Correct: ?name=Tom%26Jerry (si & n'est pas un délimiteur)
Ou: ?name=Tom&name=Jerry (si & est un délimiteur)
Équivalence
Important: Les URI qui diffèrent dans le remplacement d'un caractère réservé par son octet encodé en pourcentage correspondant ne sont PAS équivalents
http://example.com/path?key=value
http://example.com/path%3Fkey=value
Ces deux URI ne sont PAS équivalents
2.3. Caractères non réservés (Unreserved Characters)
Définition
Les caractères autorisés dans un URI mais n'ayant pas d'objectif réservé sont appelés non réservés.
Ensemble de caractères non réservés
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
Comprend:
- ALPHA: Lettres majuscules et minuscules (A-Z, a-z)
- DIGIT: Chiffres décimaux (0-9)
- -: Tiret
- .: Point
- _: Trait de soulignement
- ~: Tilde
Règles d'encodage
Équivalence: Les URI qui diffèrent dans le remplacement d'un caractère non réservé par son octet US-ASCII encodé en pourcentage correspondant sont équivalents
Normalisation: Les octets encodés en pourcentage correspondant à des caractères non réservés devraient (SHOULD) être décodés
URI équivalents:
http://example.com/~user
http://example.com/%7Euser
Normalisé en:
http://example.com/~user
Plage d'encodage en pourcentage
Ne devrait PAS être créé (SHOULD NOT):
- ALPHA:
%41-%5A(A-Z),%61-%7A(a-z) - DIGIT:
%30-%39(0-9) - Tiret:
%2D - Point:
%2E - Trait de soulignement:
%5F - Tilde:
%7E
Devrait être décodé: Lorsque ces encodages sont trouvés dans un URI, les normalisateurs devraient (SHOULD) les décoder en leurs caractères non réservés correspondants
2.4. Quand encoder ou décoder (When to Encode or Decode)
Quand encoder
Producteurs d'URI:
- Lors de la production de l'URI, doivent (MUST) encoder en pourcentage les caractères non autorisés
- Les caractères réservés ne sont laissés non encodés que lorsqu'ils sont utilisés comme délimiteurs
- Les caractères non réservés ne devraient pas (SHOULD NOT) être encodés
Exemples:
# Encodage du chemin
path = "/files/my document.pdf"
encoded = "/files/my%20document.pdf"
# Encodage de la requête
query = "?name=John Doe&age=30"
encoded = "?name=John%20Doe&age=30"
Quand décoder
Consommateurs d'URI:
- Après l'analyse de l'URI, décoder les composants selon les besoins
- Ne pas décoder prématurément (peut changer la structure de l'URI)
- Décoder chaque composant une seule fois
Exemple dangereux:
Original: /path%2Fto%2Ffile
Décodage prématuré: /path/to/file (structure du chemin modifiée!)
Correct: Analyser d'abord, puis décoder chaque segment
Segment 1: "path%2Fto%2Ffile" → Décoder → "path/to/file"
Problème de double encodage
Données originales: "100%"
Premier encodage: "100%25"
Deuxième encodage erroné: "100%2525"
Lors du décodage:
"100%2525" → "100%25" → "100%"
2.5. Identification des données (Identifying Data)
Jeux de caractères et encodage
Caractère vs Octet:
- Les URI sont des séquences de caractères
- Les caractères sont encodés en octets pour la transmission/le stockage
- UTF-8 est l'encodage de caractères recommandé
Identificateurs de ressources internationalisés (IRI)
Extension IRI: RFC 3987 définit les IRI, qui permettent l'utilisation de caractères Unicode
Conversion:
IRI: http://例え.jp/引き出し
↓ Encoder en UTF-8 et encoder en pourcentage
URI: http://xn--r8jz45g.jp/%E5%BC%95%E3%81%8D%E5%87%BA%E3%81%97
Meilleures pratiques
Production d'URI:
- Encoder les caractères non-ASCII en UTF-8
- Encoder en pourcentage les octets résultants
- Utiliser des chiffres hexadécimaux majuscules
- Ne pas encoder les caractères non réservés
Consommation d'URI:
- Analyser par composant
- Décoder les encodages en pourcentage
- Interpréter les octets en utilisant UTF-8
- Gérer les encodages invalides
Référence rapide des jeux de caractères
Classification complète des caractères
Caractères URI
├── Non réservés (unreserved)
│ ├── ALPHA: A-Z, a-z
│ ├── DIGIT: 0-9
│ └── Symboles: - . _ ~
│
├── Réservés (reserved)
│ ├── Délimiteurs généraux (gen-delims): : / ? # [ ] @
│ └── Sous-délimiteurs (sub-delims): ! $ & ' ( ) * + , ; =
│
└── Encodé en pourcentage (pct-encoded): %HEXDIG HEXDIG
Arbre de décision d'encodage
Le caractère doit apparaître dans l'URI?
├─ Est un caractère non réservé? → Utiliser directement
├─ Est un caractère réservé?
│ ├─ Utilisé comme délimiteur? → Utiliser directement
│ └─ Utilisé comme données? → Encoder en pourcentage
└─ Autre caractère? → Encoder en pourcentage
Table d'encodage des caractères courants
| Caractère | Objectif | Encodage |
|---|---|---|
| Espace | Séparation | %20 ou + (dans la requête) |
| ! | Sous-délimiteur | %21 (si encodage nécessaire) |
| " | Guillemet | %22 |
| # | Délimiteur de fragment | %23 (dans les données) |
| $ | Sous-délimiteur | %24 (si encodage nécessaire) |
| % | Marqueur d'encodage | %25 |
| & | Séparateur de paramètre | %26 (dans les données) |
| ' | Sous-délimiteur | %27 (si encodage nécessaire) |
| ( ) | Sous-délimiteur | %28 %29 |
| + | Espace/Sous-délimiteur | %2B (dans les données) |
| , | Séparateur de liste | %2C (si encodage nécessaire) |
| / | Séparateur de chemin | %2F (dans les données) |
| : | Séparateur de schéma | %3A (dans les données) |
| ; | Séparateur de paramètre | %3B (si encodage nécessaire) |
| = | Séparateur clé-valeur | %3D (si encodage nécessaire) |
| ? | Séparateur de requête | %3F (dans les données) |
| @ | Séparateur d'info utilisateur | %40 (dans les données) |
| [ ] | Limites IPv6 | %5B %5D |
Recommandations d'implémentation
Implémentation de l'encodage
def percent_encode(text, safe=''):
"""Encoder le texte en pourcentage"""
result = []
for char in text:
if char in safe or is_unreserved(char):
result.append(char)
else:
# Encoder en UTF-8 et encoder en pourcentage
for byte in char.encode('utf-8'):
result.append(f'%{byte:02X}')
return ''.join(result)
def is_unreserved(char):
"""Vérifier si le caractère est non réservé"""
return (char.isalnum() or
char in '-._~')
Implémentation du décodage
def percent_decode(text):
"""Décoder le texte en pourcentage"""
result = bytearray()
i = 0
while i < len(text):
if text[i] == '%' and i + 2 < len(text):
try:
byte = int(text[i+1:i+3], 16)
result.append(byte)
i += 3
except ValueError:
result.extend(text[i].encode('utf-8'))
i += 1
else:
result.extend(text[i].encode('utf-8'))
i += 1
return result.decode('utf-8', errors='replace')
Chapitre suivant: 3. Composants syntaxiques (Syntax Components) - Composants structurels des URI