Table des matières
Module requete
Nom du fichier : requete.py
Défini une classe Requete chargée d’interpréter une requête d'un client reçue par le serveur.
Vous pouvez tester le bon fonctionnement avec le module de test : requete.test.py.
À quoi ressemblent les requêtes
Les requêtes sont toujours de simples textes qui peuvent avoir les formes suivantes :
Cas d'une requête GET
GET /dossier/sousdossier/test.html HTTP/1.1 Host: localhost:80 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate DNT: 1 Connection: keep-alive Upgrade-Insecure-Requests: 1
Dans ce cas l’URL demandée est /dossier/sousdossier/test.html
l’URL peut être plus compliquée. Rien n'empêche d'entrer une URL comme chose=45-id+74
Cas d'une requête POST avec des paramètres
POST /dossier/sousdossier/test.html HTTP/1.1 Host: localhost:80 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate DNT: 1 Connection: keep-alive Upgrade-Insecure-Requests: 1 x=17&monttexte=blablabla
C'est le cas où l'interface web contient un formulaire permettant à l'utilisateur d'envoyer des données. On utilise une requête POST seulement dans le cas où la requête est susceptible de modifier l'état du serveur (écrire dans la BDD) sinon on utilise une requête GET.
Il existe des requêtes PUT et DELETE mais elles sont moins connues et nous ne les utiliserons pas.
Interface de la classe Requete
- méthode
__init__(self, str_requete:str)oùstr_requeteest le texte de la requête - méthode
url(self) -> strrenvoie l’URL complète de la requête, - méthode
is_GET(self) -> boolrenvoieTruesi la méthode de la requête est GET, - méthode
is_POST(self) -> boolrenvoieTruesi la méthode de la requête est POST, - méthode
post_params(self) -> dictrenvoie les paramètres sous forme d'un dictionnaire en cas de requête POST. Précondition : requête POST.
Dans l'exemple ci-dessus, le retour serait {'x':'17', 'montexte':'blablabla'}
- méthode
match(self, pattern:str). Celle-ci est complexe, je détaille ci-dessous.
Méthode match
On veut pouvoir définir un schéma – pattern pour une URL générique.
Par exemple le schéma <nom>.html.
- Si l’URL est
dossier/monfichier.html, alors le schéma est vérifié etnom = 'dossier/monfichier'. La méthode devrait alors renvoyer{'nom':'dossier/monfichier'} - Si L’URL est
image.jpg, alors le schéma n'est pas vérifié et la méthode devrait renvoyerFalse.
Autre exemple : le schéma /livre-<id>
- Si l’URL est
/livre-45, alors le schéma est vérifié etid = '45'. La méthode devrait alors renvoyer{'id':'45'} - Si l’URL est
/blabla-18, alors le schéma n'est pas vérifié et la méthode devrait renvoyerFalse
Le schéma est donc constitué de parties fixes et de parties ente <...> variables qu'il faut récupérer.
Cette méthode nécessite l'utilisation d'expressions régulières. Je vous donne ci-dessous un peu d'aide :
# nécessite :
import re
# supposons que pattern = "/livre-<id>"
# et que url = "/livre-475"
regex_tag = "<[^<]*>" # consiste à chercher les <...>
for m in re.finditer(regexTag, pattern): # parcours les <...> trouvés dans pattern
needle = m.group(0) # ex: trouve "<id>"
repl = "(?P"+needle+".*)" # ex: propose de remplacer par "(?P<id>.*)"
pattern = re.sub(needle,repl,pattern) # effectue le remplacement
pattern = "^" + pattern + "$"
# l'expression est devenue : "^/livre-(?P<id>.*)$"
# on peut appliquer l'expression à l'url
retour = re.match(pattern, url)
# en cas d'échec, retour == None
# mais dans notre exemple, c'est un succès :
# "^/livre-(?P<id>.*)$" a bien reconnu "/livre-475" et a extrait id = 475
retour.groupdict()
# cette commande renvoie le résultat sous forme d'un dictionnaire :
# { 'id':'475' }
