10.2. Le protocole HTTP#

Le protocole HTTP fait partie de la couche application du modèle TCP/IP.

Le protocole HTTP (HyperText Transfer Protocol) définit plusieurs verbes correspondant à des actions. Parmi ces actions, on dispose de :

  • GET pour récupérer une ressource

  • POST pour envoyer une ressource

  • HEAD pour demander un entête

  • PUT pour envoyer une ressource sans modification d’état

  • DELETE pour supprimer une ressource

  • UPDATE pour mettre à jour une ressource existante.

En classe de Première, on étudiera essentiellement les deux premières.

10.2.1. Récupération d’une ressource#

Pour récupérer une ressource, on utilise le verbe HTTP GET suivi de la ressource. Une façon de faire avec Python est d’utiliser la bibliothèque http et plus particulièrement le rayon http.client.

Note

http.client fait partir de la bibliothèque standard, au même titre que socket ou urllib3 que nous ne développerons pas là. Une bibliothèque populaire est requests mais il faut l’installer avec

pip install requests

Note

Il s’agit de la requête effectué lorsque vous tapez http://httpbin.org/get dans la barre d’adresse de Firefox.

>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s.connect(("httpbin.org",80))
>>> s.send(b"GET /get\nHost: httpbin.org\n\n")
27
>>> r = s.recv(1024)
>>> r
import http.client
conn = http.client.HTTPConnection('httpbin.org:80')
conn.request('GET', '/get')
res = conn.getresponse()
data = res.read()
data
import requests

response = requests.get('http://httpbin.org/get')
response.text

Note

En réalité, la traduction du nom de domaine (httpbin.org) en une adresse IP est une fonction du système d’exploitation. Celle-ci est accessible dans le module socket.

Ainsi, la fonction socket.gethostbyname renvoie la première adresse IP correspondant au nom passé en argument :

import socket
socket.gethostbyname('httpbin.org')
'44.205.219.248'

Mais, une même adresse IP peut héberger plusieurs hôtes :

import socket
ip = socket.gethostbyname('httpbin.org')
socket.gethostbyaddr(ip)
('ec2-34-205-201-49.compute-1.amazonaws.com', [], ['34.205.201.49'])

Les 3 méthodes proposées ici vont de la plus rudimentaire à celle avec le plus haut niveau d’abstraction, mais il est nécessaire de bien comprendre ce qui se passe.

Le verbe GET, suivi de la ressource / permet de récupérer le document servi par le chemin (on parle de path_info) précisé. Ce chemin peut correspondre à un chemin de fichier de type Unix, comme vu dans le chapitre sur le shell.

On peut aussi passer des informations dans la ressource avec le query_string, c’est-à-dire la partie de l’url située après le caractère ?.

Avertissement

Lorsqu’on utilise le protocole HTTP, l’intégralité du message est transmis en clair.

###[ Ethernet ]###
  dst       = a4:b1:e9:52:20:55
  src       = d8:5e:d3:ad:ab:a7
  type      = IPv4
###[ IP ]###
     version   = 4
     ihl       = 5
     tos       = 0x0
     len       = 119
     id        = 18159
     flags     = DF
     frag      = 0
     ttl       = 64
     proto     = tcp
     chksum    = 0x8df2
     src       = 172.27.0.15
     dst       = 34.205.150.168
     \options   \
###[ TCP ]###
        sport     = 42304
        dport     = http
        seq       = 1765525781
        ack       = 1785487554
        dataofs   = 8
        reserved  = 0
        flags     = PA
        window    = 502
        chksum    = 0x6609
        urgptr    = 0
        options   = [('NOP', None), ('NOP', None), ('Timestamp', (2814698591, 2307966401))]
###[ Raw ]###
           load      = b'GET /get HTTP/1.1\r\nHost: httpbin.org\r\nAccept-Encoding: identity\r\n\r\n'

###[ Ethernet ]###
  dst       = d8:5e:d3:ad:ab:a7
  src       = a4:b1:e9:52:20:55
  type      = IPv4
###[ IP ]###
     version   = 4
     ihl       = 5
     tos       = 0x0
     len       = 517
     id        = 48139
     flags     = DF
     frag      = 0
     ttl       = 235
     proto     = tcp
     chksum    = 0x6c47
     src       = 34.205.150.168
     dst       = 172.27.0.15
     \options   \
###[ TCP ]###
        sport     = http
        dport     = 42304
        seq       = 1785487554
        ack       = 1765525848
        dataofs   = 8
        reserved  = 0
        flags     = PA
        window    = 105
        chksum    = 0x38d8
        urgptr    = 0
        options   = [('NOP', None), ('NOP', None), ('Timestamp', (2307966514, 2814698591))]
###[ Raw ]###
           load      = b'HTTP/1.1 200 OK\r\nDate: Sun, 05 Mar 2023 14:24:28 GMT\r\nContent-Type: application/json\r\nContent-Length: 235\r\nConnection: keep-alive\r\nServer: gunicorn/19.9.0\r\nAccess-Control-Allow-Origin: *\r\nAccess-Control-Allow-Credentials: true\r\n\r\n{\n  "args": {}, \n  "headers": {\n    "Accept-Encoding": "identity", \n    "Host": "httpbin.org", \n    "X-Amzn-Trace-Id": "Root=1-6404a61c-1890c689306178c07eec4456"\n  }, \n  "origin": "109.190.189.63", \n  "url": "http://httpbin.org/get"\n}\n'

10.2.2. Envoi d’information#

L’intérêt de la requête GET vue précédemment réside dans le fait que celle-ci peut s’enregistrer pour être effectuée de la même façon et renvoyer un résultat prédictible. Par exemple, l’url https://www.openstreetmap.org/?mlat=48.89274&mlon=2.36100#map=19/48.89274/2.36100 peut être partagée pour fournir une carte des rues autour de l’établissement.

Cependant, cette méthode ne permet pas d’envoyer des informations à un serveur pour en modifier son état. Pour cela, on utilisera POST ou PUT [2].

>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s.connect(("httpbin.org",80))
>>> s.send(b"POST /post HTTP/1.1\nHost: httpbin.org\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 19\n\nvar1=val1&var2=val2\n")
27
>>> r = s.recv(1024)
>>> r
import http.client
conn = http.client.HTTPConnection("httpbin.org")
conn.request("POST", "/post", "var1=val1&var2=val2")
res = conn.getresponse()
data = res.read()
data
import requests

response = requests.post('https://httpbin.org/post', data={"var1": "val1", "var2": "val2"})