INF8007 Langages de script Sockets et serveur 1/18 INF8007 Langages de script Sockets et serveur Michel Desmarais Génie informatique et génie logiciel École Polytechnique de Montréal Hiver, 2014
INF8007 Langages de script Sockets et serveur 2/18 Sockets et serveur 1 Requête HTTP 2 Module SocketServer 3 Module BaseHTTPServer
INF8007 Langages de script Sockets et serveur 3/18 Serveur web Quelques notions de base d un serveur Web Écoute sur un port donné, par défaut le port 80. Pour éviter un conflit avec un serveur existant, on utilise souvent le port 8080 pour un serveur HTML alternatif. Attention : deux serveurs ne doivent pas écouter sur le même port. Deux types de requêtes : GET : requête avec paramètes fournis dans l appel ; normalement utilisé pour une requête simple qui n a pas d effet de bord POST : requête avec un corps contenant des paramètres
INF8007 Langages de script Sockets et serveur 4/18 Anatomie d une requête HTTP $ telnet en.wikipedia.org 80 Trying 208.80.152.2... Connected to en.wikipedia.org (208.80.152.2). GET /wiki/main_page http/1.1 Host: en.wikipedia.org HTTP/1.0 200 OK Date: Sun, 13 Sep 2009 22:51:11 GMT Server: Apache Cache-Control: private, s-maxage=0, max-age=0, must-revalid Content-Language: en Vary: Accept-Encoding,Cookie Last-Modified: Sun, 20 Sep 2009 22:32:30 GMT Content-Length: 56024 Content-Type: text/html; charset=utf-8 Age: 10426
INF8007 Langages de script Sockets et serveur 5/18 SocktServer et BaseHTTPServer Deux librairies de base sont utiles pour créer un serveur Web : SocketServer : gestion de la connection et des requêtes pour les protocoles TCP et UDP http://docs.python.org/library/ socketserver.html BaseHTTPServer : surclasse SocketServer pour fournir la base d un serveur HTTP http://docs.python.org/library/ basehttpserver.html
INF8007 Langages de script Sockets et serveur 6/18 Sockets et serveur 1 Requête HTTP 2 Module SocketServer 3 Module BaseHTTPServer
INF8007 Langages de script Sockets et serveur 7/18 Exemple de SocketServer # coding = Latin -1 # Tiré de # http :// docs. python. org / library / socketserver. html import SocketServer class MyTCPHandler ( SocketServer. BaseRequestHandler ): """ Surclassement de BaseRequestHandler Instantié à chaque connection ; surcharge handle () """ def handle ( self ): # self. request est le socket TCP # connecté au client self. data = self. request. recv ( 10000 ). strip () print "%s a écrit :" % self. client_address [0] print self. data # renvoit les données en majuscules self. request. send ( self. data. upper ())
INF8007 Langages de script Sockets et serveur 8/18 Exemple de SocketServer (suite) if name == " main ": HOST, PORT = " localhost ", 9999 # Créé le serveur au port 9999 de localhost server = SocketServer. TCPServer (( HOST, PORT ), \ MyTCPHandler ) # Active le serveur ; roule jusqu ' à une # interruption par Ctrl - C server. serve_forever ()
INF8007 Langages de script Sockets et serveur 9/18 Une requête à ce serveur Une connection telnet permet de valider le serveur : telnet localhost 9999 foobar FOO BAR Une requête d un fureteur (http://localhost:9999) nous permet d inspecter la réponse : GET / HTTP/1.1 HOST: LOCALHOST:9999 USER-AGENT: MOZILLA/5.0 (X11; U; LINUX X86_64; EN-US; RV:1.8.1.13) GECKO ACCEPT: TEXT/XML,APPLICATION/XML,APPLICATION/XHTML+XML,TEXT/HTML;Q=0.9,T ACCEPT-LANGUAGE: FR,FR-FR;Q=0.8,EN-US;Q=0.5,EN;Q=0.3 ACCEPT-ENCODING: GZIP,DEFLATE ACCEPT-CHARSET: ISO-8859-1,UTF-8;Q=0.7,*;Q=0.7 KEEP-ALIVE: 300 CONNECTION: KEEP-ALIVE
INF8007 Langages de script Sockets et serveur 10/18 Requête avec un POST Supposons que le fichier HTML suivant est soumis au serveur : <HTML><BODY> <form method= POST enctype= multipart/form-data action= http://localhost:8080/ > File to upload: <input type=file name=upfile><br> <br> <input type=submit value=press> to upload the file! </form> </BODY> </HTML> Il créé une requête POST dont le résultat est à la page suivante.
INF8007 Langages de script Sockets et serveur 11/18 Requête transmise au serveur POST / HTTP/1.1 HOST: LOCALHOST:9999 [...] CONTENT-TYPE: MULTIPART/FORM-DATA; BOUNDARY=---------------------------5 CONTENT-LENGTH: 619 -----------------------------5639707191244491524599084267 CONTENT-DISPOSITION: FORM-DATA; NAME="UPFILE"; FILENAME="UPLOAD.HTML" CONTENT-TYPE: TEXT/HTML <HTML><BODY> <FORM METHOD= POST ENCTYPE= MULTIPART/FORM-DATA ACTION= HTTP://LOCALHO [...] -----------------------------5639707191244491524599084267 CONTENT-DISPOSITION: FORM-DATA; NAME="HID1" ABC -----------------------------5639707191244491524599084267--
INF8007 Langages de script Sockets et serveur 12/18 Sockets et serveur 1 Requête HTTP 2 Module SocketServer 3 Module BaseHTTPServer
INF8007 Langages de script Sockets et serveur 13/18 Le module BaseHTTPServer Voir http: //docs.python.org/library/basehttpserver.html Le module BaseHTTPServer surclasse le module SocketServer.BaseServer La classe BaseHTTPServer.BaseHTTPRequestHandler facilite la gestion des requêtes et réponses HTTP en offrant une série de variables et méthodes dédiées. Nécessite de surcharger les méthodes do *(), notamment : do GET() do POST()
INF8007 Langages de script Sockets et serveur 14/18 Un exemple (1) # coding = Latin -1 # Inspiré du code webserver. py de Jon Berg, turtlemeat import string, cgi, time from os import curdir, sep from BaseHTTPServer import BaseHTTPRequestHandler, \ HTTPServer class MyHandler ( BaseHTTPRequestHandler ): def do_get ( self ): [... ] def do_post ( self ): [... ] def main (): [... ] if name == ' main ': main ()
INF8007 Langages de script Sockets et serveur 15/18 Un exemple (2) def main (): try : server = HTTPServer (('', 8080 ), MyHandler ) print ' serveurweb démarré... ' server. serve_forever () except KeyboardInterrupt : print ' Interruption ^C, arr^et du serveur ' server. socket. close () if name == ' main ': main ()
INF8007 Langages de script Sockets et serveur 16/18 Un exemple (3) def do_get ( self ): try : if self. path. endswith (". html "): f = open ( curdir + sep + self. path ) self. send_response ( 200 ) self. send_header ('Content - type ', \ 'text / html ') self. end_headers () self. wfile. write (f. read ()) f. close () return return except IOError : self. send_error (404,\ ' Fichier non trouvé : %s' % self. path )
INF8007 Langages de script Sockets et serveur 17/18 Un exemple (4) def do_post ( self ): global rootnode try : ctype, pdict = cgi. parse_header (\ self. headers. getheader ('content - type ')) if ctype == ' multipart /form - data ': query = cgi. parse_multipart ( self. rfile,\ pdict ) self. send_response ( 301 ) self. end_headers () upfilecontent = query. get ('upfile ') print " filecontent ", upfilecontent [ 0] self. wfile. write ("<HTML > POST OK.<BR ><BR >"); self. wfile. write ( upfilecontent [0]); except : pass
INF8007 Langages de script Sockets et serveur 18/18 Un exemple (5) Pour l utilisation de la librairie cgi, voir : http://docs.python.org/library/cgi.html#cgi. parse_header http://docs.python.org/library/cgi.html#cgi. parse_multipart