mod_rewrite, mod_perl, Mason : que la force soit dans Apache
Alexandre SIMON
CIRIL - Centre Interuniversitaire de Ressources Informatiques de Lorraine
Rue du Doyen Roubault
54500 VANDOEUVRE-LÈS-NANCY - FRANCE
Vincent DELOVE
CIRIL - Centre Interuniversitaire de Ressources Informatiques de Lorraine
Rue du Doyen Roubault
54500 VANDOEUVRE-LÈS-NANCY - FRANCE
Résumé
Le Web est sans doute la facette la plus visible et la plus incontournable de l'Internet. Ces dernières années les protocoles, les technologies et les frameworks ont énormément évolués pour faire changer les contenus et les méthodes de programmation d'un mode statique à un mode dynamique. On parle aujourd'hui du Web 2.0. Le serveur web Apache a su évoluer dans ce sens en proposant de nombreux modules. Parmi ces modules il y a la réécriture d'URL avec mod_rewrite et le module d'exécution et d'interprétation « embarquée » Perl mod_perl. Avec ces deux modules un développeur a à sa disposition deux outils extrêmement puissants lui permettant d'agir dynamiquement sur la visibilité de son site et sur la publication des contenus. mod_rewrite permet de faire quasiment toutes les manipulations sur les URL demandées ce qui entraine le développeur, en quelques lignes RewriteRule, à répondre à de complexes problèmes ou besoins d'accès à son site. Avec mod_perl, il peut aller encore plus loin en surchargeant et en modifiant le mode de fonctionnement « normal » d'Apache en l'adaptant à ses besoins. Le développeur va pouvoir en quelques lignes de Perl réécrire ou compléter les modules « de base » d'Apache et ainsi obtenir des fonctionnalités difficilement réalisables avec de simples scripts CGI. Enfin côté contenu, le module Perl HTML::Mason offre un système de template simple et complet. Très lié à mod_perl, HTML::Mason hérite de ses possibilités et dépasse le simple système de template en allant plus loin dans la publication des contenus. Cet article fera le point sur ces technologies en les présentant de manière pragmatique et en les illustrant par des exemples concrets.
Mots clefs
Apache, Perl, mod_rewrite, mod_perl, Mason, Web 2.0, REST
Parmi les standards à l'origine de l'Internet, le Web et les protocoles associés sont certainement ceux qui ont subi les évolutions les plus importantes de ces dernières années. Apache, pour prendre en compte ces nouveaux usages, s'appuie sur une architecture interne originale et flexible qui permet une extension modulaire de ses fonctionnalités. L'accessibilité des différentes étapes du processus de traitement des requêtes à travers ces modules fait d'Apache un modèle de conception. Pour le développeur web, la connaissance de ces mécanismes internes permet de révéler les possibilités étendues qui sont accessibles à travers l'utilisation ou la conception de nouveaux modules. Le module de réécriture des URL, « mod_rewrite », est un exemple parfait pour illustrer l'avantage que constitue le choix de cette architecture pour, par exemple, modifier dynamiquement la visibilité de son site. Ce module qui intervient très tôt dans la chaine de traitement, redéfinit profondément le comportement par défaut d'Apache en permettant par exemple de découpler la gestion des URL du système de fichiers sur disque. Cet article présente également comment certains modules comme « mod_perl » ne s'attachent pas simplement à une phase particulière mais comment ils constituent en fait une réelle API d'extension à Apache. Contrairement à ce que son nom pourrait faire penser, ce module n'est en aucun cas l'adaptation de mod_php pour Perl. Il offre la possibilité au programmeur Perl d'enrichir et de personnaliser le serveur à tous les niveaux. Cette introduction à « mod_perl » servira finalement de préambule à la présentation du module HTML::Mason et de ses concepts en terme de gestion de contenus.
Pour bien appréhender la présentation des modules mod_rewrite, mod_perl et Mason il est nécessaire de faire un approfondissement sur leur point commun : Apache. La compréhension de chacun de ces modules pourrait se suffire à elle-même, mais une présentation d'Apache permet de les replacer dans le contexte de fonctionnement du serveur et d'approfondir les mécanismes associés. L'idée n'est pas simplement de comprendre ce que « font » ces modules, mais surtout « pourquoi » et « comment » ils le font.
Dans ce cadre, la présentation d'Apache est ciblée et seuls les aspects du fonctionnement interne seront abordés. Les aspects généraux sur le serveur web, la configuration ou l'exploitation quotidienne ne seront pas traités. Certains concepts et explications seront raccourcis et simplifiés pour converger rapidement au coeur du fonctionnement d'Apache tout en restant le plus précis possible afin d'introduire au mieux la présentation des modules mod_rewrite, mod_perl et Mason.
Apache est sans doute le serveur web le plus connu et le plus répandu dans le monde du logiciel libre. Ses fonctionnalités et ses performances en tant que « serveur web » sont reconnues de tous. Mais ce n'est pas tout... Apache offre également une facette moins connue des administrateurs : une architecture interne originale faisant de lui une plateforme de développement pour compléter et modifier son fonctionnement « de base ». En effet, plus particulièrement depuis sa version 2.0, Apache propose une architecture interne modulaire, portable et extensible faisant penser, au premier abord, plus à une bibliothèque de développement qu'à un simple serveur web. Le noyau d'Apache (Apache core) est le point de départ et la base du développement du serveur lui-même mais également de tous les modules Apache disponibles (mod_...). Cette plateforme de développement propose une API de programmation : la librairie APR (Apache Portable Runtime) mais c'est surtout les concepts et l'architecture interne d'Apache qui font sa pertinence et son originalité.
Avec cette subtile combinaison de l'API de programmation et des concepts fondamentaux, il est possible de développer facilement et rapidement des modules et des fonctions complémentaires. Ces développements spécifiques sont, de fait, cohérents avec le reste du serveur. En suivant quelques règles de codage, ils bénéficient des fonctionnalités existantes et peuvent également être « prestataires de fonctions pour le reste ».
Les possibilités de développement avec Apache sont directement liées à son fonctionnement et à l'architecture utilisée pour le traitement des requêtes et pour la génération des réponses.
Une vue naïve et simpliste du
fonctionnement d'un serveur web peut être résumée
par la Figure 1.
En effet, du point de vue client, le cycle « requête
– contenu – réponse » résume
bien l'interface proposée par un serveur web. T
Figure
1: Vue simpliste du fonctionnement d'Apache
Le fonctionnement d'Apache se décompose en deux parties distinctes :
la phase de démarrage initiale (cycle de vie du serveur)
et la phase « opérationnelle » de traitement des requêtes et de génération des réponses (cycle de vie des requêtes).
Le synoptique complet de ce fonctionnement est illustré par la Figure 2.
Figure
2: "The big picture" - Cycles de vie du serveur et des
requêtes
Sur cette figure on distingue les deux blocs fonctionnels :
server lifecycle : démarrage et cycle de vie du processus père
child lifecycle : démarrage et cycle de vie des processus fils pour le traitement des requêtes.
Le processus père a en charge :
le démarrage et l'initialisation du serveur : lecture de la configuration, création des ressources, …
la création des processus fils et la gestion de cet ensemble selon le modèle MPM (Multi-Processing Module) choisi
l'attente des signaux de contrôle pour le pilotage du serveur (stop, restart, graceful, …)
De leur côté, les processus fils se chargent :
de l'écoute sur les sockets réseau et l'acceptation de nouvelles connexions
du traitement des requêtes : interprétation du protocole HTTP, recherche des URL demandées, vérifications des droits d'accès, …
du traitement et de la création du contenu à retourner au client.
Deux types d'appels de fonctions apparaissent sur la Figure 2 :
les blocs rectangulaires (ex. read_config) correspondent à des appels « classiques » de fonctions; ils ont été énumérés pour faciliter la compréhension de l'algorithme
les blocs rectangulaires avec une flèche vers la droite (ex. pre_config) sont des appels de fonctions configurables et extensibles : les Apache Hooks (les « crochets » d'Apache). Ces crochets sont les points d'entrées pour modifier ou compléter le fonctionnement « de base » du serveur.
L'originalité du code d'Apache est d'avoir prévu « ces points de branchement » accessibles par les modules de base (Apache Core) mais également par tous les autres modules (modules fournis par Apache ou contributions extérieures).
Le principe d'utilisation des hooks est simple : un module peut à son initialisation enregistrer (ie. attacher) sur les crochets disponibles une fonction qui lui est propre. Durant le cycle de vie, au passage de chaque crochet, le processus exécute les fonctions (handlers) attachées à ces crochets selon la configuration du serveur et la requête en cours.
Figure
3: Exemple d'exécution des handlers sur le hook
translate_name
Le processus fils, au passage sur ce crochet, exécute les fonctions enregistrées par mod_perl puis mod_rewrite puis mod_alias et enfin mod_core. Cette série d'exécutions est conditionnelle et fonction de la configuration du serveur, de la requête en cours et du retour de l'appel à chacune de ces fonctions.
Le principe est donc posé : Apache propose en standard des « points de branchements » pour chainer l'exécution de fonctions enregistrées par les modules activés au démarrage du serveur. Cette notion de crochet n'est pas figée et il ne serait pas surprenant de voir apparaître des nouveaux hooks dans la prochaine version d'Apache, comme cela a été le cas lors du passage de la version 2.0 à la version 2.2 (test_config et monitor). D'autre part, la déclaration de nouveaux hooks ne se limite pas au coeur d'Apache et un module peut proposer lors de son exécution un point de branchement qui pourrait être utilisé à son tour par d'autres modules.
Cette présentation des Apache Hooks n'est pas exhaustive mais le concept doit être maintenant bien maitrisé. Pour approfondir ce mécanisme, le lecteur pourra étudier de plus prés les notions suivantes :
comment déclarer un nouveau hook,
comment appeler un hook (ap_run_...),
le type d'exécution du hook (VOID, RUN_FIRST, RUN_ALL)
le code de retour des fonctions handler (OK, DECLINED, DONE, HTTP ERRORS, ...),
comment se brancher sur un hook et comment spécifier l'ordre d'enregistrement (HOOK_REALLY_FIRST, HOOK_FIRST, HOOK_MIDDLE, HOOK_LAST, HOOK_REALLY_LAST)
Le lecteur se reportera à la section 4.2 pour une description plus détaillée du rôle de chaque hooks dans le contexte de mod_perl.
Depuis la version 2.2 d'Apache, le module mod_info permet de visualiser les hooks, les modules qui les utilisent et l'ordre d'enregistrement. Le lecteur pourra se reporter à la documentation http://httpd.apache.org/docs/2.2/mod/mod_info.html pour la mise en oeuvre de ce module. Il lui sera alors possible d'observer et de comprendre le comportement de son serveur au travers des informations de hooks ↔ modules enregistrés.
Dans la distribution d'Apache il existe également un script Perl qui fournit la liste des hooks disponibles dans le code : httpd-2.x.y/support/list_hooks.pl.
Après les hooks, la deuxième notion fondamentale d'Apache sont les filtres. Cette notion de filtre est déjà perceptible par les administrateurs qui ont certainement déjà manipulé des directives de configuration telles que AddOutputFilter, SetOutputFilter, AddOutputFilterByType... mais les filtres ne s'arrêtent pas là. En réalité dans Apache « tout est filtre » et les mécanismes associés sont transversaux et présents dans tous les autres concepts du serveur. Cette transversalité empêche de faire apparaître les filtres sur le synoptique des cycles de vie du serveur et des requêtes Figure 2, néanmoins les filtres sont omniprésents.
Il existe trois types de filtres qui opèrent à différents niveaux (cf. Figure 4).
Figure
4: Les filtres dans Apache
en premier lieu, au niveau du réseau. Pour être plus exact la lecture et l'écriture sur le réseau sont considérées comme des filtres à part entière, transformant la lecture dans une socket en un flux de données TCP (et inversement pour l'écriture)
ensuite, ce sont les filtres au niveau du protocole qui sont évalués, le but étant principalement d'interpréter les entêtes HTTP et de construire les structures de données « requêtes » associées en entrée (et inversement en sortie)
enfin les filtres de contenu prennent le relais et permettent d'appliquer toute sorte de transformations sur les contenus avant et après génération.
Figure
5: Exemple d'application des filtres
Qui aurait pu croire que la fonctionnalité d'encodage/décodage SSL était implémentée à l'aide d'un « simple » filtre ? Pour se convaincre de l'omniprésence des filtres dans Apache il suffit de lancer un grep sur ap_register_output et ap_register_output dans les sources du serveur...
Avec ces concepts de hooks et de filtres, Apache propose une architecture interne originale, modulaire et facilement extensible. Ce sont les fonctionnalités des modules proposés par Apache qui ont fait son succès auprès des administrateurs. C'est son architecture interne qui a séduit les développeurs et qui a permis l'ajout des fonctionnalités que l'on connait aujourd'hui.
Apache est donc bien plus qu'un « simple serveur web » car il propose une vraie plateforme de développement pour ses besoins propres et pour son évolution. Mais cette plateforme peut être également utilisée pour développer des serveurs qui n'ont rien à voir avec le protocole HTTP... pourquoi pas un serveur FTP... ou encore mieux un serveur SMTP ! C'est possible et cela existe déjà : http://httpd.apache.org/modules/.
Le temps où les sites web vus des navigateurs étaient le reflet du système de fichiers du serveur est révolu et le module mod_rewrite y participe grandement ! Par défaut le serveur Apache fait une correspondance directe entre l'URL demandée et les fichiers disponibles sous sa portée (sous l'arborescence du DocumentRoot). Bien sûr les directives telles que Alias et ScriptAlias permettent de modifier cette correspondance et même de sortir des objets de la portée du serveur. Mais les possibilités de réécriture restent très basiques et lorsque les limites sont atteintes il faut utiliser un outil plus puissant : mod_rewrite.
Les détails des mécanismes utilisés par Apache pour faire la correspondance entre l'URL demandée et l'emplacement sur le système de fichiers sont présentés dans le document : http://httpd.apache.org/docs/2.2/urlmapping.html.
mod_rewrite est un outil très utile pour le développement d'applications web « modernes », car celles-ci ne sont pas toujours bien placées pour un traitement spécifique des URL. Il est souvent plus simple et pertinent d'écrire quelques règles de réécriture (RewriteRule) que de se lancer dans un codage applicatif trop spécifique.
Il faut préciser que mod_rewrite s'enregistre et intervient sur les hooks translate_name, fixups et handler du cycle de vie d'une requête HTTP (Figure 2).
Rappelons que les règles de réécriture sont du type :
RewriteRule Pattern Substitution [flags]
Le Pattern est évalué par rapport à l'URL demandée par le client. La sous-chaine utilisée est extraite juste après le nom du serveur (hostname) et le port, et juste avant la chaîne des paramètres. Par exemple, pour l'URL http://vhost.ciril.fr/foo/bar/page.html?param=zoo&test=yes c'est la sous-chaine /foo/bar/page.html qui sera évaluée.
Si l'évaluation du Pattern est positive, alors la Substitution pourra être appliquée, et c'est cette nouvelle URL qui sera traitée dans le reste du cycle de vie de la requête. Les réécritures peuvent être de quatre types différents :
un fichier sur le système de fichiers (ex. /var/www/site/index.html)
une URL dans la portée du serveur (ex. /images/favicon.ico)
une URL en dehors de la portée du serveur (ex. http://autre.site.fr/foo/bar)
aucune substitution n'est effectuée (ex. -)
Il est possible d'utiliser des variables propres au contexte de réécriture pour compléter les substitutions précédentes, comme par exemple :
une référence arrière (back-reference) sur le Pattern évalué (ex. /images/$1.png)
une référence arrière sur la dernière règle RewriteCond dont l'évaluation était positive (ex. /images/%1.png)
Figure
6: Enchainement des règles de réécriture
une variable provenant d'une table de correspondance clef → valeur (ex. ${mapname:key|default})
Des tests additionnels à l'aide de la directive RewriteCond peuvent compléter les règles de réécriture. Cette directive permet également des tests sur des éléments non disponibles au niveau de la directive RewriteRule. Dans l'exemple précédent, la règle RewriteRule ne peut évaluer le nom du serveur (vhost.ciril.fr) ni les paramètres passés dans l'URL (param=zoo&test=yes). RewriteCond a accès, entre autre, à ces valeurs et permet de les évaluer. Les règles de réécriture sont également de la forme :
RewriteCond
TestString1 CondPattern1 [flags]
RewriteCond
TestString2 CondPattern2 [flags]
RewriteRule
Pattern0 Substitution [flags]
La Figure 6 illustre l'évaluation et l'enchainement de règles RewriteRule et RewriteCond.
Figure
7: Références arrières $ et %
La Figure 7, ci-contre, illustre le « parenthésage » des Pattern et la création automatique des références arrières associées. Il est également précisé où sont utilisables les différentes références arrières.
Cet article n'ira pas plus loin dans les explications des réécritures Apache. Le lecteur pourra se reporter aux excellentes documentations sur le sujet : http://httpd.apache.org/docs/2.2/rewrite/. Pour illustrer la puissance de mod_rewrite rien ne vaut quelques exemples concrets.
Comment remettre dans la portée du site web une page qui a bougé sur le système de fichier ?
RewriteRule /doc/doc.html /chemin/ancien/site/vieille-doc.html
Comment cacher un script ou le passage de paramètres derrière une « belle » URL ?
RewriteRule
/graph-renater
/cgi-bin/graph-rrd.cgi?file=renater.rrd
RewriteRule
/([edit|view])/article([0-9]+)
/cgi-bin/wiki.php?action=$1&article=$2
Comment servir une page spéciale en fonction du navigateur du client ?
RewriteCond
%{HTTP_USER_AGENT} (Firefox) [OR]
RewriteCond
%{HTTP_USER_AGENT} (Safari)
RewriteRule /foo.html
/navigateurs-OK/%1/foo.html [L]
RewriteRule
/foo.html /navigateurs-indesirables/foo.html
Comment faire une redirection (code HTTP 3xx) vers un site web extérieur ?
RewriteRule /vers-google http://www.google.fr [R]
Comment donner accès automatiquement à une page sous arborescence du type AAAA-MM-JJ depuis une URL invariable ?
RewriteRule /doc-du-jour /vers/arbo/%{TIME_YEAR}-%{TIME_MON}-%{TIME_DAY}/doc
Comment afficher une image spéciale sur le site est accédé en IPv6 ?
RewriteCond
%{SERVER_ADDR} [:]+
RewriteRule /images/proto.png
/images/proto-ipv6.png [L]
RewriteRule /images/proto.png
/images/proto-ipv4.png
Comment servir des pages différentes en fonction de l'heure de consultation du site ?
RewriteCond
%{TIME_HOUR}%{TIME_MIN} >0800
RewriteCond
%{TIME_HOUR}%{TIME_MIN} <1800
RewriteRule /dispo
/on-travaille.html [L]
RewriteRule /dispo
/on-travaille-pas.html
Comment refuser l'accès à certaines ressources si le client n'est pas authentifié ?
RewriteCond
%{REMOTE_USER} ![a-z0-9]+ [nocase]
RewriteRule
/doc-interne - [forbidden]
De nombreux autres exemples très utiles sont documentés sur les pages :
http://httpd.apache.org/docs/2.2/rewrite/rewrite_guide.html
http://httpd.apache.org/docs/2.2/rewrite/rewrite_guide_advanced.html
Se lancer dans mod_perl peut, au début, être très déroutant. En effet, il n'est pas toujours évident de comprendre l'utilité et le fonctionnement de ce module qui est très différent des modules « classiques » disponibles avec Apache. Pour bien appréhender le sujet, un développeur devrait déjà se pencher sur le fonctionnement interne d'Apache. Il lui sera plus facile de faire le parallèle avec les possibilités de mod_perl. La suite de cet article s'appuie sur le chapitre 2 qui a traité en détails du fonctionnement interne d'Apache.
La réponse à la question « c'est quoi mod_perl ? » pourrait être :
« mod_perl est une subtile association de la flexibilité et de la simplicité du langage Perl avec la puissance du serveur web Apache. Ce module permet de faire énormément de choses, mais le plus intéressant est sa capacité à s'intégrer à l'architecture d'Apache en ayant accès à toutes les phases du cycle de vie d'une requête pour pouvoir dérouter et modifier le fonctionnement « normal » d'Apache. Avec mod_perl, il est possible d'écrire des modules « Apache en Perl » qui compléteront ou remplaceront les modules standards. Une fois que le développeur a compris où il est possible d'interagir, il n'y a plus de limite à l'imagination pour reprogrammer le comportement d'Apache. »1
Figure
8: Exemple de handler mod_perl
La Figure 8 illustre ce fonctionnement avec l'exemple d'une fonction Perl qui force la réécriture en minuscule de l'URL demandée. L'attachement de cette fonction sur le hook translate_name se fait dans le fichier de configuration httpd.conf via la directive PerlTransHandler MyApache::lcURI.
Figure
9: mod_perl et hooks cycle de vie serveur
La Figure 9 détaille l'utilisation par mod_perl des hooks du cycle de vie du serveur. A ce niveau seuls les hooks open_logs et post_config sont utilisés. Dans open_logs les tâches les plus communes sont l'initialisation et l'ouverture des fichiers de traces. C'est à cet endroit qu'une fonction ad'hoc devra être attachée si le développement mod_perl nécessite un fichier de trace spécifique. Le hook post_config est quant à lui placé juste après la lecture de la configuration et juste avant la création des fils Apache. C'est dans ce hook que le développeur va pouvoir initialiser un environnement qui sera disponible et partagé par l'ensemble des processus fils créés plus tard.
Figure
10: mod_perl et hooks cycle de vie requête
mod_perl dévoile toutes ses possibilités dans le cycle de vie des processus fils et du traitement des requêtes. Quasiment la totalité des hooks proposés par Apache sont utilisés par mod_perl (Figure 10) ce qui permet d'intervenir à n'importe quelle étape de traitement des requêtes. Voici le détail de chaque hook et les possibilités d'extensions en Perl :
child_init est exécuté une seule fois à la création du processus fils, on y trouve la création et l'initialisation de structures de données propres au processus en cours : pré-chargement de données, connexion vers une base de données, ...
pre_connection : à cette étape la connexion TCP est disponible mais aucun protocole (HTTP ou autre) n'a encore été décodé, il est donc possible d'appliquer des procédures, au plus tôt, sur la connexion TCP : par exemple refuser au plus tôt (avant décodage du protocole) les connexions depuis un sous-réseaux, positionner des paramètres spécifiques sur la socket, ...
process_connection : c'est dans ce hook que les modules de décodage des protocoles réalisent l'essentiel de leur tâche. L'implémentation et le support d'un nouveau protocole devra être codé ici.
post_read_request est exécuté juste après le décodage des entêtes HTTP et la création de la structure de données request. Les métadonnées de la requête sont disponibles et peuvent être utilisées.
translate_name est la phase de « manipulation » et de réécriture de l'URL demandée. Il est possible ici d'appliquer des règles de réécriture encore plus complexes que celles de mod_rewrite !
une fois l'URL « finale » disponible, le hook map_to_storage se charge de la traduction de l'URL vers le système de fichiers. Une fois encore, il est possible ici d'intervenir sur la ressource qui est demandée.
le rôle du hook header_parser est le traitement spécifique des entêtes HTTP, par exemple bloquer des useragents malveillants, refuser certaines méthodes HTTP, ...
access_checker, check_user_id et auth_checker constituent le triptyque « Authentification, Autorisation et contrôle d'Accès ». Il est possible de compléter ou de remplacer ici les méthodes AAA fournies en standard par Apache, comme par exemple autoriser ou non les connexions d'adresses IP en les vérifiant depuis une base de données, vérifier l'accès aux ressources, …
dans type_checker on retrouve les fonctions qui positionnent le type MIME de la réponse (en fonction de la requête)
fixups est la « dernière chance » de pouvoir intervenir sur la requête avant la génération du contenu de la réponse
c'est dans le hook handler que le contenu (corps et entêtes HTTP) de la réponse est construit. Les modules tels que mod_php ou HTML::Mason font l'essentiel de leur tâche ici. A ce niveau, la réponse reste entièrement modifiable...
il suffit de s'intégrer au hook log_translation pour une génération et un traitement spécifique des logs d'accès (par exemple logguer dans une base de données en complément des fichiers plats)
enfin, les hooks PerlChildExitHandler et PerlCleanupHandler qui n'existent pas réellement dans Apache (mais qui sont simulés par mod_perl) permettent un « nettoyage » spécifique des ressources à chaque cycle de vie (cleanup) ou à la fin de vie du fils (exit).
Figure
11: mod_perl et filtres Apache
La Figure 11 détaille l'implémentation mod_perl des filtres Apache. Les filtres disponibles ne peuvent s'appliquer qu'aux niveaux suivants :
filtre de protocole : dans mod_perl, la fonction implémentant le filtre sera déclarée de type FilterConnectionHandler
filtre de contenu : dans ce cas la fonction Perl associée sera de type FilterRequestHandler
Le code suivant présente un exemple de filtre de contenu (FilterRequestHandler) en sortie de traitement de la requête (PerlOutputFilterHandler). La totalité des données de la réponse passe par ce filtre qui va, au fil de l'eau, transformer tous les caractères en minuscule.
/*
httpd.conf /
PerlOutputFilterHandler
MyFilter::lowercase_all
/* MyFilter::lowercase_all */
sub
handler : FilterRequestHandler {
my $f = shift;
unless ($f->ctx) {
$f->r->headers_out->unset('Content-Length');
$f->ctx(1);
}
while ($f->read(my $data)) {
my $lowercase = lc( $data );
$f->print( $lowercase );
}
return Apache2::Const::OK;
}
L'utilisation des filtres est extrêmement puissante mais l'implémentation nécessite une bonne compréhension de quelques autres concepts (les Bucket Brigade, l'enchainement des filtres, …) et une convention d'écriture pour s'intégrer aux autres filtres disponibles en standard dans Apache. Le document suivant détaille ces points : http://perl.apache.org/docs/2.0/user/handlers/filters.html.
La transposition par mod_perl des possibilités offertes par Apache doit être maintenant comprise. Cet article est loin d'être exhaustif sur le sujet mais les bases du fonctionnement ont toutes été présentées ici. Un développeur Perl a maintenant à sa disposition un ensemble d'outils lui permettant d'interagir avec le fonctionnement « normal » d'Apache pour l'adapter à ses besoins. Avec mod_perl, la résolution d'un problème peut trouver plusieurs solutions. Le plus important est que le développeur sache que «tout est possible » et qu'en suivant quelques « recettes de cuisine » il peut arriver rapidement et facilement à ses fins.
mod_perl est à la fois un complément très utile pour l'extension et l'administration d'Apache mais il est également une base de développement solide pour des plateformes de développement (par exemple HTML::Mason, Catalyst, …) ou des applications complexes (Request Tracker, OTRS, …).
Pendant longtemps, la façon la plus simple et la plus répandue de générer du contenu dynamique à travers un serveur web consistait en l'écriture de scripts CGI (Common Gateway Interface). Cette méthode réalise l'exécution d'un programme pour chaque requête et retourne le résultat (sortie standard) comme contenu. Ce mode de fonctionnement, qui convient encore parfaitement pour le traitement ponctuel de formulaires, présente des inconvénients majeurs pour le développement d'interface web dynamiques complexes (exécution systématique d'une nouvelle occurrence du script CGI, multiplications des scripts à écrire, intégration très faible avec le serveur, …).
Dans ce contexte et au vu des évolutions des technologies et frameworks du Web ces dernières années, le développement d'applications conséquentes nécessitait de nouveaux outils plus flexibles et mieux adaptés à ces nouveaux besoins.
A l'heure où la notoriété des langages est principalement évaluée à travers leur utilisation dans les technologies du Web, Perl a su proposer un grand nombre de librairies pour s'adapter à ces nouveaux usages. L'environnement de développement HTML::Mason est une illustration parfaite des possibilités offertes par l'intégration de Perl dans Apache au niveau de la gestion des contenus dynamiques.
Figure
12: Composants Mason
Ce concept peut paraître primaire et il pourrait être assimilé à de simples inclusions si il n'intégrait pas des fonctions avancées permettant au programmeur de contrôler de manière originale le flux d'exécution des composants.
Le notion d'héritage désigne ici la possibilité pour chaque élément de spécifier un composant « père ». Ce dernier sera systématiquement exécuté lors de l'appel du ou des composants qui en héritent. Lors d'une requête, Mason détermine le composant de base à appeler ainsi que l'ensemble de ses pères pour former la chaine d'exécution. Chaque composant hérite d'un père par défaut nommé « autohandler » se matérialisant par un composant du même nom situé dans le répertoire courant ou l'un des répertoires supérieurs. Ces inclusions automatiques peuvent permettre de gérer le rendu global d'un site mais aussi des phases d'initialisation communes à un sous ensemble de pages. Voici un exemple d'organisation illustrant ce principe d'héritage :
/ # répertoire racine de Mason
/comps/ # répertoire des composants internes (appelés par les composants externes)
/pages/ # répertoires des composants externes => pages accessibles
/pages/autohandler # handler par défaut de toutes les pages
# => rendu global + initialisation (db, ...)
/pages/private/ # répertoire avec restriction d'accès
/pages/private/autohandler # vérification des droits
# => @Ips, User, Horaires d'accès, ...
Parallèlement à cette notion d'héritage, Mason intègre un mécanisme nommé « dhandler » pour la gestion d'URL virtuelles qui ne correspondent pas directement à des composants présents sur le système de fichiers. Avec l'avènement d'AJAX et des interfaces REST (Representational State Transfer), la nécessité d'avoir un contrôle total sur les URL s'avère indispensable. Mason, à travers le concept de « default handler », offre une réponse simple et efficace qui peut servir de point de départ pour une réflexion de gestion dynamique des URL. Dés lors, on se rend compte que Mason n'est pas un simple moteur de « template » mais peut servir de base à la mise en oeuvre d'un framework de développement d'applications web. A titre d'exemple, l'ensemble des frameworks MVC reposent tous sur un système d'aiguillage des requêtes permettant de s'abstraire totalement de la structure physique des répertoires. Un service d'accès aux articles des JRES 2009 pourrait être imaginé comme décrit ci-dessous :
2009.jres.org/articles # Accès au listing complet des articles
2009.jres.org/articles/id_article # Présentation du résumé + liens vers vidéo,publication, ...
2009.jres.org/articles/pres/id_article # Accés aux diapositives de présentation
2009.jres.org/articles/videos/id_article # Accés à la vidéo de la présentation
2009.jres.org/articles/paper/id_article # Accès à la publication de l'article
Une autre solution consisterait évidemment à gérer l'ensemble de ces accès à travers une seule URL associée à des variables passées en paramètres comme cela serait le cas avec un script CGI (ex : 2009.jres.org/articles?id_article=85&type=paper). L'utilisation de ces paramètres peut s'avérer quelquefois complexe et nuit à la navigation.
La première solution, présentée ci-dessus, est en fait la base du principe des applications REST qui repose en partie sur l'utilisation d'URL distinctes pour l'adressage des ressources. REST va encore plus loin en proposant l'utilisation des méthodes standard du protocole HTTP (GET/POST/PUT/DELETE) pour implémenter les fonctions de manipulations des ressources (CRUD : Create/Read/Update/Delete). Beaucoup d'outils de développement répondent aujourd'hui directement à cette problématique. Mason permet, quant à lui, une réponse simple en comparaison de frameworks plus lourds à mettre en oeuvre :
/pages/articles/dhandler # 2009.jres.org/articles
# 2009.jres.org/articles/id_article
/pages/articles/pres/dhandler # 2009.jres.org/articles/pres/id_article
Dans l'environnement mod_perl, la variable globale « $r » est disponible partout dans le code. Cette variable fournit une API d'accès à la requête courante. L'environnement Mason met à disposition une seconde variable globale « $m », permettant entre autre, un contrôle avancé du flux d'exécution des composants. Les appels inter-composants illustrés par la Figure 12 peuvent également être réalisés en utilisant la méthode $m->comp(comp, args...).
La notion d'héritage dans Mason utilise la méthode $m->call_next pour permettre à un père de poursuivre le flux d'exécution à travers ses fils. L'exemple, déjà évoqué, d'un composant vérifiant des droits d'accès en fonction d'expressions régulières sur les fichiers accédés pourrait se traduire ainsi :
%# /pages/private/autohandler
<%perl>
my %authz = ( # Définition des autorisations
login1 => “/[paper|videos]/“,
login2 => “/[pres]/“,
);
my $user = $r->user(); # Récupération du login
if((not defined $user)||(not exists $authz{$user}){ # Vérif. authentification et existence droits
$m->clear_and_abort(401) # NOK => return code 401
}
$expr = $authz{$user}; # Récupération droits (expression régulière)
$rel_path = $r->path_info(); # Récupération du chemin
$m->clear_and_abort(403) if (not $rel_path =~ /$expr/); # Accès non autorisés => code 403
$m->call_next(); # Permet l'exécution du fils
</%perl>
Le flux d'exécution des composants présenté dans la Figure 13 illustre les capacités de Mason à répondre de manière simple et astucieuse à des problématiques variées. Ce schéma reprend les exemples précédents et met en évidence l'utilisation couplée des mécanismes d'héritage et de manipulation dynamique des URL pour la gestion d'accès restreints à des ressources.
Figure
13: Flux d'exécution de composants Mason
Cette brève présentation des concepts forts de Mason n'a pour but que de montrer son intérêt pour le développement d'applications web. Request Tracker (http://bestpractical.com/) est un des nombreux exemples qui témoigne de son utilisation dans des projets de grande envergure. Pour une présentation plus complète le lecteur se référera aux sites suivants : http://www.masonhq.com/, http://www.masonbook.com/.
Cet article vient de faire le point sur Apache, mod_rewrite, mod_perl et Mason qui constituent un ensemble d'outils très utiles et complémentaires pour le développement d'applications web « modernes » dans les modèles Web 2.0 et REST.
Dans le cadre de cet article, ces sujets n'ont malheureusement pas pu être plus approfondis (nous reviendrons ! 2). Néanmoins nous espérons que les bases du fonctionnement ont, elles, été correctement détaillées. Ceci est une invitation pour le lecteur à regarder maintenant de plus près tous ces outils pour le développement de ses sites web.
L'équipe réseau LOTHAIRE3 du CIRIL4, qui a en charge l'exploitation, l'administration et la supervision des réseaux lorrains, développe depuis de nombreuses années des interfaces et des applications web à destination de ses correspondants de sites. Les choix et les stratégies sont maintenant clairs et unifiés : toutes les applications doivent être accessibles depuis un navigateur web et elles doivent être implémentées à l'aide des technologies Web 2.0 et REST. Dans ce cadre, les outils utilisés sont bien évidement ceux (entre autres) présentés dans cet article. Après maintenant quelques années d'expériences et de recul, nous sommes de plus en plus convaincus de la pérennité de ces choix. La migration progressive des « anciennes » applications vers ces modèles « plus modernes » simplifie la compréhension du code et des architectures tout en facilitant le développement courant et à venir : « plus on avance, plus c'est facile d'avancer... ».
Depuis maintenant plus de deux ans, l'équipe réseau propose un portail web de réseaux lorrains et des services disponibles : http://reseau.ciril.fr. Ce portail qui unifie l'ensemble des interfaces web (non visibles par un visiteur n'ayant pas de compte CIRIL) est le résultat des migrations et des développements Apache/Perl/... de ces dernières années. Selon nous, la mise à disposition d'un tel portail aurait été très difficile, voir impossible, sans les outils et les concepts présentés dans cet article.
Merci Apache, merci Perl !
1Citation d'Alex, sous sa douche, le mardi 27 octobre 2009 vers 7h12, en pensant à la rédaction de cet article.
2 « I'll Be Back » - Terminator 1 - 1984.
3 http://www.lothaire.net
4 http://www.ciril.fr