====== CGI ====== ====== 1. Programmation CGI simple ====== Un programme dit **CGI** (plus précisément: respectant la spécification //Common Gateway Interface//) reste un programme des plus normaux, il peut être donc très facile de créer ou d'adapter un programme Perl pour qu'il se dote d'une interface web. Ainsi une tâche obscure gérée par un administrateur avec sa ligne de commande peut se transformer en simple URL à aller consulter... ===== Contexte du CGI ===== Un serveur web peut être configuré pour exécuter à la demande un script sous certaines conditions. Par exemple, avec Apache on peut utiliser cette directive pour exécuter automatiquement les fichiers //*.cgi// : AddHandler cgi-script .cgi Options ExecCGI Si l'adresse http://localhost/test.cgi correspond au fichier local suivant : #!/usr/bin/perl -w use Data::Dumper; print "Content-Type: text/plain\r\n\r\n"; print Dumper(\%ENV); Alors la consultation de l'URL exécutera notre script et nous verrons les informations suivantes : $VAR1 = { 'SCRIPT_NAME' => '/~zerodeux/test.cgi', 'SERVER_NAME' => 'localhost', 'SERVER_ADMIN' => 'webmaster@localhost', 'HTTP_ACCEPT_ENCODING' => 'gzip,deflate', 'HTTP_CONNECTION' => 'keep-alive', 'REQUEST_METHOD' => 'GET', [...] 'GATEWAY_INTERFACE' => 'CGI/1.1', 'SERVER_ADDR' => '127.0.0.1', 'DOCUMENT_ROOT' => '/var/www/', 'HTTP_HOST' => 'localhost' }; On constate alors que la communication **en entrée** avec le programme s'effectue via les variables d'environnement, à l'instar de //@ARGV// dans un programme. Le nom des variables et leur contenu est précisément défini par l'interface **CGI/1.1**. Par extension, dans le cas où des informations doivent être remontées vers le programme (requête **POST**: upload, formulaire), ces informations arriveront par l'entrée standard du programme. Enfin, le résultat correspond simplement à la **sortie standard** du programme, avec une contrainte importante: elle commence par les entêtes HTTP de la réponse (optionnels, bien que //Content-Type// soit incontournable). Ces entêtes finissent toujours par une ligne vide, la convention du retour chariot étant en //\r\n//. ===== Module CGI ===== Le module //CGI// de Perl nous permet de respecter le standard sans se soucier des détails qui peuvent être parfois délicats et très ennuyeux. Il peut également nous aider à produire un document HTML en sortie en gardant une approche "programme" (et non "template"). Exemple : #!/usr/bin/perl -w use CGI qw/:standard/; print header('text/html'), start_html('Un formulaire simple'), h1('Quizz'), start_form(), "Comment vous appelez-vous ?", textfield('name'), submit(), end_form(); if (param()) { my $name = param('name'); print hr(), "Bonjour ".escapeHTML($name)."! \n"; } print end_html(); La gestion des paramètres du CGI est très similaire à celle de //getopt//, sous la forme de paires clé/valeur. On obtient la liste des paramètres avec //@names = param()// et la valeur de chacun d'eux avec //$val = param('name')//. Dans le cas d'un document HTML, toute variable doit être considérée avec soin avant d'être imprimée vers la sortie car celle-ci peut contenir du code HTML: si cela n'est pas souhaité, alors on utilise //escapeHTML//. ===== Limitations ===== Un programme CGI simple s'exécute dans le contexte d'une requête HTTP, ceci a plusieurs limitations : * **durée de la connexion**: la connexion peut être abrégée par le serveur ou un proxy si aucun transfert n'a lieu, ou une durée maximale est dépassée, ce qui peut interrompre des programmes de longue haleine. Solution: se lancer en tâche de fond (//system("$0 &")//), mais on perd alors la sortie du script. * **job control**: on ne peut pas interrompre le programme simplement, ni savoir s'il est toujous en cours d'exécution ou non * **privilèges**: le script est lancé avec les privilèges du serveur web, qui sont en général ceux d'un compte dédié. Solution: utiliser **sudo** à bon escient. ===== Sécurité ===== En dehors du contexte de la console dont on considère son utilisateur (l'admin sys, vous!) responsable, vous devrez considérer que vos programmes pourront être détournés de leur usage, par malveillance ou malchance. En général une URL est largement accessible (intranet ou publique) et de nombreuses personnes avec des contextes et des connaissances différentes pourront y accéder. Pour se préserver de surprises, Perl possède un mode de sécurité automatique appelé **taint mode**: toutes les informations en entrée (paramètres, entrée standard, variables d'environnement, etc) sont considérées par défaut //tainted// (colorées) et il faudra explicitement les "blanchir" avant de pouvoir les utiliser. Appliquer une expression régulière pour vérifier le contenu d'une variable est par exemple considéré comme une opération de blanchiement : #!/usr/bin/perl -wT use CGI qw/:standard/; my $file = param('file'); $file =~ s:/::; header("Content-Type: text/html"); $ENV{'PATH'} = '/usr/bin'; system("cat doc/$file"); ====== 2. mod_perl ====== Ressources : http://perl.apache.org/ Historiquement Perl fut parmi le langage le plus utilisé pour la programmation web, avant l'avènement de Java, PHP et autres dans le domaine. Il reste des infrastructures solides et très abouties, et bien sûr Perl lui-même avec ses innombrables modules. Tous les principes de CGI restent valable, mais cette fois l'interpréteur Perl est "embarqué" dans le serveur web. Cela signifie deux choses importantes : * **Performance**: il n'y a pas besoin d'exécuter un interpréteur pour chaque requête, mais pour chaque création de process Apache (qui va typiquement gérer 10,000 à 100,000 requêtes) * **Coopération**: il devient possible de programmer le serveur web lui-même et profiter de son infrastructure pour décider précisément comment les requêtes doivent être traitées (on peut ainsi écrire l'équivalent de //rewrite//, //auth//, etc. en Perl) L'utilisation du module //CGI// est transparente dans le contexte de mod_perl, vous pouvez donc profiter des gains de performance et des économies de ressources tout en continuant à utiliser la simplicité de ce module pour programmer. Exemple de configuration permettant d'utiliser ses CGIs sous mod_perl avec Apache : SetHandler perl-script PerlHandler Apache::Registry Options ExecCGI Pour programmer des applications plus complexes basées sur mod_perl, la méthode la plus efficace est très probablement d'adopter un //framework//, c'est-à-dire un ensemble de modules cohérents qui répondent à la majorité des scenarii dont vous aurez besoins (sessions, formulaires, base de données, persistence, etc). Le framework attitré de Perl (comme //Rails// pour Ruby) est http://www.catalystframework.org/ Catalyst.