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 ressourcePOST
pour envoyer une ressourceHEAD
pour demander un entêtePUT
pour envoyer une ressource sans modification d’étatDELETE
pour supprimer une ressourceUPDATE
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"})