| |||||
| © Perl Mongers Italia. Tutti i diritti riservati. | |||||
| |||||
Non è necessario, ma ricordiamo che Il Perl è il più diffuso linguaggio di scripting per l'amministrazione di sistemi Unix/Linux e di gran lunga il più utilizzato per le web application e Apache e il web server leader con oltre il 65% di installazioni sul totale dei web server installati nel mondo (fonte http://www.netcraft.com). | |||||
| |||||
In breve,
| |||||
| |||||
Nel primo caso tutti i moduli vengono linkati all'interno di un unico eseguibile rendendo necessaria la ricompilazione ad ogni modifica e/o aggiunta di moduli al server. Nella seconda modalità, detta anche DSO (Dinamyc Shared Object), il caricamento dei moduli avviene run-time col vantaggio che, oltre ad ottenere un eseguibile molto più piccolo, i moduli possono venire modificati, compilati e aggiunti senza dovere ricompilare e reinstallare il server Apache stesso ogni volta; inoltre con un'unica compilazione e installazione è possibile, a seconda delle necessità, avviare diverse istanze del server (ad esempio un "httpd" con %> httpd -l e vedere se tra la lista dei moduli ci sia anche la voce mod_so.c, il modulo Apache responsabile della gestione DSO Figura 1. Lista dei moduli compilati staticamente in
In tal caso, dopo esservi procurati l'ultima versione del %> tar -zxvf mod_perl-1.26.tar.gz
%> cd mod_perl-1.26
%> perl Makefile.PL \
USE_APXS=1 \
WITH_APXS=/path/to/apache_1.3.xx/bin/apxs \
EVERYTHING=1
%> make
%> make test
%> make install
Nota: Nelle distribuzioni linux RedHat (almeno fina alla 7.0) il tool "apxs" non è installato di default e occorre quindi installarlo manualmente tramite il pacchetto RPM apache-devel-1.3.xx.i386.rpm con il comando: %> rpm -i path/to/apache-devel-1.3.xx.i386.rpm Il pacchetto in questione si trova nel CD-ROM RedHat nella directory RedHat/RPMS Nel caso invece che l'Apache installato sulla macchina sia statico verifichiamo se è stato compilato anche il modulo Brevemente (ma si rimandano agli articoli dedicati ad Apache su Linux & C, nonche ai vari file README ed INSTALL presenti nella distribuzione per una descrizione più dettagliata) la maniera più veloce per compilare Apache in modalità dinamica è la seguente: %> tar -xzvf apache_1.3.xx.tar.gz
%> cd apache_1.3.xx
%> ./configure --prefix=/path/to/install/apache_1.3.xx \
--enable-shared=max \
--enable-module=<modulo aggiuntivo> \
--enable-shared=<modulo aggiuntivo>
%> make
%> make install
Con la direttiva "--enable-shared=max" abilitiamo il supporto DSO e compiliamo in modalità dinamica tutti i moduli standard. Con la coppia di direttive "--enable-module" e "--enable-shared" abbiamo poi la possibilità di compilare ed installare in modalità DSO altri utili moduli (compresi nella distribuzione ma non compilati di default) come il "mod_rewrite", "mod_usertrack", ecc Possiamo quindi compilare ed installare | |||||
| |||||
Il primo e forse maggior beneficio evidente dell'uso di Agli albori del Web, l'unico modo di creare applicazioni che generassero pagine dinamiche (ad eccezione delle Server Side Includes) era l'interfaccia CGI o Common Gateway Interface. Nel modello CGI, quando uno script Perl viene richiesto da un client, il server Web deve avviare l'interprete Perl, l'interprete quindi compila lo script, lo esegue e trasmette il risultato di nuovo al server che interrompe l'interprete e infine trasmette il risultato al client. La spesa di risorse (memoria e CPU) associata in questo modello è evidente se si considera il fatto che questo ciclo è ripetuto per ogni richiesta a quel determinato script. Il principale difetto di questo modello è la scarsa scalabilita. Supponiamo infatti che si stia usando il Perl per alcuni script CGI: come il numero di visite aumenta e l'applicazione da semplice script (o raccolta di script) di poche linee evolve ad una più seria applicazione di decine di migliaia di linee di codice per includere via via sempre piu caratteristiche, presto ci si accorgerà che le prestazioni degraderanno in maniera esponenziale. Ecco che allora Vediamo ora come | |||||
| |||||
Ogni modifica dello script non necessita del riavvio di Apache: ad ogni richiesta, <IfModule mod_perl.c>
PerlModule Apache::Registry
Alias /perl/ /usr/local/apache/cgi-bin/
<Location /perl>
SetHandler perl-script
PerlHandler Apache::Registry
Options +ExecCGI
PerlSendHeader On
PerlSetupEnv On
</Location>
</IfModule>
Vediamo in dettaglio cosa succede. Tutte le direttive sono all'interno del blocco <IfModule>: Apache infatti processerà tutte le direttive contenute solo se è presente il modulo Con Con la direttiva
Con
Esempio 1. test.pl, semplice #!/usr/local/bin/perl
use strict;
use vars qw($call_count $last_invocation_time);
print "Content-type: text/html\n\n";
print <<EOM;
<HEAD><TITLE>Registry/PerlRun/cgi-bin test</TITLE></HEAD>
<BODY>
<H1>Salve $ENV{REMOTE_ADDR}!</H1>
<PRE>
EOM
my @x;
my $time_now;
$call_count = 0 if ! defined $call_count;
$call_count++;
$time_now = time();
print "Realtime = ", $time_now, " seconds since epoch.\n";
if ( defined($last_invocation_time) ) {
print "Last time = ", $time_now - $last_invocation_time," seconds ago.\n";
}
$last_invocation_time = $time_now;
@x = times();
print <<EOM;
User CPU = $x[0]
System CPU = $x[1]
CallCount = $call_count
PID = $$
EOM
print "Parent PID = ", getppid(), "\n</PRE>\n</BODY>\n<HTML>";
exit;
Una volta riavviato Apache, non dovremo far altro che mettere lo script test.pl nella directory indicata dalla direttiva Figura 2. Output dello script test.pl
| |||||
| |||||
Una delle caratteristiche fondamentali dell'ambiente Apache/ Non vi sorprendete infatti se facendo il reload dello script test.pl l'output conterrà valori di volta in volta 'magicamente' incrementati di 1 accanto all'etichetta: 'call count' anche se nel lanciare lo script non passiamo alcun parametro e non facciamo alcun uso di tecniche di memorizzazione dello stato (tramite cookie o ID di sessione)! Le variabili use vars qw($call_count $last_invocation_time); e al termine dell'esecuzione dello script non vengono distrutte ma rimangono inizializzate col valore dell'ultima invocazione Questo potrebbe portare, sviluppando sotto Potrà sembrare una banalità, ma la migliore soluzione è sempre quella di scrivere un codice pulito: l'evitare l'uso di variabili globali e l'adozione del pragma "use strict" sono un buon punto di partenza. Il pragma "use strict" viene in nostro aiuto in quanto forza l'interprete Perl, in fase di compilazione e non di esecuzione, a generare un errore ogni qualvolta vengono incontrate variabili (o più in generale oggetti) globali che non siano stati esplicitamente dichiarati con | |||||
| |||||
Una tipica configurazione di httpd.conf è la seguente: <IfModule mod_perl.c>
PerlModule Apache::PerlRun
Alias /cgi-perl/ /usr/local/apache/cgi-bin/
<Location /cgi-perl>
SetHandler perl-script
PerlHandler Apache::PerlRun
Options +ExecCGI
PerlSendHeader On
PerlSetupEnv On
</Location>
</IfModule>
La configurazione è abbastanza simile alla precedente con la differenza che ora carichiamo il modulo Ricordiamo ancora una volta che la direttiva Subito ci si potrebbe chiedere perche utilizzare L'adozione di una 'pulita programmazione' rimane sempre la soluzione migliore, ma se volessimo subito beneficiare dell'aumento di prestazioni senza incorrere in questi problemi, il modulo | |||||
| |||||
Concludiamo questa puntata mostrando brevemente come Come semplice esempio illustriamo una configurazione dinamica che semplifica assai la configurazione di Apache in situazioni di mass virtual hosting: Esempio 2. Sezione di configurazione <Perl></Perl> all'interno di httpd.conf <Perl>
#!perl
$User = 'www';
$NameVirtualHost = "192.168.1.3";
my $base_web_dir = "/home/web";
my @domains = qw/oltrelinux.com superpatrizio.org modperl.it/;
foreach my $domain (@domains) {
push(@{$VirtualHost{$NameVirtualHost}},
{
ServerName => "www.$domain",
DocumentRoot => "$base_web_dir/$domain/htdocs",
ErrorLog => "$base_web_dir/$domain/logs/error_log",
CustomLog => "$base_web_dir/$domain/logs/access_log common",
ServerAdmin => "webmaster\@$domain",
ScriptAlias => "/cgi-bin \"$base_web_dir/$domain/cgi-bin\"",
Directory => {
"$base_web_dir/$domain/htdocs" => {
Options => 'Indexes FollowSymLinks',
AllowOverride => 'None',
Order => 'allow,deny',
Allow => 'from all'
},
"$base_web_dir/$domain/cgi-bin" => {
AllowOverride => 'None',
Options => 'None',
Order => 'allow,deny',
Allow => 'from all'
}
}
});
}
use Apache::PerlSections ();
Apache::PerlSections->store("/home/web/PerlServerConfig.pm");
__END__ </Perl> Subito notiamo come tutto il codice della sezione <Perl> sia nella forma: <Perl>
#!perl
...
__END__
</Perl>
Questo consente di effettuare un semplice test usando direttamente l'interprete Perl a linea di comando: %> perl -cx httpd.conf
httpd.conf syntax OK
dove lo switch Le prime due linee impostano le direttive "User" e "NameVirtualHost": in generale nella sezione <Perl> per far riferimento alle corrispondenti direttive di configurazione di Apache e necessario utilizzare variabili globali il cui spelling corrisponda esattamente. Le successive linee utilizzano due variabili locali che serviranno per la configurazione dinamica di tutti i virtual host: my $base_web_dir = "/home/web"; my @domains = qw/oltrelinux.com superpatrizio.org modperl.it/;
push(@{$VirtualHost{$NameVirtualHost}}, ...
Infatti tutte le sezioni racchiuse tra TAG, come <VirtualHost> o <Directory>, vanno mappate in un hash che nel nostro caso è $VirtualHost{'192.168.1.3'} = {
ServerName => 'dominio.com',
...
};
Nel nostro caso di virtual host name-based abbiamo il problema di avere valori dell'hash $VirtualHost{'192.168.1.3'} = [
{
ServerName => 'dominio-1.com',
...
},
{
ServerName => 'dominio-2.com',
...
}
];
Da notare che in questo esempio la directory definita in Tutto ciò può sembrare complesso ma se pensiamo ad una situazione di webhosting intensivo -ad esempio un centinaio di virtual host- ci accorgiamo che con sole 20 linee di codice Perl sia possibile configurare l'Apache risparmiandoci la fatica di dover scrivere e aggiornare centinaia e centinaia di linee di direttive! Infine nelle ultime due linee: use Apache::PerlSections ();
Apache::PerlSections->store("/home/web/serverconfig.pm");
viene caricato il modulo Concludiamo accennando al fatto di come sia possibile documentare la configurazione utilizzando il formato POD (Plain Old Documentation) all'interno della sezione <Perl> | |||||
| |||||
In questa puntata abbiamo visto come sia possibile includere un interprete Perl direttamente nel processo Apache rendendo l'esecuzione degli script Perl CGI estremamente veloce ottenendo prestazioni nettamente superiori (a volte di due ordini di grandezza). Infatti uno script Nella prossima puntata ci spingeremo oltre, illustrando come | |||||
| |||||
Ecco un elenco delle principali direttive di configurazione di Questa direttiva non è specifica di Carica e compila il modulo nome_modulo indicato. E' l'anologo di entrambi i comandi Perl: use nome_modulo; require nome_modulo; Il modulo viene cercato in tutti i path presenti nell'array Carica e compila ed esegue lo script indicato. E' l'anologo del comando Perl: require 'script_file'; A differenza di Le direttive Intercetta tutte le linee di intestazione generate dallo script (ad esempio Content-type text/html) e le riconverte in un corretto header HTTP/1.x allo stesso modo in cui lo fa Apache con gli script CGI tradizionali. Questo consente di lasciare inalterati i nostri script Perl CGI senza doverci preoccupare di formattare ed inviare un corretto header HTTP. Consente il settaggio di una variabile di ambiente disponibile all'interno dello script CGI. Imposta e passa tutte le variabili di ambiente tradizionali (cioè tutte le variabili Consente di passare la variabile di ambiente env_var agli script CGI Consente il refresh (caricamento e ricompilazione) di tutti i moduli
precedentemente caricati con il solo restart del server. Altrimenti è necessario
stoppare e riavviare il server affinché le modifiche ai moduli Consente di abilitare i warnings per tutto il codice Perl dei moduli Consente di attivare il taint check per tutto il codice Perl gestito da
Consente di passare informazioni dal file di configurazione di Apache al moduli
PerlSetVar base_dir /usr/local/my_dir Il valore contenuto in base_dir è poi recuperabile all'interno del modulo tramite chiamate ad opportuni metodi. | |||||
| |||||
| |||||
| |||||
| |||||
| |||||
Le seguenti convenzioni tipografiche sono stato utilizzate in questo articolo: Corsivo
Negli articoli ci sono molti esempi di codice Perl: alcuni sono solamente pezzi
di codice, altri invece programmi completi che possono essere individuati poiché
iniziano tutti con la linea #!/usr/bin/perl Tutti gli esempi che illustrano procedure a linea di comando usano %> perl -e 'print "Hello world\n"'
Hello word
Occasionalmente viene utilizzato #> perl -e 'print "Hello world\n"'
Hello word
| |||||