=========================== Le protocole HTTP et WSGI =========================== .. role:: lat Rappels sur le Web ================== Web ≠ Internet -------------- Internet est ensemble de réseaux informatiques locaux utilisant les mêmes protocoles de bas niveau standards (TCP/IP) et formant un réseau global. .. figure:: InternetMonde.* Image © portices.fr__ __ http://www.portices.fr/formation/Res/Internet/Res/InternetMonde.gif .. note:: Le Web est *l'une* des applications d'internet, et la plus populaire, d'où l'amalgamme souvent fait entre les deux. Qu'est-ce que le Web ? ---------------------- Un espace documentaire décentralisé, interconnecté et interopérable. .. rst-class:: build * décentralisé → **HTTP** * interconnecté → **URL** * interopérable → **HTML** .. note:: Ces technologies peuvent bien sûr évoluer (elle l'ont déjà fait), voire être à terme remplacées par d'autres. Ce ne sont pas elles qui définissent le Web, mais les 3 propriétés qu'elles lui confèrent. Architecture du Web =================== Architecture Client-Serveur --------------------------- * **Ressource**: toute unité d'information (document, image, vidéo, données...) accessible sur le Web, **identifiée par une URL** * **Serveur**: un ordinateur « contenant » des ressources, toujours connecté à Internet. * **Client**: un ordinateur/smartphone/tablette... utilisé pour **exploiter** des ressources. .. figure:: client-server.* :height: 8ex Source image http://commons.wikimedia.org/wiki/File:Client-server-model.svg .. note:: * Les termes "client" et "serveur" identifient en fait des *rôles*. * Le même ordinateur peut jouer le rôle de client dans certaines situations, et de serveur dans d'autres situations. * Il est même possible d'avoir, sur un *même ordinateur*, un logiciel client et un logiciel serveur (c'est ce que nous ferons en TP). Identification des ressources ----------------------------- .. raw:: html :file: url-structure1.html * Le nom local a souvent une structure hiérarchique (similaire à la structure des fichiers). * Comme pour les fichiers, on peut spécifier une URL *relativement* à une autre : exemple : ``../algorithmique`` .. warning:: Malgré cette similitude, les ressources ne correspondent *pas toujours* à des fichiers. .. nextslide:: * Plus généralement, le nom local est composé de plusieurs parties, ayant des structures différentes. Son interprétation est du ressort *du serveur*. .. raw:: html :file: url-structure2.html * *Chaque* URL désigne une **ressource différente** (même lorsqu'elle ne diffère que par les paramètres, par exemple) Rôles du serveur ---------------- * Est garant de l'état des ressources, * pour en fournir une *représentation* aux clients qui le demandent (GET), * mais aussi pour les *modifier* en réponse à certaines requêtes (POST), par exemple : - commande sur un site marchand, - message posté sur un réseau social, - `etc`:lat:... .. important:: L'état d'une ressource n'est pas forcément stocké dans un fichier. Souvent, il est stocké dans une base de données ; la représentation HTML (ou autre) de la ressource est calculée par le serveur. Rôles du client --------------- * Interprète les représentation envoyées par le serveur (pour les afficher, mais pas uniquement) * Gère la navigation en interne * Gère les interactions avec le serveur : - clics sur des liens, - formulaires, - `etc`:lat:... Message HTTP ============ Principe -------- HTTP est basé sur l'échange de **messages** : * le client envoie un message *requête*, * le serveur retourne un message *réponse*. Chaque échange est indépendant des autres (messages auto-suffisants). Structure générale ------------------ .. image:: envelope.svg Structure d'une requête ----------------------- * Première ligne - verbe - identifiant local de la ressource - version du protocole HTTP * En-têtes (suivis d'une ligne vide) * Contenu facultatif (selon le verbe) Exemples de requêtes -------------------- .. rst-class:: request .. code-block:: http :emphasize-lines: 1 GET /france/lyon HTTP/1.1 Host: meteo.example.org User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0 Accept: text/html,application/xhtml+xml, application/xml;q=0.9,*/*;q=0.8 Accept-Language: fr,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: UTF-8,* Connection: keep-alive Keep-Alive: 300 (pas de contenu) ---- .. nextslide:: :increment: .. rst-class:: request .. code-block:: http :emphasize-lines: 1 GET /france?ville=lyon HTTP/1.1 Host: meteo.example.org User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0 Accept: text/html,application/xhtml+xml, application/xml;q=0.9,*/*;q=0.8 Accept-Language: fr,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: UTF-8,* Connection: keep-alive Keep-Alive: 300 (pas de contenu) ---- .. nextslide:: :increment: .. rst-class:: request .. code-block:: http :emphasize-lines: 1 POST /passer-commande HTTP/1.1 Host: marchand.example.org User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0 Accept: text/html,application/xhtml+xml, application/xml;q=0.9,*/*;q=0.8 Accept-Language: fr,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: UTF-8,* Connection: keep-alive Keep-Alive: 300 Content-Type: application/x-www-form-urlencoded Content-Length: 12345 nom=PA+Champin&addresse=12+rue+Turing&articles=... .. note:: * On retrouve dans la requête la structure de l'URL (nom du serveur, nom local de la ressource) * Notez que les deux premières requêtes sont identiques, à l'exception du nom local. Structure d'une réponse ----------------------- * Première ligne - version du protocole HTTP - code de statut - libellé textuel * En-têtes (suivis d'une ligne vide) * Contenu facultatif (selon le code de statut) Exemples de réponse ------------------- .. rst-class:: response .. code-block:: http :emphasize-lines: 1 HTTP/1.1 200 OK Date: Mon, 02 Jan 2016 22:46:26 GMT Server: Apache/2 Accept-Ranges: bytes Content-Type: text/html; charset=utf-8 Content-Length: 29794 Etag: "7462-477341dcfb940;89-3f26bd17a2f00" Last-Modified: Mon, 02 Jan 2016 12:00:00 GMT Content-Location: Home.html Vary: negotiate,accept Cache-Control: max-age=600 Expires: Mon, 02 Nov 2009 22:56:26 GMT Connection: close Météo de Lyon ... .. nextslide:: :increment: .. rst-class:: response .. code-block:: http :emphasize-lines: 1 HTTP/1.1 303 See also Date: Mon, 02 Jan 2016 22:46:26 GMT Server: Apache/2 Accept-Ranges: bytes Location: /commande/12345 Connection: close (pas de contenu) ---- .. nextslide:: :increment: .. rst-class:: response .. code-block:: http :emphasize-lines: 1 HTTP/1.1 404 Not Found Date: Mon, 02 Jan 2016 22:46:26 GMT Server: Apache/2 Content-Type: text/html; charset=utf-8 Content-Length: 2979http://rdflib.readthedocs.io/ Connection: close Cette ressource n'existe pas ... Codes de statut --------------- HTTP définit 40 codes de statut, répartis en cinq catégories : .. list-table:: :header-rows: 1 * - Catégories - Exemples * - 1xx : Information - 100 Continue * - 2xx : Succès - 200 OK * - 3xx : Redirection - 301 Moved Permanently * - 4xx : Erreur client - 404 Not Found, 401 Unauthorized * - 5xx : Erreur serveur - 500 Internal Server Error En-têtes de requête ------------------- .. note:: HTTP spécifie un *très grand nombre* d'en-têtes ; nous décrirons au fur et à mesure du cours ceux dont nous avons besoin. * ``accept``: la liste des types de contenu (au format `MIME`_) préférés le client. * ``accept-language``: la liste des langues (au format :rfc:`4646`) préférés par le client. Ces en-têtes servent à la *négociation de contenu* (*conneg*). Le serveur *peut* utiliser ces informations pour *adapter* le contenu de la réponse, mais il peut aussi les ignorer (lorsque la ressources est un fichier statique). .. _MIME: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_Types * ``cache-control``: permet d'influer sur le comportement des caches intermédiaires, notamment pour les inhiber (option ``no-cache``). En-têtes de réponse -------------------- * ``content-type``: le type de contenu de la réponse (au format `MIME`_). Exemple: ``text/html``, ``image/png``, ``application/pdf``. * ``content-length``: la taille du message en octets. * ``cache-control``: permet d'influer sur le comportement des caches, notamment pour indiquer la durée de validité maximale (option ``max-age=``). .. note:: les en-têtes ``content-type`` et ``content-length`` sont en fait utilisés pour tout message ayant un contenu, y compris certaines *requêtes* (`e.g.`:lat: POST). WSGI ==== Serveur et application ---------------------- .. graphviz:: serveur.dot :caption: Les ressources du serveur peuvent être gérées de différentes manières .. note:: * Certaines ressources sont stockées directement dans des fichiers statiques (dont le nom est en général corellé avec le chemin de l'URL). * Certaines ressources sont gérées par un script PHP. * Certaines ressources sont gérées par un programme, répondant à certains standards, comme - `CGI `_, - WSGI, que nous allons décrire dans ce cours, - ... WSGI ---- WSGI (Web Server Gateway Interface) est un standard spécifiant comment un serveur Web peut interagir avec une application Python. .. _hello_world_wsgi: Hello world WSGI ---------------- .. code-block:: python def application(environ, start_response): message = b"Hello world\n" status = "200 Ok" headers = [ ("content-type", "text/html"), ("content-length", str(len(message))), ] start_response(status, headers) return [message] Explications ------------ * La fonction ``application`` sera appelée à chaque requête. * ``environ`` est un dictionnare, qui contient notamment toute l'information décrivant la requête. * ``start_response`` est une fonction servant à générer les méta-données de la réponse (statut et en-têtes). * La fonction doit retourner une liste de chaînes d'octets. .. note:: Plus précisément, la fonction doit retourner un `itérable`_ de chaînes d'octets. Cela permet dans certains cas au serveur d'envoyer les premiers octers avant que la fonction n'ait terminé son exécution. .. _itérable: https://docs.python.org/3/glossary.html#term-iterable Chargement du module -------------------- * Le module peut rester chargé entre deux requêtes, ce qui permet de mutualiser certains traitemens (`e.g.`:lat: connexion à une base de données). * Cela dit, le serveur peut à tout moment décharger le module, donc l'application ne doit pas s'appuyer sur des données conservées en mémoire. .. code-block:: python n = 0 def application(environ, start_response): global n n = n+1 message = ("Compteur: %s\n" % n).encode("utf-8") status = "200 Ok" headers = [ ("content-type", "text/html"), ("content-length", str(len(message))), ] start_response(status, headers) return [message] .. note:: Dans l'exemple ci-dessus, plusieurs requêtes successives vont faire augmenter le compteur. Cependant, à tout moment, le module peut être déchargé par le serveur, et rechargé lors d'une nouvelle requête, ce qui remettra le compteur à zéro. Si on voulait persister la valeur du compteur, il faudrait la sauvegarder dans un fichier ou une base de données. Le dictionnaire ``environ`` --------------------------- Il contient, entre autre, les clé suivantes : * ``PATH_INFO``: la partie hiérarchique du nom de la ressource * ``QUERY_STRING``: la partie associative du nom de la ressource * ``REQUEST_METHOD``: la méthode HTTP de la requête * ``wsgi.input``: un *file-like* donnant accès au contenu de la requête * ``CONTENT_TYPE``, ``CONTENT_LENGTH``: la valeur des en-têtes correspondants * ``HTTP_xxx`` : la valeur le l'en-tête ``xxx`` Pour en savoir plus, consultez `la spécification WSGI`__. __ https://www.python.org/dev/peps/pep-3333/#environ-variables .. _serveur_dev: Serveur de développement ------------------------ * Pour tester notre application, il ne serait pas très pratique d'avoir à configurer et déployer un serveur Web complet. * Heureusement, les bibliothèques standards de Python nous fournissent un mini-serveur, utile pour la phase de développement. * Pour l'utiliser, il suffit de créer un script contenant les lignes suivantes (en adaptant la première ligne) : .. code-block:: python from mon_projet import application from wsgiref.simple_server import make_server srv = make_server("localhost", 12345, application) srv.serve_forever()