Détection de la fin d'une requête HTTP

Comment détecter la fin d'une requête HTTP

Lorsqu'on implémente un serveur HTTP basique en Python, il est crucial de savoir quand une requête HTTP se termine pour éviter des connexions persistantes non désirées. Voici quelques exemples illutsrant différents cas où le client reste connecté indéfiniment :

from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR

reponse_http = 'HTTP/1.1 200 OK\r\n\r\n<html>Bonjour Monde !</html>'

serveur_socket = socket(AF_INET, SOCK_STREAM)
serveur_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serveur_socket.bind(('localhost', 12000))
serveur_socket.listen(1)

connexion_client, adresse = serveur_socket.accept()
while True:
    print('En attente de requête HTTP...')
    requete = connexion_client.recv(1024)
    
    print('Envoi de la réponse HTTP...')
    connexion_client.sendall(reponse_http.encode('utf-8'))

Dans cet exemple, bien que "Bonjour Monde !" soit affiché dans le navigateur, la connexion reste ouverte car aucune directive explicite ne stipule sa fermeture.

Solutions possilbes

1. Utilisation de Content-Length

Indiquer explicitement la longueur du corps de la réponse permet au client de savoir combien de données lire avant de considérer la requête comme terminée.

from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR

reponse_http = 'HTTP/1.1 200 OK\r\nContent-Length: 23\r\n\r\n<html>Bonjour Monde !</html>'

serveur_socket = socket(AF_INET, SOCK_STREAM)
serveur_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serveur_socket.bind(('localhost', 12000))
serveur_socket.listen(1)

connexion_client, adresse = serveur_socket.accept()
while True:
    print('En attente de requête HTTP...')
    requete = connexion_client.recv(1024)
    
    print('Envoi de la réponse HTTP...')
    connexion_client.send(reponse_http.encode('utf-8'))

2. Encodage par morceaux (Transfer-Encoding: chunked)

Le transfert par blocs divise les données en parties distinctes, avec chaque partie précédée de sa taille en hexadécimal.

from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR

entete_reponse = 'HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n'

serveur_socket = socket(AF_INET, SOCK_STREAM)
serveur_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serveur_socket.bind(('localhost', 12000))
serveur_socket.listen(1)

connexion_client, adresse = serveur_socket.accept()
while True:
    print('En attente de requête HTTP...')
    requete = connexion_client.recv(1024)
    
    print('Envoi de la réponse HTTP...')
    connexion_client.send(entete_reponse.encode('utf-8'))
    
    # Envoi du premier bloc
    connexion_client.send('5\r\nSalut\r\n'.encode('utf-8'))
    # Indication de fin
    connexion_client.send('0\r\n\r\n'.encode('utf-8'))

3. Fermeture de la connexion après la réponse (Connection: close)

Une autre méthode consiste à fermer explicitement la connexion après avoir envoyé la réponse.

from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR

reponse_http = 'HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n<html>Bonjour Monde !</html>'

serveur_socket = socket(AF_INET, SOCK_STREAM)
serveur_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serveur_socket.bind(('localhost', 12000))
serveur_socket.listen(1)

while True:
    print('En attente de requête HTTP...')
    connexion_client, adresse = serveur_socket.accept()
    requete = connexion_client.recv(1024)
    
    print('Envoi de la réponse HTTP...')
    connexion_client.send(reponse_http.encode('utf-8'))
    
    connexion_client.close()

Ces techniques permettent de gérer correctement la fin des requêtes HTTP et d'éviter des connexions ouvertes inutilement.

Étiquettes: HTTP Python SocketProgramming

Publié le 21 octobre à 16h36