Introduction à HTTP
Une petite présentation du protocole HTTP
- HTTP : Hyper Text Transfer Protocol
- Conçu pour le World Wide Web, à l'origine constitué de pages statiques liées entre-elles par des liens hypertextes
- Protocole concurrent : Gopher (1991)
-
Petit historique :
- 1991 : naissance de HTTP/0.9
- Mai 1996 : RFC 1945 définissant HTTP/1.0 par T. Berners-Lee, R. Fielding et H. Frystyk
- Janvier 1997 : \href{http://www.ietf.org/rfc/rfc2068.txt}{RFC2068} définissant HTTP/1.1
- Protocole transitionnel avant HTTP/2.0 : SPDY proposé par Google (sous-couche pour HTTP)
- Mai 2015 : HTTP/2.0 proposé par la RFC 7540
- Le client envoie une requête au serveur (port par défaut : 80 ou 443 en sécurisé) qui lui répond
- Le protocole est sans état : chaque requête est indépendante
- Possibilité d'utiliser des proxys intermédiaires avec cachage des ressources
Un protocole devenu fourre-tout
- Tendance : utilisation de HTTP comme protocole de transport avec (trop) d'applications possibles
- Protocole devenu universel et "passe-partout" (toléré par les pare-feux)
-
Quelques applications :
- Serveurs de ressources (documents, images...) : usage historique
- Systèmes de fichiers partagés (WebDAV), partage de calendrier (CalDAV), de carnets d'adresses (CardDAV)
- Tunnelisation de connexions TCP (méthode CONNECT)
- Appels distants de méthodes (SOAP)
- Interfaces web pour des services historiquement utilisés avec des protocoles propres (email, forum...)
- Applications web de bureau ou mobile (backend + HTML5 et JavaScript)
- ...
Méthodes HTTP
- OPTIONS : pour obtenir les capacités du serveur HTTP (nilpotente)
- GET : pour récupérer une ressource, méthode la plus employée (nilpotente)
- HEAD : pour obtenir les en-têtes d'une ressource, pas le corps (nilpotente)
- POST : pour envoyer des données vers une ressource
- PUT : pour enregistrer une ressource sur le serveur (idempotente)
- DELETE : pour supprimer une ressource du serveur (idempotente)
- TRACE : requête de diagnostic pour connaître le cheminement à travers les proxys (nilpotente)
- CONNECT : pour ouvrir un tunnel afin d'envoyer des données brutes
-
Nilpotence et idempotence}
- Nilpotence = pas d'effet de bord sur le serveur
- Idempotence = la réexécution d'une même requête n'a pas d'incidence
Requête vers le serveur HTTP
Contenu d'une requête
- 1ère ligne : METHODE /chemin/vers/la/ressource HTTP/v \r\n
- Lignes suivantes d'en-têtes avec paires de clé/valeur : clé: valeur \r\n
- Ligne vide de séparation en-tête/corps
- Corps (facultatif) de la requête
Envoi de données pour un web dynamique
- Envoi de formulaire (texte, fichiers) : par le chemin de ressource et/ou le corps
- Suivi de sessions malgré un protocole sans état : par un en-tête spécifique (cookie)
Réponse du serveur HTTP
HTTP/1.1 200 OK \r\n Server: monBeauServeur v3 \r\n Date: Thu, 09 Oct 2013 09:30:24 GMT \r\n ...autres en-têtes... Content-Type: text/html \r\n Content-Length: 2037 \r\n \r\n <html> ... </html>
Les codes de résultat
- 1xx : information, réponse intermédiaire du serveur (exemple : 100 continue, 101 switching protocols, 118 connection timedout)
- 2xx : succès de la requête (exemple : 200 OK)
- 3xx : redirection de ressource (exemples : 300 multiple choices, 301 moved permanently, 302 moved definitively)
- 4xx : erreur du client HTTP (exemples : 400 bad request, 403 forbidden, 404 not found)
- 5xx : erreur au niveau du serveur empêchant la satisfaction de la requête (exemples : 500 internal server error, 501 not implemented)
La méthode GET
Envoi de champs par méthode GET
-
Principe
- À envoyer : ensemble de paires clé/valeur
- Cet ensemble est spécifié dans la section query de l'URL
-
Syntaxe
- Format général d'URI hiérarchique : schema:autority/path?query\#fragment
- Format de query/ : cle1=valeur1\&cle2=valeur2\&...
- Les caractères spéciaux (autres que [A-Za-z0-9\$-\_.!*'()]) des clés et valeurs doivent être déspécialisés
- Déspécialisation : code ASCII hexadécimal préfixé par %
- L'espace peut être représenté par + ou %20
-
Exemples :
- http://www.bing.com/search?q=serveur+http&first=42 pour rechercher sur Bing serveur http (à partir de la 42ème réponse)
- http://www.google.fr/search?q=c%2B%2B pour rechercher c++ sur Google
Table ASCII
Déclencher l'envoi de champs par méthode GET sur le web
- Par lien hypertexte direct
- Par formulaire spécifié sur une page HTML et soumis par l'internaute
Exemple de formulaire HTML
<form action="http://www.bing.com/search" method="get" enctype="application/x-www-form-urlencoded"> <label>Mot-clé à chercher : <input type="text" name="q" /></label> <br /> <label>Rang de départ : <input type="number" name="first" /></label> <br /> <label><input type="submit" name="submission" value="submitted"></label> <br /> </form>
Implications de l'envoi de champs par méthode GET
- Les clés/valeurs sont intégrées dans l'URL de la ressource demandée GET ressource HTTP/ver; le protocole HTTP n'impose pas de limite pour la longueur des URLs. Cependant certains clients et serveurs HTTP limitent la taille des URLs. Il est conseillé de ne pas dépasser 2048 caractères.
- Conservation d'historiques d'URLs consultées par les clients et serveurs : implication sur la confidentialité des données
- Rejeu possible de requêtes par navigation dans l'historique du client
Dans quel cas utiliser la méthode GET pour l'envoi de champs ?
- Pour des opérations sans effet de bord sur le serveur (nilpotence)
- Pour communiquer des données de petite taille
- Pour des informations peu confidentielles
Les en-têtes HTTP
Les types MIME
- MIME = Multipurpose Internet Mail Extension défini par la RFC 2046
- Utilité : pour identifier la nature des contenus envoyés ou reçus (en-tête Content-Type)
- Registre de types MIME courants maintenu par l'IANA
- Format: type/sous-type; parametre=valeur (paramètre peut indiquer le charset)
-
Quelques types :
- application (application/octet-stream, application/json...)
- audio (audio/mpeg, audio/x-wav...)
- example
- image (image/png, image/jpeg...)
- message
- multipart
- text (text/html, text/plain; charset=UTF-8...)
- video (video/mpeg, video/mastroska...)
Quelques en-têtes
- Host : indique le nom d'hôte du serveur, indispensable en HTTP/1.1 pour supporter l'hébergement virtuel (requête)
- Date : date de la requête (requête/réponse)
- Last-Modified : date de dernière modification de la ressource (réponse)
- ETag : valeur de hachage du document (réponse)
- Content-Type : type MIME du document (requête/réponse)
- Content-Length : longueur du document (requête/réponse)
- Accept : formats acceptés par le client (requête)
- Authorization : pour s'authentifier suite à une erreur 401
- Pragma : pour indiquer une politique de cache (réponse)
- Referer : URL antécédante (requête)
- et bien d'autres qu'il serait fastidieux de tous citer (RTFRFC)
En-têtes pour requêtes conditionnelles
Utilisables avec les requêtes GET
- If-Modified-Since : on indique la date de dernière modification connue.
- If-None-Match : on spécifie le dernier ETag connu.
Le corps de la ressource est retourné ssi les conditions indiquées sont remplies (utile si l'on dispose d'une version précédente en cache et que l'on ne souhaite pas la retélécharger inutilement).
La méthode POST
Envoi de champs par méthode POST par encodage application/x-www-form-urlencoded
Les données suivent le même format que pour la méthode GET sauf qu'elles sont intégrées au corps de la requête et non à l'URL.
<form action="http://igm.univ-mlv.fr/~chilowi/sendmessage.php" method="post" enctype="application/x-www-form-urlencoded"> <label>Adresse e-mail de l'expéditeur : <input type="text" name="sender" /></label> <br /> <label>Message à envoyer : <textarea name="message" rows="5" cols="20">Message à écrire</textarea></label> <br /> <label><input type="submit" name="submission" value="submitted"></label> <br /> </form>
Exemple : requête créée par soumission du formulaire
POST /~chilowi/sendmessage.php HTTP/1.1 Host: igm.univ-mlv.fr User-Agent: Mozilla/5.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 DNT: 1 Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 198 sender=foo%40example.com&message=Le+protocole+HTTP+est+vraiment+tr%C3%A8s+int%C3%A9ressant.%0D%0ASurtout +lorsqu%27il+s%27agit+d%27envoyer+des+donn%C3%A9es+par+m%C3%A9thode+POST.&submission=submitted
Envoi de fichiers
Envoi de fichiers possible :
-
Par méthode PUT : possibilité d'envoyer un unique fichier par requête en spécifiant le chemin de placement sur le serveur
- Exemple : PUT /album1/landscape.jpg HTTP/1.1 pour envoyer un fichier vers le chemin spécifié ; on fournit le contenu du fichier dans le corps de la requête
-
L'envoi au sein d'un formulaire par la méthode POST : le contenu du fichier est intégré dans la valeur associée à une clé
- On n'utilise pas l'encodage application/x-www-form-urlencoded : déspécialisation des octets fastidieuse et coûteuse pour des fichiers binaires ou textes non-ASCII, pas de possibilité d'indiquer le type MIME du fichier envoyé ⇒ emploi de l'encodage multipart/form-data (\href{http://tools.ietf.org/html/rfc2388}{RFC 2388})
Envoi de champs par encodage multipart/form-data
- Encodage à privilégier pour l'envoi de champs par méthode POST.\
-
Les contenus des champs sont spécifiés dans le corps de la requête avec :
- Une chaîne de caractère boundary délimitant un champ (placée avant et après)
-
Un en-tête
- Content-Disposition: form-data; name="nomDuChamp" ou
- Content-Disposition: file; filename="nomDuFichier" (si fichier)
- Un en-tête (si fichier) Content-Type: mime/sous-mime
Exemple de formulaire et requête d'envoi de fichiers par encodage multipart/form-data
<FORM action="http://example.com/sendFiles" enctype="multipart/form-data" method="post"> Expéditeur : <INPUT type="text" name="sender"> <cr /> Fichiers à envoyer : <INPUT type="file" name="files"> <br /> <INPUT type="submit" value="Send"> <INPUT type="reset"> </FORM> \end{verbatim} \begin{verbatim} Content-Type: multipart/form-data; boundary=AaB03x --AaB03x Content-Disposition: form-data; name="sender" Mike --AaB03x Content-Disposition: form-data; name="files" Content-Type: multipart/mixed; boundary=BbC04y --BbC04y Content-Disposition: file; filename="file1.txt" Content-Type: text/plain ... contenu de file1.txt ... --BbC04y Content-Disposition: file; filename="file2.gif" Content-Type: image/gif Content-Transfer-Encoding: binary ...contenu de l'image file2.gif... --BbC04y-- --AaB03x--
Les sessions en HTTP
Suivi de session en HTTP
Principe :
- Le serveur attribue un identifiant aléatoire à un client lors de sa première requête
- Le serveur associe à cet identifiant des informations stockées
- On force le client à réenvoyer cet identifiant pour les requêtes suivantes
Comment forcer le client à réenvoyer l'identifiant de session ?
- En l'intégrant dans les liens hypertextes de la page HTML (champ envoyé par méthode GET) : http://www.example.com/shoppingCart?sessionid=37af3ee56785acd
- En l'intégrant dans un formulaire en tant que champ caché : <input type="hidden" name="sessionid" value="37af3ee56785acd">
- En utilisant un cookie (introduit par la RFC 2109)
- Mais pas en utilisant l'adresse IP du client : adresse IP dynamique, adresse IP publique partagée par NAT, adresse IP de relai...
Cookies
Un cookie est une paire clé/valeur stocké par le client et associé à un domaine de validité.
- Le serveur demande l'installation d'un cookie par l'en-tête Set-cookie d'une réponse.
- Le client stocke le cookie et l'associe au domaine.
- Lorsque le client réémet une requête vers un domaine, il réenvoit l'ensemble des cookies stockés pour ce domaine par l'en-tête Cookie dans la requête.
Attributs d'un cookie
- max-age : durée de vie du cookie (nulle pour effacer le cookie immédiatement, négative pour effacer le cookie à la fin de la session)
- domain : domaine de validité du cookie (exemples : www.univ-mlv.fr, .google.fr)
- path : préfixe de chemin de validité du cookie (/ pour une validité pour l'ensemble des chemins du serveur)
- secure : demande au client de ne renvoyer le cookie que sur une connexion sécurisée (bonne pratique pour les cookies authentificateurs)
- comment : commentaire à destination de l'utilisateur
Usage des cookies
-
Utilité :
-
Conserver un identifiant de session :
- Pour stocker un profil côté serveur
- Pour servir d'authentifiant temporaire
- Conserver des préférences de l'utilisateur côté client (fuseau horaire, devise préférée...)
-
Conserver un identifiant de session :
-
Limites des cookies :
- Peu adapté pour conserver des données volumineuses
-
Validité globale pour un client : difficilement restreignable à une instance de navigation
- Comment maintenir plusieurs paniers d'achat sur un même site dans deux fenêtres d'un même navigateur ?
- ⇒ utilisation de l'API de stockage local introduite par HTML5
Risques des cookies
Sécurité
-
Risque de capture d'un identifiant de session contenu dans un cookie :
- Par espionnage d'une connexion non chiffrée (point d'accès WiFi public)
- Par injection de code dans une page HTML (Cross Site Scripting XSS)
- ⇒ il faut toujours déspécialiser le contenu d'un formulaire renvoyé.
- Soumission furtive d'un formulaire par un site tiers (Cross Site Request Forgery CSRF) : \\
- ⇒ il faut ajouter à tout formulaire HTML un champ caché avec un jeton vérifié par le serveur
Vie privée
- Super-cookies sur des domaines trop larges (normalement refusés par le client sur domaines avec "1 point" tels que .com, .fr... par contre .gouv.fr pourrait être accepté)
- Cookie de durée de vie trop importante
- Cookie tiers : intégration d'éléments de sites tiers sur une page avec envoi de cookie (image invisible...)
- Cookie zombie utilisant de façon détournée le cache ou l'historique du navigateur pour survivre
- Exploitation de la signature comportementale du navigateur (en-têtes HTTP, comportement canvas HTML5...)
- Cookie utilisant des greffons du navigateur (cookie Flash...)
Évolutions du protocole HTTP
Connexion persistante et pipelining
- 1 requête/réponse = 1 connexion HTTP : trop coûteux
- Idée #1 : ne pas fermer la connexion si plusieurs requêtes à envoyer au même serveur
- ⇒ envoi d'un champ d'en-tête Connection: Keep-Alive (par défaut en HTTP/1.1)
- Idée #2 : ne pas attendre la réponse à une requête pour envoyer la suivante (pipelining)
- ⇒ permet d'économiser des RTTs (très utile sur les connexions de forte latence)
Multiplexage des flots, compression et poussée (SPDY, HTTP/2.0)
- Limitation du pipelining simple : 1 seul flot simultané
- Multiplexage : plusieurs flots découpés en trames enchevêtrées et transportés sur une même connexion TCP
- Priorisation : possibilité d'attribuer une priorité pour chaque flot
- Compression des en-têtes par code de Huffman
- Compression du corps : plus ou moins intéressant selon le type de données
- Poussée spontanée de données : le serveur peut suggérer ou devancer la demande d'une ressource
Utilisation du protocole UDP pour HTTP/3 (QUIC)
-
Utilisation historique du protocole de transport TCP par HTTP (TCP assure la retransmission des segments perdus et l'adaptabilité à la bande passante)
- Latence de l'initialisation des connexions TCP (poignée de main en 3 étapes)
- Latence supplémentaire introduite par le protocole d'échange de clés de chiffrement (TLS)
-
Introduction du protocole QUIC (Quick UDP Internet Connections) pour HTTP/3
- Initialisation simplifiée de la connexion avec échange simultané des clés (moins de latence)
- Multiplexage de la connexion : plusieurs ressources transmises simultanément, une perte de paquet sur une ressource ne bloque pas le chargement d'une autre ressource
- Multihoming : transmission possible de plusieurs adresses IP (réseau wifi, réseau cellulaire...)
- Evolution plus rapide du protocole (implantation applicative et pas dans le noyau) : mises à jour fréquente possible des clients et serveurs web
WebSocket
- Protocole défini dans la RFC 6455
- Permet au serveur de pousser des données (évite une approche pull avec requêtes AJAX)
-
Initialisation d'une connexion WebSocket :
- Le client HTTP contacte le serveur avec une requête HTTP spécifique (méthode GET avec en-tête Upgrade: websocket)
- Le serveur envoie une réponse HTTP pour accepter le passage en websocket
- La communication bascule en websocket (irréversible)
- Communication bidirectionnelle par envoi de messages (binaires ou textuels UTF-8)
- Destiné à remplacer la méthode COMET (appels AJAX avec envoi différé de la réponse)
- Principal avantage : réduction de latence par pipelining de messages
WebRTC
A venir...