Table des matières
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.