[successivo] [precedente] [inizio] [fine] [indice generale] [indice analitico]
In precedenza, nei capitoli ##capitolo-http## e ##capitolo-server-web-apache##, è stato descritto il servizio HTTP, la configurazione di Apache e l'utilizzo di un cliente in grado di accedere a tale servizio. In questo capitolo si intende vedere in che modo si può organizzare il proprio servente HTTP in modo da renderlo interattivo attraverso l'uso dei programmi CGI.
HTTP (HyperText Transfer Protocol) è un protocollo cliente-servente progettato per gestire documenti ipertestuali e per permettere l'interazione con programmi, detti gateway, attraverso le specifiche CGI (Common Gateway Interface).
L'interfaccia CGI permette quindi di realizzare programmi che interagiscono con gli utenti attraverso il protocollo HTTP. La figura 15.1 illustra il meccanismo.
Figura 15.1. Schema del collegamento fisico e ideale tra le varie parti di una connessione HTTP-CGI. |
I programmi gateway, detti anche cgi-bin o più semplicemente CGI, possono essere realizzati con qualunque linguaggio, purché siano in grado di interagire attraverso le specifiche del protocollo CGI.
Nel capitolo ##capitolo-uri## è descritto in modo generale l'utilizzo degli indirizzi URI. Vale la pena di richiamare brevemente quei concetti per ciò che riguarda in particolare la gestione interattiva che si vuole descrivere in questo capitolo. Il formato di un URI potrebbe essere definito secondo lo schema seguente:
protocollo indirizzo_della_risorsa dati_aggiuntivi
Alcuni tipi di protocolli sono in grado di gestire dei dati aggiuntivi in coda all'indirizzo della risorsa. Nel caso del protocollo HTTP combinato con CGI, può trattarsi di richieste o di percorsi aggiuntivi.
protocollo indirizzo_della_risorsa ? richiesta
Quando un URI comprende anche una stringa di richiesta (query), questa viene distinta dall'indirizzo della risorsa attraverso un punto interrogativo.
L'utilizzo di una stringa di richiesta presume che la risorsa sia un programma in grado di utilizzare l'informazione contenuta in tale stringa. Segue un esempio banale di un URI contenente una richiesta.
http://www.brot.dg/cgi-bin/saluti.pl?buongiorno
protocollo indirizzo_della_risorsa percorso_aggiuntivo
Quando l'indirizzo della risorsa di un URI fa riferimento a un programma, questo può ricevere un'informazione aggiuntiva legata a un file o una directory particolare. Si ottiene questo aggiungendo l'indicazione del percorso che identifica questo file o questa directory. Segue un esempio banale di un URI, completo dell'indicazione di un percorso.
http://www.brot.dg/cgi-bin/elabora.pl/archivio.doc
Quando un simbolo di quelli non utilizzabili deve essere indicato ugualmente da qualche parte dell'URI, facendogli perdere il significato speciale che questo potrebbe avere altrimenti, si può convertire utilizzando la notazione % h h . La sigla h h rappresenta una coppia di cifre esadecimali. A questa regola fa eccezione lo spazio che viene codificato normalmente con il segno +, ma non in tutte le occasioni.
Generalmente, per gli indirizzi URI normali non c'è la necessità di preoccuparsi di questo problema, quindi, l'utilizzo di simboli particolari riguarda prettamente la costruzione delle richieste, come si vedrà meglio in seguito.
La tabella 15.1 mostra l'elenco di alcune corrispondenze tra simboli particolari e la codifica alternativa utilizzabile negli URI.
Carattere | Codifica |
% | %25 |
& | %26 |
+ | %2B |
/ | %2F |
= | %3D |
~ | %7E |
Tabella 15.1. Alcune corrispondenze tra simboli particolari e codifica alternativa utilizzabile negli URI.
Il servente HTTP mostra ai clienti solo una parte dei dati contenuti all'interno del proprio sistema, e ciò attraverso una sorta di astrazione per cui, per esempio, http://www.brot.dg/ciao.html
non è il file ciao.html
che si trova nella directory radice del file system del nodo www.brot.dg.
L'organizzazione e l'accessibilità dei dati attraverso il protocollo HTTP può essere gestita in vario modo. Apache (il servente più comune) utilizza per questo il file /etc/apache/srm.conf
in cui vanno indicate, tra le altre, le direttive seguenti.
DocumentRoot directory_root_html
Rappresenta la directory da cui si possono diramare i documenti HTML. Se per esempio si trattasse della riga seguente,
DocumentRoot /home/httpd/html
e un cliente volesse accedere al documento http://www.brot.dg/ciao.html
, il file restituito effettivamente sarebbe /home/httpd/html/ciao.html
.
Alias directory_fasulla directory_reale
Questo tipo di direttiva, che può essere ripetuta, permette di definire delle directory in posizioni diverse da quelle reali. La directory fasulla fa riferimento a una directory indicata nell'indirizzo richiesto e quella reale indica la directory effettiva nel file system. Per esempio,
Alias /icons/ /home/httpd/icons/
fa in modo che l'indirizzo http://www.brot.dg/icons/
faccia in realtà riferimento alla directory /home/httpd/icons/
e non alla directory icons/
discendente da DocumentRoot.
ScriptAlias directory_fasulla directory_reale
Funziona come la direttiva Alias, ma si riferisce ai programmi CGI. Per esempio,
ScriptAlias /cgi-bin/ /home/httpd/cgi-bin/
fa in modo che l'indirizzo http://www.brot.dg/cgi-bin/
faccia in realtà riferimento alla directory /home/httpd/cgi-bin/
e non alla directory /cgi-bin/
discendente da DocumentRoot.
Il funzionamento del protocollo HTTP è molto semplice. L'utilizzo di un servizio HTTP si compone di una serie di transazioni, ognuna delle quali si articola in queste fasi:
apertura della connessione;
chiusura della connessione.
In questo modo, il servente non deve tenere traccia delle transazioni che iniziano e finiscono ogni volta che un utente compie un'azione attraverso il suo cliente.
La richiesta inviata dal cliente deve contenere il metodo (i più comuni sono GET e POST), l'indicazione della risorsa cui si vuole accedere, la versione del protocollo, ed eventualmente l'indicazione dei tipi di dati che possono essere gestiti dal cliente (si parla in questi casi di tipi MIME). Naturalmente sono possibili richieste più ricche di informazioni.
Tabella 15.2. Alcuni metodi di comunicazione per le richieste di un cliente.
La risposta del servente HTTP è costituita da un'intestazione che, tra le altre cose, specifica il modo in cui l'informazione allegata deve essere interpretata. È importante comprendere subito che l'intestazione viene staccata dall'inizio dell'informazione allegata attraverso un riga vuota, composta dalla sequenza <CR><LF>.
Per comprendere in pratica il funzionamento di una connessione HTTP, si può utilizzare il programma telnet al posto di un navigatore normale. Si suppone di poter accedere al nodo www.brot.dg nel quale è stato installato Apache con successo. Dal servente verrà prelevato il file index.html
che si trova all'interno della directory DocumentRoot.
$
telnet www.brot.dg http
[Invio]
telnet risponde e si mette in attesa di ricevere il messaggio da inviare al servente.
Trying 192.168.1.1... Connected to www.brot.dg. Escape character is '^]'.
Si deve iniziare a scrivere, cominciando con una riga contenente il metodo, la risorsa e la versione del protocollo, continuando con una riga contenente le possibilità di visualizzazione del cliente (i tipi MIME).
GET /index.html HTTP/1.0
[Invio]
Accept: text/html
[Invio]
[Invio]
Appena si invia una riga vuota, il servente intende che la richiesta sia terminata e risponde.
HTTP/1.1 200 OK Date: Tue, 27 Jan 1998 17:44:46 GMT Server: Apache/1.2.4 Last-Modified: Tue, 30 Dec 1997 21:07:24 GMT ETag: "6b003-792-34a9628c" Content-Length: 1938 Accept-Ranges: bytes Connection: close Content-Type: text/html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <HTML> <HEAD> <TITLE>Test Page for Linux's Apache Installation</TITLE> </HEAD> <!-- Background white, links blue (unvisited), navy (visited), red (active) --> <BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#000080" ALINK="#FF0000" > <H1 ALIGN="CENTER">It Worked!</H1> <P> If you can see this, it means that the installation of the <A HREF="http://www.apache.org/" >Apache</A> software on this Linux system was successful. You may now add content to this directory and replace this page. </P> ... ... </BODY> </HTML> Connection closed by foreign host.
Come già accennato, il messaggio restituito dal servente è composto da un'intestazione in cui l'informazione più importante è il tipo di messaggio allegato, cioè in questo caso Content-Type: text/html, seguita da una riga vuota, e quindi dall'oggetto richiesto, cioè il file index.html
.
Al termine della ricezione dell'oggetto richiesto, la connessione ha termine. Lo si può osservare dal messaggio dato da telnet: Connection closed by foreign host.
Il lavoro del cliente è tutto qui: inviare richieste al servente, ricevere le risposte e gestire i dati, possibilmente visualizzandoli o mettendo comunque l'utente in grado di fruirne.
MIME è una codifica standard per definire il trasferimento di documenti multimediali attraverso la rete. L'acronimo sta per Multipurpose Internet Mail Extentions e la sua origine è appunto legata ai trasferimenti di dati allegati ai messaggi di posta, come il nome lascia intendere.
Il protocollo HTTP utilizza lo stesso standard, e con questo il servente informa il cliente del tipo di oggetto che gli viene inviato. Nello stesso modo, il cliente, all'atto della richiesta di una risorsa, informa il servente dei tipi MIME che è in grado di gestire.
Il servente, per poter comunicare il tipo MIME al cliente, deve avere un modo per riconoscere la natura degli oggetti che costituiscono le risorse accessibili. Questo modo è dato dall'estensione, per cui, la stessa scelta dell'estensione per i file accessibili attraverso il protocollo HTTP è praticamente obbligatoria, ovvero, dipende dalla configurazione dei tipi MIME.
Tabella 15.3. Alcuni tipi MIME con le possibili estensioni.
Come si è visto dagli esempi mostrati precedentemente, la richiesta fatta dal cliente è composta da una prima riga in cui si dichiara il tipo, la risorsa desiderata e la versione del protocollo.
GET /index.html HTTP/1.0
Di seguito vengono indicati una serie di campi, più o meno facoltativi. Questi campi sono costituiti da un nome seguito da due punti (:), da uno spazio e dall'informazione che gli si vuole abbinare.
Una o più righe contenenti un campo Accept possono essere incluse per indicare i tipi MIME che il cliente è in grado di gestire (cioè di ricevere). Se non viene indicato alcun campo Accept, si intende che siano accettati almeno i tipi text/plain e text/html.
I tipi MIME sono organizzati attraverso due parole chiave separate da una barra obliqua. In pratica si distingue un tipo e un sottotipo MIME. È possibile indicare un gruppo di tipi MIME mettendo un asterisco al posto di una o di entrambe le parole chiave, in modo da selezionare tutto il gruppo relativo. Per esempio,
Accept: */*
rappresenta tutti i tipi MIME;
Accept: text/*
rappresenta tutti i sottotipi MIME che appartengono al tipo text; mentre
Accept: audio/basic
rappresenta un tipo e un sottotipo MIME particolare.
Il campo User-Agent permette di informare il servente sul nome e sulla versione dell'applicativo particolare che svolge la funzione di cliente. Per convenzione, il nome di questo è seguito da una barra obliqua e dal numero della versione. Tutto quello che dovesse seguire sono solo informazioni addizionali per le quali non è stabilita una forma precisa. Per esempio, nel caso di Netscape, si potrebbe avere un'indicazione del tipo seguente:
User-Agent: Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i586)
La risposta del servente a una richiesta del cliente si compone di un'intestazione seguita eventualmente da un allegato, che costituisce la risorsa a cui il cliente voleva accedere. L'intestazione è separata dall'allegato da una riga vuota.
La prima riga è costituita dal codice di stato della risposta. Nella migliore delle ipotesi dovrebbe presentarsi come nell'esempio seguente:
HTTP/1.0 200 OK
Il resto dell'intestazione è composto da campi, simili a quelli utilizzati per le richieste dei clienti.
Tabella 15.4. Alcuni codici di stato utilizzati più frequentemente.
Il campo Allow viene utilizzato dal servente per informare il cliente dei metodi che possono essere utilizzati. Viene restituita tale informazione quando il cliente tenta di utilizzare un metodo di richiesta che il servente non è in grado di gestire. Segue un esempio.
Allow: GET, HEAD, POST
Il campo Content-Length indica al cliente la dimensione (in byte) dell'allegato. Se viene utilizzato il metodo HEAD, con cui non viene restituito alcun allegato, permette di conoscere in anticipo la dimensione della risorsa.
Content-Length: 1938
Il campo Content-Type indica al cliente il tipo MIME a cui appartiene la risorsa (allegata o meno). Segue l'esempio più comune.
Content-Type: text/html
Il tipo di comunicazione che avviene tra cliente e servente, descritta nelle sezioni precedenti, è nascosta all'utente, il quale agisce attraverso la richiesta e l'invio di documenti HTML.
Si distinguono tre tipi di definizioni da inserire all'interno di documenti HTML che permettono all'utente di inserire dati (nel senso di input):
marcatore ISINDEX;
attributo ISMAP delle immagini;
moduli FORM.
Quando un documento HTML contiene il marcatore (o tag) ISINDEX, il programma cliente fa apparire, in corrispondenza di questo, una richiesta di inserimento di un testo. La figura 15.2 mostra ciò che potrebbe apparire con un comune navigatore.
Figura 15.2. L'effetto della presenza di un marcatore ISINDEX all'interno di un documento HTML. |
Si tratta di una forma antiquata di interazione tra l'utente e il servizio HTTP, ma tuttora utile per comprendere i meccanismi più complessi che di fatto vengono utilizzati.
L'utente inserisce quello che vuole all'interno del campo che gli viene messo a disposizione e quando lo sottopone (di solito si tratta di premere il tasto [Invio]), il programma cliente (cioè il navigatore) converte i caratteri che necessitano di conversione, quindi invia una richiesta GET per lo stesso documento, seguito da una stringa di richiesta (preceduta dal solito punto interrogativo) ottenuta da quanto l'utente aveva inserito.
Un marcatore di riferimento a un file di immagine può contenere l'attributo ISMAP: <IMG SRC="..." ISMAP>. Se il marcatore dell'immagine è contenuto a sua volta in un riferimento a una risorsa, attraverso l'uso del mouse, facendo clic in una posizione qualunque dell'immagine che appare, si inviano le coordinate relative all'indirizzo indicato.
L'esempio seguente mostra il riferimento a un'immagine, racchiuso all'interno di un riferimento a un programma CGI in grado di gestire le coordinate.
<A HREF="http://www.brot.dg/cgi-bin/coordinate.pl"> <IMG SRC="http://www.brot.dg/immagini/punta.gif ISMAP> </A>
Facendo un clic sull'immagine punta.gif
mostrata dal programma cliente all'utente, vengono inviate le coordinate attraverso una richiesta GET all'indirizzo della risorsa coordinate.pl. Questo indirizzo risulterà essere seguito da una stringa di richiesta (preceduta dal punto interrogativo) composta da due numeri interi, staccati da una virgola, che rappresentano rispettivamente le coordinate x e y .
I moduli FORM nei documenti HTML sono il modo più complesso e completo per permettere a un utente di interagire con un servizio. A differenza di quanto visto in precedenza, si consente l'inserimento di molte informazioni che poi vengono trasmesse nella forma nome = valore . I dati inseriti attraverso i FORM possono essere trasmessi con una richiesta GET oppure POST, attraverso l'indicazione opportuna all'interno dello stesso documento HTML che contiene il modulo.
La descrizione di questi moduli FORM verrà fatta più avanti, dopo gli esempi che servono a mostrare i meccanismi elementari di comunicazione dati relativi a ISINDEX e ISMAP.
I programmi gateway, o CGI, vengono visti dai cliente come delle risorse normali. Alla chiamata, tali programmi restituiscono, attraverso il servente, un documento HTML.
I programmi gateway generano questo output e lo emettono attraverso lo standard output che viene intercettato dal servente che a sua volta lo completa inizialmente del codice di stato.
In pratica, un programma del genere riceve input in qualche modo attraverso il servente, che a sua volta ha ricevuto una richiesta da un cliente, quindi restituisce un documento HTML preceduto da un'intestazione, ma senza la riga di stato.
Un programma CGI banale, potrebbe essere quello che restituisce semplicemente un messaggio formattato in HTML, ogni volta che viene eseguito.
#!/bin/sh echo "Content-type: text/html" echo echo "<HTML>" echo "<HEAD>" echo "<TITLE>Programma CGI banale</TITLE>" echo "</HEAD>" echo "<BODY>" echo "<H1>Programma CGI banale</H1>" echo "<P>" echo "Ciao Mondo!" echo "</P>" echo "</BODY>" echo "</HTML>"
Supponendo di avere chiamato questo programma cgi-banale.sh, che sia stato reso eseguibile, e che si trovi nella directory definita attraverso la direttiva ScriptAlias come /cgi-bin/
, si potrà accedervi aprendo l'URI http://.../cgi-bin/cgi-banale.sh
. Se si fa una prova con il proprio elaboratore, che funge simultaneamente da cliente e da servente, si potrebbe utilizzare l'URI http://localhost/cgi-bin/cgi-banale.sh
.
Figura 15.3. Risultato per l'utente della richiesta di accedere all'URI che punta allo script elementare (cgi-banale.sh) che produce solo un output semplice senza interpretare alcun input. |
Nelle sezioni precedenti si è visto in particolare il tipo di comunicazione che si instaura tra il programma cliente e il servente, mentre la comunicazione tra il servente e il programma gateway no.
Quando un cliente invia una richiesta di accedere a una risorsa che viene riconosciuta essere un programma gateway, il servente esegue questo programma e lo standard output di questo viene inviato in risposta al cliente, con l'aggiunta del codice di risultato iniziale: la preparazione del resto dell'intestazione è a carico del programma gateway.
Quando il servente esegue il programma gli può inviare alcuni dati: in forma di argomenti della riga di comando, utilizzando le variabili di ambiente e anche attraverso lo standard input. Dipende dalla modalità della richiesta fatta dal cliente il modo con cui il programma gateway riceverà i dati dal servente.
È sufficiente realizzare uno script in grado di restituire tutti i dati che vengono forniti dal servente al programma gateway per comprendere il meccanismo.
#!/bin/sh # # cgi-test.sh echo "Content-type: text/html" echo echo "<HTML>" echo "<HEAD>" echo "<TITLE>Test CGI</TITLE>" echo "</HEAD>" echo "<BODY>\n"; echo "<H1>Test CGI</H1>" echo "<PRE>" echo "N. argomenti = $#" echo "Argomenti = $*" echo echo "SERVER_SOFTWARE = $SERVER_SOFTWARE" echo "SERVER_NAME = $SERVER_NAME" echo "GATEWAY_INTERFACE = $GATEWAY_INTERFACE" echo "SERVER_PROTOCOL = $SERVER_PROTOCOL" echo "SERVER_PORT = $SERVER_PORT" echo "SERVER_ADMIN = $SERVER_ADMIN" echo "REQUEST_METHOD = $REQUEST_METHOD" echo "HTTP_ACCEPT = $HTTP_ACCEPT" echo "HTTP_USER_AGENT = $HTTP_USER_AGENT" echo "HTTP_CONNECTION = $HTTP_CONNECTION" echo "PATH_INFO = $PATH_INFO" echo "PATH_TRANSLATED = $PATH_TRANSLATED" echo "SCRIPT_NAME = $SCRIPT_NAME" echo "QUERY_STRING = $QUERY_STRING" echo "REMOTE_HOST = $REMOTE_HOST" echo "REMOTE_ADDR = $REMOTE_ADDR" echo "REMOTE_USER = $REMOTE_USER" echo "AUTH_TYPE = $AUTH_TYPE" echo "CONTENT_TYPE = $CONTENT_TYPE" echo "CONTENT_LENGTH = $CONTENT_LENGTH" echo echo "Standard input:" cat echo "</PRE>" echo "</BODY>" echo "</HTML>"
Figura 15.4. Richiamando lo script cgi-test.sh attraverso un URI, senza l'indicazione di alcuna stringa di richiesta, si ottiene lo stato delle variabili di ambiente fornite allo script stesso. |
Eventualmente si può realizzare un altro programma, in Perl, che compie praticamente le stesse operazioni, ma in modo più preciso.
#!/usr/bin/perl # # cgi-test.pl print "Content-type: text/html\n"; print "\n"; print "<HTML>\n"; print "<HEAD>\n"; print "<TITLE>Test CGI</TITLE>\n"; print "</HEAD>\n"; print "<BODY>\n"; print "<H1>Test CGI</H1>\n"; print "<PRE>\n"; print "N. argomenti = $#ARGV\n"; print "Argomenti = @ARGV\n"; print "\n"; foreach $var_amb (keys %ENV) { print "$var_amb = $ENV{$var_amb}\n"; } print "\n"; print "Standard input:"; while ( $riga = <STDIN> ) { print "$riga"; } print "</PRE>\n"; print "</BODY>\n"; print "</HTML>\n";
Le forme più semplici attraverso cui un utente può dare un input a un programma gateway sono: i percorsi aggiuntivi, i marcatori ISINDEX e gli attributi ISMAP delle immagini.
Il percorso aggiuntivo, tra tutti, è il concetto più semplice, anche se raramente se ne incontra l'utilizzo. Si ottiene richiedendo un URI che punta a un programma gateway seguito immediatamente, e senza separazioni addizionali, da un percorso che indichi un file o una directory. Il programma gateway riceve questa informazione all'interno di variabili di ambiente.
Per verificarlo basta usare uno dei due script mostrati nella sezione precedente. Si può anche tentare di raggiungere un percorso che non esiste. Supponendo di indicare l'URI http://.../cgi-bin/cgi-test.sh/ciao/come/stai
, lo script riceverà (e mostrerà) la variabile di ambiente PATH_INFO con il valore /ciao/come/stai
, mentre la variabile PATH_TRANSLATED conterrà la (presunta) traduzione di quel percorso in un percorso reale, corrispondente probabilmente a DocumentRoot /ciao/come/stai
. Sta quindi al programma (o allo script) gateway sapere cosa farsene di questa informazione.
Un'altra forma di input elementare, ormai in disuso, è il marcatore ISINDEX. Per comprendere di cosa si tratta basta modificare leggermente uno dei due script di analisi preparati nella sezione precedente. Viene mostrato il caso dello script di shell.
#!/bin/sh # # cgi-test2.sh echo "Content-type: text/html" echo echo "<HTML>" echo "<HEAD>" echo "<TITLE>Test CGI</TITLE>" echo "</HEAD>" echo "<BODY>" echo "<H1>Test CGI</H1>" echo "<PRE>" echo "N. argomenti = $#" echo "Argomenti = $*" ... #Viene inviato un marcatore ISINDEX. echo "<ISINDEX>" echo "</PRE>" echo "</BODY>" echo "</HTML>"
In corrispondenza del marcatore ISINDEX, il programma cliente mostrerà un campo modificabile dall'utente, come appare nella figura 15.2 già mostrata in precedenza. Per esempio, si può provare a scrivere la frase uno due tre, premere [Invio] e vedere cosa succede (si immagina che lo script si chiami cgi-test2.sh).
Gli spazi vengono trasformati con il segno + e il testo corrispondente viene accodato all'URI (dopo l'aggiunta di un punto interrogativo): http://.../cgi-bin/cgi-test2.sh?uno+due+tre
. Per questo URI, completato della stringa codificata, il cliente esegue una richiesta GET.
Il programma gateway riceve questa informazione attraverso la variabile di ambiente QUERY_STRING, che conterrà uno+due+tre, e anche attraverso gli argomenti della riga di comando, dove le tre parole corrispondono ad altrettanti argomenti separati.
L'ultimo, tra i tipi di input descritti in questa sezione, è quello ottenuto attraverso l'attributo ISMAP delle immagini. Per comprendere di cosa si tratta, basta modificare leggermente uno dei due script di analisi preparati nella sezione precedente. Viene mostrato il caso dello script di shell.
#!/bin/sh # # cgi-test3.sh echo "Content-type: text/html" echo echo "<HTML>" echo "<HEAD>" echo "<TITLE>Test CGI</TITLE>" echo "</HEAD>" echo "<BODY>" echo "<H1>Test CGI</H1>" echo "<PRE>" echo "N. argomenti = $#" echo "Argomenti = $*" ... #Viene mostrata un'immagine con attributo ISMAP. echo "<A HREF=\"/cgi-bin/cgi-test3.sh\">" echo " <IMG SRC=\"/test.jpg\" ISMAP>" echo "</A>" echo "</PRE>" echo "</BODY>" echo "</HTML>"
Per vedere funzionare questo esempio occorre anche un file di immagine, test.jpg
, da collocare nella directory di inizio dei documenti HTML, ovvero DocumentRoot.
Basta fare un clic con il mouse, da qualche parte sull'immagine, perché il programma cliente calcoli le coordinate corrispondenti, espresse in pixel, e le attacchi in coda all'URI. Per esempio, l'URI http://.../cgi-bin/cgi-test3.sh?10,15
rappresenta un clic eseguito nel punto x =10, y =15.
Il programma (lo script) cgi-test3.sh riceve questa informazione attraverso la riga di comando e anche attraverso il contenuto della variabile QUERY_STRING.
Si è già accennato ai moduli FORM HTML. Fino a questo punto si sono viste tecniche elementari per permettere l'interazione tra l'utente e un servizio HTTP. In particolare, il campo ISINDEX è praticamente del tutto inutilizzato. La vera interazione avviene con modelli HTML complessi, basati sui moduli FORM. Un particolare da osservare, prima di affrontare questo nuovo argomento, è il fatto che tutti i tipi di interazione visti finora sono basati su richieste che utilizzano il metodo GET.
I moduli FORM servono a generare degli elementi di input, che permettono quindi all'utente di inserire un certo tipo di dati. L'input ottenuto in questo modo viene assemblato in coppie nome = valore . È poi compito del programma gateway disassemblare e interpretare tali informazioni.
I moduli FORM vengono generati dal programma cliente (cioè dal browser) in base alle direttive incontrate all'interno di un documento HTML. Ciò significa che l'apparenza di questi moduli può essere diversa a seconda del programma cliente utilizzato e del sistema operativo.
Il documento HTML contenente moduli di questo tipo, ovviamente, può essere stato predisposto nel servente come file normale, oppure può essere generato dinamicamente da un programma gateway.
Un modulo di questo tipo viene dichiarato e delimitato dall'elemento FORM, all'interno di un documento HTML:
<FORM ...> ... ... ... </FORM>
Un documento HTML può contenere più FORM, purché non annidati. Il marcatore FORM di apertura può contenere degli attributi che ne definiscono il comportamento generale, mentre all'interno della zona definita dall'elemento FORM si possono inserire altri elementi di vario genere, il cui scopo è quello di permettere all'utente un tipo particolare di interazione.
L'attributo ACTION dell'elemento FORM specifica l'URI a cui inviare i dati inseriti attraverso il modulo. Deve trattarsi evidentemente dell'indirizzo di un programma gateway in grado di gestirli. Intuitivamente si comprende che questo attributo non può mancare. L'esempio seguente mostra in che modo si possa inserire questo attributo.
<FORM ACTION="http://www.brot.dg/cgi-bin/mio_programma.pl ...>
L'attributo METHOD dell'elemento FORM specifica il metodo della richiesta che deve essere fatta dal cliente. Utilizzando un modulo FORM sono disponibili due tipi: GET e POST. L'esempio seguente mostra una situazione in cui si definisce l'utilizzo del metodo POST.
<FORM ACTION="http://www.brot.dg/cgi-bin/mio_programma.pl METHOD="POST">
All'interno dell'ambiente FORM, cioè della zona delimitata dai marcatori <FORM> e </FORM>, si può collocare sia testo normale che elementi specifici di questo ambiente. Si è ripetuto più volte che i dati inseriti attraverso questi elementi vengono assemblati in coppie nome = valore . Quello che manca da sapere è che tali coppie vengono unite successivamente attraverso il simbolo e-commerciale (&). Gli esempi proposti più avanti mostreranno meglio questo comportamento.
Esistono pochi tipi di elementi atti a permettere l'input all'interno dell'ambiente FORM. Questi cambiano il loro comportamento e l'apparenza a seconda degli attributi che gli vengono indicati. Il tipo di elemento più comune è INPUT.
<INPUT NAME=... TYPE=... ...>
Tutti gli elementi che permettono l'input hanno in comune l'attributo NAME che è obbligatorio. Le sezioni seguenti mostrano alcuni degli elementi utilizzabili in un modulo.
Si tratta di un elemento che consente l'inserimento di testo normale su una sola riga. Questo elemento non richiede l'indicazione del tipo, attraverso l'attributo TYPE.
SIZE= n
Permette di definire la dimensione in caratteri del campo che si vuole visualizzare.
MAXLENGTH= n
Permette di stabilire un limite massimo alla dimensione, in caratteri, del testo che si può immettere.
VALUE= x
Permette di definire un valore predefinito che appaia già all'interno del campo.
Inserisci il colore: <INPUT NAME="colore" SIZE=20 VALUE="giallo">
Visualizza un campo di 20 caratteri all'interno del quale l'utente deve scrivere il nome di un colore. Nel campo appare già la scritta giallo che può essere modificata o cancellata a piacimento.
Si tratta di un elemento che consente la scrittura di testo normale nascondendone l'inserimento, come avviene di solito quando si introducono le parole d'ordine.
Dal momento che, a parte l'oscuramento dell'input, il funzionamento è uguale a quello dei campi di input normali, si possono utilizzare anche gli stessi tipi di attributi.
Inserisci la password: <INPUT TYPE=password NAME="password-utente" SIZE=20>
Visualizza un campo di 20 caratteri all'interno del quale l'utente deve inserire la parola d'ordine richiesta.
Si tratta di un elemento che visualizza una casellina da barrare (casella di spunta). Queste caselline appaiono senza selezione in modo predefinito, a meno che venga utilizzato l'attributo CHECKED. Se la casellina risulta selezionata, viene generata la coppia nome = valore corrispondente, altrimenti no.
VALUE= x
Permette di definire un valore (o una stringa) da restituire nel caso in cui la casellina sia selezionata. Questo attributo è essenziale.
CHECKED
Questo attributo vale in quanto presente o meno. Se viene inserito nell'elemento, la casellina apparirà inizialmente selezionata.
Barrare la casella se si desidera ricevere propaganda: <INPUT TYPE=checkbox NAME="propaganda" VALUE="SI" CHECKED >
Visualizza una casellina già barrata inizialmente. Se viene lasciata così, selezionata, questo elemento genererà la coppia propaganda=SI.
Si tratta di un elemento che permette la selezione esclusiva di un pulsante all'interno di un gruppo. In pratica, selezionandone uno, si deselezionano gli altri.
Rispetto agli elementi visti in precedenza, questo richiede la presenza di più elementi dello stesso tipo, altrimenti non ci sarebbe da scegliere. Il collegamento che stabilisce che i pulsanti appartengono allo stesso gruppo viene definito dal nome che rimane uguale.
VALUE= x
Permette di definire un valore (o una stringa) da restituire nel caso in cui il bottone risulti selezionato. Questo attributo è essenziale.
CHECKED
Questo attributo vale in quanto presente o meno. Se viene inserito nell'elemento, il bottone apparirà inizialmente selezionato.
Selezionare il contenitore dell'elaboratore: <INPUT TYPE=radio NAME="case" VALUE="desktop" CHECKED> <INPUT TYPE=radio NAME="case" VALUE="tower"> <INPUT TYPE=radio NAME="case" VALUE="minitower">
Visualizza tre pulsanti, di cui il primo già selezionato, per la scelta di un tipo di contenitore. I tre bottoni sono collegati insieme perché hanno lo stesso valore associato all'attributo NAME.
Questo tipo di elemento visualizza un tasto contenente un'etichetta, e selezionandolo si ottiene l'invio dei dati contenuti nel modulo in cui si trova. L'etichetta che appare sul pulsante in modo predefinito dipende dal cliente, e potrebbe trattarsi di Submit o qualcosa del genere.
Questo elemento è diverso dagli altri in quanto non è previsto l'uso dell'attributo NAME. Infatti non viene generato alcun dato da questo, ma solo l'invio dei dati del FORM.
SRC= uri
Permette di indicare l'URI di un'immagine da utilizzare come pulsante.
VALUE= x
Permette di indicare un'etichetta alternativa a quella che verrebbe messa automaticamente dal programma cliente.
<INPUT TYPE=submit VALUE="Invia la richiesta">
Visualizza un tasto sul quale appare la scritta Invia la richiesta. Selezionandolo viene inviato il contenuto del modulo.
Si tratta di una sorta di tasto di invio (submit) che in più aggiunge le coordinate in cui si trovava il puntatore nel momento del clic. In un certo senso assomiglia anche all'elemento ISMAP descritto prima di affrontare i FORM.
SRC= uri
Permette di indicare l'URI dell'immagine da utilizzare come base. Questo attributo è obbligatorio data la natura dell'elemento.
<INPUT TYPE=image NAME="immagine" SRC="/immagine.jpg">
Visualizza l'immagine immagine.jpg
e se viene fatto un clic con il puntatore del mouse sulla sua superficie, vengono inviati i dati del modulo, e assieme a questi anche le coordinate relative all'immagine.
Questo tipo di elemento, a prima vista, non ha alcun senso: permette di inserire dei campi nascosti, cosa che genererà una coppia nome = valore fissa.
Si era detto, all'inizio di questo capitolo, che il protocollo HTTP non ha alcun controllo sullo stato delle transazioni, o meglio, ogni richiesta si conclude con una risposta. In questo modo, è compito del programma gateway mantenere il filo delle operazioni che si stanno svolgendo. Una delle tecniche con cui è possibile ottenere questo risultato è quella di restituire un modello contenente le informazioni già inserite con quelli precedenti.
Ci sono anche altre situazioni in cui i dati nascosti e predefiniti sono utili, ma per il momento è sufficiente tenere a mente che esiste la possibilità.
VALUE= x
Definisce il valore o la stringa nascosti. Questo argomento è obbligatorio per questo tipo di elemento.
<INPUT TYPE=hidden NAME="nominativo" VALUE="Tizio">
Fa in modo che il modulo contenga anche la coppia nominativo=Tizio che altrimenti, si suppone, renderebbe inutilizzabili gli altri dati inseriti dall'utente.
Questo elemento permette all'utente di inserire un testo su più righe. L'interruzione di riga, in questo caso, è fatta utilizzando la sequenza <CR><LF>. Questo particolare va tenuto presente in fase di programmazione, dal momento che gli ambienti Unix, e GNU/Linux in particolare, utilizzano l'interruzione di riga rappresentata con il solo carattere <LF>.
ROWS= n
Stabilisce il numero di righe dell'area di inserimento.
COLS= n
Stabilisce il numero di colonne dell'area di inserimento.
<TEXTAREA NAME="messaggio" ROWS=7 COLS=40 > CIAO! </TEXTAREA>
Visualizza un'area per l'inserimento di testo su più righe. L'area visibile ha la dimensione di sette righe per 40 colonne e contiene già il testo CIAO! che può essere modificato o sostituito con qualcos'altro.
L'elemento SELECT delimita un ambiente attraverso cui si definiscono una serie di scelte possibili, che normalmente appaiono in forma di menù a scomparsa. Per questo, oltre a SELECT si devono utilizzare una serie di elementi OPTION con cui si indicano tali scelte possibili. Va tenuto in considerazione che l'attributo NAME viene indicato nel marcatore di apertura dell'ambiente SELECT.
MULTIPLE
Questo attributo vale solo in quanto esistente o meno. Se presente, indica che sono ammissibili selezioni multiple, altrimenti è consentita la scelta di una sola voce.
VALUE= x
Definisce il valore (numero o stringa) da abbinare alla scelta eventuale. La stringa che appare all'utente è quella che segue il marcatore OPTION di apertura, e se mancasse l'attributo VALUE, sarebbe quella stessa stringa a essere restituita in abbinamento al nome definito nel marcatore SELECT.
SELECTED
La presenza di questo attributo definisce una selezione predefinita.
<SELECT NAME="codice-colori"> <OPTION VALUE=0 SELECTED>Nero <OPTION VALUE=1 >Marrone <OPTION VALUE=2 >Rosso <OPTION VALUE=3 >Arancio <OPTION VALUE=4 >Giallo <OPTION VALUE=5 >Verde <OPTION VALUE=6 >Blu <OPTION VALUE=7 >Viola <OPTION VALUE=8 >Grigio <OPTION VALUE=9 >Bianco </SELECT>
Presenta un menù di scelta a scomparsa per la selezione di un colore che poi viene convertito in un codice numerico corrispondente. Il nero, corrispondente allo zero, risulta predefinito.
Si è ripetuto più volte che esistono differenze nel modo con cui i programmi gateway ricevono le informazioni dal servente. Il modo fondamentale attraverso cui ciò viene controllato dal cliente, è la scelta del metodo della richiesta: GET o POST. Finora sono stati visti esempi che utilizzavano il metodo GET.
Quando un cliente invia una richiesta utilizzando il metodo GET appende all'URI tutte le informazioni aggiuntive necessarie. In pratica, l'URI stesso comprende l'informazione. Per convenzione, la richiesta è distinta dalla parte dell'URI che identifica la risorsa attraverso un punto interrogativo, come nell'esempio seguente, dove la parola ciao è l'informazione aggiuntiva che rappresenta l'input per il programma cgi-test.sh.
http://www.brot.dg/cgi-bin/cgi-test.sh?ciao
È già stato descritto in che modo debbano essere codificati i caratteri riservati, per fare sì che quanto ottenuto sia sempre un URI valido.
Per convenzione, se il testo della richiesta che segue il punto interrogativo contiene il simbolo = (senza alcuna trasformazione), si intende che si tratti di una richiesta proveniente da un modulo FORM, altrimenti da un semplice elemento ISINDEX oppure da un'immagine con l'attributo ISMAP.
In pratica, se sembra una richiesta ISINDEX perché non appare il segno di assegnamento (=) non protetto in alcun modo, il programma gateway riceverà la stringa di richiesta attraverso gli argomenti della riga di comando e anche la variabile di ambiente QUERY_STRING, altrimenti li riceverà solo attraverso la variabile QUERY_STRING.
In questa situazione, in presenza di una richiesta GET, il programma gateway può concentrarsi nell'analisi della sola variabile QUERY_STRING.
http://www.brot.dg/cgi-bin/cgi-test.sh?nome=Pinco&cognome=Pallino&sesso=M
L'URI mostrato sopra rappresenta una richiesta proveniente (presumibilmente) da un modulo FORM, per la presenza dei simboli di assegnamento. Come si può osservare, ogni coppia nome = valore è collegata alla successiva attraverso il simbolo e-commerciale (&).
Il metodo GET, in quanto aggiunge all'URI la stringa di richiesta, permette all'utente di controllare e di memorizzare il flusso di dati, per esempio attraverso un segnalibro (bookmark). In pratica, con la semplice memorizzazione dell'URI, l'utente può riprendere un'operazione di inserimento di dati, senza dover ricominciare tutto dall'inizio.
Lo svantaggio nell'utilizzo di tale metodo sta nel fatto che esiste un limite alla dimensione degli URI, e di conseguenza anche alla quantità di dati che gli si possono accodare.
Il metodo POST è stato progettato per porre rimedio ai limiti dell'altro metodo. Con questo, i dati dei FORM vengono inviati in modo separato dall'URI, e il gateway li riceve dal servente attraverso lo standard input. Il metodo POST è generalmente preferibile.
Si è fatto riferimento più volte alle variabili di ambiente e al loro ruolo nel sistema di comunicazione tra il servente e il programma gateway. Segue l'elenco di quelle più importanti.
SERVER_SOFTWARE
Il nome e la versione del software utilizzato come servente.
SERVER_NAME
SERVER_PROTOCOL
Il nome e la versione del protocollo utilizzato dal servente.
SERVER_PORT
Il numero della porta di comunicazione utilizzata dal servente.
GATEWAY_INTERFACE
Letteralmente, è l'interfaccia gateway, ovvero la versione del protocollo CGI utilizzato dal servente.
PATH_INFO
Quando l'URI contiene l'indicazione di un percorso aggiuntivo, questa variabile riceve quel percorso.
PATH_TRANSLATED
Questa variabile viene utilizzata assieme a PATH_INFO, per indicare il percorso reale nel file system che ospita il servente.
SCRIPT_NAME
La parte dell'URI che identifica il percorso del programma utilizzato come gateway.
REQUEST_METHOD
Il metodo della richiesta (GET, POST).
REMOTE_HOST
Il nome del cliente. Se il nome non è disponibile, si deve fare uso della variabile REMOTE_ADDR che contiene l'indirizzo IP.
REMOTE_ADDR
AUTH_TYPE
Contiene l'eventuale metodo di autenticazione.
REMOTE_USER
Il nome dell'utente se si utilizza l'autenticazione.
QUERY_STRING
Contiene la stringa di richiesta se si utilizza il metodo GET.
CONTENT_LENGTH
Contiene la dimensione in byte dei dati ricevuti dal cliente. Questa informazione è disponibile solo se si utilizza il metodo POST.
CONTENT_TYPE
Contiene la definizione del tipo di codifica dei dati ricevuti dal cliente e riguarda solo il metodo POST. La codifica più comune è application/x-www-form-urlencoded e significa che i dati sono stati codificati secondo lo standard utilizzato per il metodo GET: gli spazi sono convertiti in + e tutti i simboli speciali secondo la forma % h h , dove h h sono due cifre esadecimali.
Quando il cliente invia una richiesta al servente, prepara un'intestazione all'interno della quale possono essere inseriti diversi campi. Il contenuto di questi campi viene tradotto in altrettante variabili di ambiente il cui nome inizia per HTTP_ seguito dal nome del campo stesso. In particolare, i caratteri minuscoli sono convertiti in maiuscoli e i trattini sono sostituiti dal simbolo di sottolineatura. Seguono alcuni esempi.
HTTP_ACCEPT
Equivale al campo Accept.
HTTP_USER_AGENT
Equivale al campo User-Agent.
Prima di iniziare a pensare a dei programmi gateway concludenti, conviene verificare quando scritto attraverso i programmi di analisi mostrati in precedenza: cgi-test.sh oppure cgi-test.pl. Negli esempi verrà mostrato sempre il primo di questi due, anche se il migliore per queste cose sarebbe il secondo.
Si può realizzare una pagina HTML contenente dei FORM, come nell'esempio seguente, che si rifà a esempi visti in precedenza.
<!-- form-test.html --> <HTML> <HEAD> <TITLE>Verifica del funzionamento dei FORM</TITLE> </HEAD> <BODY> <FORM ACTION="/cgi-bin/cgi-test.sh" METHOD="GET"> <H2>Test di vari tipi di elementi di un FORM - metodo GET</H2> <INPUT TYPE=hidden NAME="nominativo" VALUE="Tizio"> <P>Inserisci il colore: <INPUT NAME="colore" SIZE=20 VALUE="giallo"> Inserisci la password: <INPUT TYPE=password NAME="password-utente" TYPE=password SIZE=20></P> <P>Barrare la casella se si desidera ricevere propaganda: <INPUT TYPE=checkbox NAME="propaganda" VALUE="SI" CHECKED > <P>Selezionare il contenitore dell'elaboratore: orizzontale <INPUT TYPE=radio NAME="case" VALUE="desktop" CHECKED> verticale <INPUT TYPE=radio NAME="case" VALUE="tower"> verticale ridotto<INPUT TYPE=radio NAME="case" VALUE="minitower"></P> <P>Scrivi qui due righe. <TEXTAREA NAME="messaggio" ROWS=3 COLS=40 ></TEXTAREA></P> <P>Selezionare il codice attraverso il colore: <SELECT NAME="codice-colori"> <OPTION VALUE=0 SELECTED>Nero <OPTION VALUE=1 >Marrone <OPTION VALUE=2 >Rosso <OPTION VALUE=3 >Arancio <OPTION VALUE=4 >Giallo <OPTION VALUE=5 >Verde <OPTION VALUE=6 >Blu <OPTION VALUE=7 >Viola <OPTION VALUE=8 >Grigio <OPTION VALUE=9 >Bianco </SELECT></P> <P><INPUT TYPE=image NAME="immagine" SRC="/test.jpg"> <INPUT TYPE=submit VALUE="Invia la richiesta con il metodo GET"></P> </FORM> <HR> <FORM ACTION="/cgi-bin/cgi-test.sh" METHOD="POST"> <H2>Test di vari tipi di elementi di un FORM - metodo POST</H2> <INPUT TYPE=hidden NAME="nominativo" VALUE="Tizio"> <P>Inserisci il colore: <INPUT NAME="colore" SIZE=20 VALUE="giallo"> Inserisci la password: <INPUT TYPE=password NAME="password-utente" TYPE=password SIZE=20></P> <P>Barrare la casella se si desidera ricevere propaganda: <INPUT TYPE=checkbox NAME="propaganda" VALUE="SI" CHECKED > <P>Selezionare il contenitore dell'elaboratore: orizzontale <INPUT TYPE=radio NAME="case" VALUE="desktop" CHECKED> verticale <INPUT TYPE=radio NAME="case" VALUE="tower"> verticale ridotto<INPUT TYPE=radio NAME="case" VALUE="minitower"></P> <P>Scrivi qui due righe. <TEXTAREA NAME="messaggio" ROWS=3 COLS=40 ></TEXTAREA></P> <P>Selezionare il codice attraverso il colore: <SELECT NAME="codice-colori"> <OPTION VALUE=0 SELECTED>Nero <OPTION VALUE=1 >Marrone <OPTION VALUE=2 >Rosso <OPTION VALUE=3 >Arancio <OPTION VALUE=4 >Giallo <OPTION VALUE=5 >Verde <OPTION VALUE=6 >Blu <OPTION VALUE=7 >Viola <OPTION VALUE=8 >Grigio <OPTION VALUE=9 >Bianco </SELECT></P> <P><INPUT TYPE=image NAME="immagine" SRC="/test.jpg"> <INPUT TYPE=submit VALUE="Invia la richiesta con il metodo POST"></P> </FORM> </BODY> </HTML>
Come si può vedere sono presenti due FORM indipendenti: il primo utilizza il metodo GET, il secondo invece il metodo POST. Entrambi i FORM richiamano il programma gateway /cgi-bin/cgi-test.sh
.
Figura 15.5. Richiamando il file HTML dell'esempio, |
Si può già provare così, anche senza modificare alcunché. Se si invia la richiesta attraverso il modulo che utilizza il metodo GET, si osserverà che la richiesta va a fare parte dell'URI del programma gateway, e di conseguenza viene inserita nella variabile QUERY_STRING. Altrimenti, con il metodo POST la richiesta apparirà solo dallo standard input. In entrambi i casi, dovrebbe risultare codificata nello stesso modo (codifica URI).
nominativo=Tizio&colore=giallo&password-utente=&propaganda=SI& case=desktop&messaggio=&codice-colori=0
Si può osservare in particolare la presenza della coppia nominativo=Tizio, inserita a titolo di esempio come campo nascosto, e costante. Se invece di inviare il modulo attraverso la selezione del tasto (submit) si utilizza l'immagine, si ottiene una stringa simile a quella seguente:
nominativo=Tizio&colore=giallo&password-utente=&propaganda=SI& case=desktop&messaggio=&codice-colori=0&immagine.x=60&immagine.y=28
A questo punto, il lettore dovrebbe provare per conto proprio a compilare i campi, a modificare le selezioni, in modo da prendere dimestichezza con l'effetto generato dai moduli FORM.
W3C, World Wide Web Consortium
1) L'uso del punto interrogativo rende la cosa intuitiva: la richiesta viene fatta attraverso un'interrogazione.
Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome servente_http_cgi.html
[successivo] [precedente] [inizio] [fine] [indice generale] [indice analitico]