# Apache Rivet

### The Rivet Team

The Apache Software Foundation

`<rivet-dev@tcl.apache.org>`

Italian Translation: Fabio Zanotti

Italian Linux Documentation Project

`<zendune@virgilio.it>`

Copyright © 2002, 2003 Apache Software Foundation

Questo documento è anche disponibile nelle seguenti lingue: Inglese, Russo

Questo documento è basato sulla versione 1.27 dell'originale in inglese.

## Introduzione ad Apache Rivet

Apache Rivet è un sistema per la creazione di contenuti web dinamici mediante un linguaggio di programmazione integrato con il Web Server Apache . È progettato per essere veloce, potente ed estensibile, utilizza poche risorse, è facile da imparare e fornisce all'utente una piattaforma che può pure essere utilizzata con altri programmi per lavori da eseguire fuori dal web (GUI, compiti di amministrazione di sistema, elaboratori di testo, gestori di database, XML e così via). Per ottenere questi risultati, è stato scelto il linguaggio di programmazione Tcl da utilizzare unitamente al Web Server Apache.

Con questo manuale aspiriamo ad aiutarvi ad iniziare ed a farvi scrivere codice di produzione il più velocemente possibile, dandovi un'idea di come ottenere grandi vantaggi dall'architettura Rivet, finalizzati alla realizzazione di diverse tipologie di siti web.

Questa documentazione è un lavoro in corso e, come ogni cosa riguardante Apache Rivet, è Software Libero. Se vedete qualche sezione che necessita di miglioramenti ed avete idee o suggerimenti al riguardo, non esitate a farcelo sapere. Se volete contribuire direttamente, meglio ancora!

## Installazione di Apache Rivet

1. Verifica delle dipendenze

   Per installare Rivet, avete bisogno di Tcl 8.2 o superiore e Apache 1.3.xx. Può essere eseguito su Linux, FreeBSD, OpenBSD, Solaris e HPUX. È possibile utilizzarlo anche in Windows NT (per cortesia verificate le indicazioni nella distribuzione).

2. Procurarsi Rivet

   Si possono scaricare i sorgenti di Rivet da http://tcl.apache.org/rivet/download. Attualmente è il solo modo per ottenere Rivet. In futuro, contiamo di distribuirlo anche direttamente nei formati utilizzati da FreeBSD, Debian, Red Hat e windows.

3. Procurarsi ed installare i sorgenti Apache

   Rivet necessita di alcuni file include (.h) per essere costruito. Il modo più facile per ottenerli, è scaricare il codice sorgente dal server web di Apache, sebbene alcuni sistemi (Debian GNU/Linux per esempio) rendano disponibili per per l'installazione i file header ed altri file di sviluppo. Se intendete costruire Rivet staticamente (compilandolo nel server web Apache, invece di caricarlo dinamicamente), chiaramente necessitate dei sorgenti. Raccomandiamo di costruire Rivet con una libreria caricabile condivisa, per avere la massima flessibilità.

   Il codice sorgente del server web Apache può essere reperito al seguente link: http://httpd.apache.org/.

4. Decomprimere i sorgenti

   Assumiamo, a questo punto, che abbiate installato Apache. Dovrete decomprimere i sorgenti di Rivet nella directory dove vorrete compilarli.

       gunzip tcl-rivet-X.X.X.tar.gz
       tar -xvf tcl-rivet-X.X.X.tar.gz

5. Compilare Rivet

   Rivet usa un unico sistema di compilazione che abbiamo creato espressamente per questo progetto. Utilizza le informazioni incluse in Apache e Tcl, considerando le loro configurazioni, al fine di compilarlo tramite una serie di script Tcl, che sono ubicati nella directory `buildscripts/`.

   1. Modificare src/make.tcl

      Potrebbe essere necessario modificare a mano `src/make.tcl`, al fine di impostare alcune opzioni. Per prima cosa provate la prossima istruzione e vedete se ha successo.

   2. A questo punto, siete pronti ad eseguire la compilazione del sistema:

          cd src/
          ./make.tcl option

      dove `option` può essere shared (condivisa) o static (statica).

   3. Installazione

      Adesso siamo pronti ad eseguire il comando ./make.tcl install per installare i file risultanti. Questo dovrebbe copiare gli oggetti condivisi (come `mod_rivet.so`, se è stato creato con successo) nella directory di Apache `libexec`, come pure installare alcuni script di supporto e codice vario.

6. File di configurazione di Apache

   Rivet è relativamente facile da configurare, cominceremo aggiungendogli il modulo:

       LoadModule rivet_module	/usr/lib/apache/1.3/
       mod_rivet.so

   Questo informa Apache che deve caricare l'oggetto condiviso Rivet, in qualsiasi parte esso risieda sul vostro file system. Ora abbiamo informato Apache su quali file sono del tipo "Rivet" e come elaborarli:

       AddType application/x-httpd-rivet .rvt
       	  AddType application/x-rivet-tcl .tcl

   Questo informa Apache di elaborare i file con le estensioni `.rvt` e `.tcl` come file Rivet.

   Per altre direttive che Rivet fornisce per la configurazione di Apache, per cortesia, vedete la sezione chiamata “Direttive di Apache”.

## Direttive di Apache

Queste direttive sono utilizzate con i file di configurazione del server httpd di Apache per modificare il comportamento di Apache Rivet. Vi sono delle precedenze, come segue: RivetDirConf, RivetUserConf, RivetServerConf, questo significa che DirConf non terrà conto di UserConf, il quale a sua volta non terrà conto di ServerConf.

RivetServerConf (CacheSize | GlobalInitScript | ChildInitScript | ChildExitScript | BeforeScript | AfterScript | ErrorScript | UploadDirectory | UploadMaxSize | UploadFilesToVar | SeperateVirtualInterps)
  RivetServerConf specifica un opzione globale che è valida per l'intero server.
  ?CacheSize? ?`size`?
    Seleziona la dimensione della cache della pagina interna, dove `size` è il numero di pagine byte-compilate da essere memorizzate per un uso futuro. Il valore predefinito è MaxRequestsPerChild / 5, o 50, se MaxRequestsPerChild è 0.
  ?GlobalInitScript? ?`script`?
    Script Tcl che è eseguito quando ogni interprete viene inizializzato. `script` è uno script Tcl effettivo; così per eseguire un file, voi eseguireste:

        RivetServerConf GlobalInitScript "source /var/www/
        foobar.tcl"

  ?ChildInitScript? ?`script`?
    Lo script viene valutato quando ogni processo figlio di Apache è inizializzato. Questo è il posto raccomandato per caricare i moduli, creare le variabili globali, aprire le connessioni ad altre applicazioni (quali database) e così via.
  ?ChildExitScript? ?`script`?
    Lo script viene valutato quando ogni processo figlio di Apache termina. Questo è il posto più naturale dove ripulire le risorse create con ChildInitScript.
  ?BeforeScript? ?`script`?
    Lo script viene valutato prima che ogni server abbia fatto l'analisi della pagina (.rvt). Questo può essere utilizzato per creare un'intestazione standard, per ogni istanza. È anche possibile utilizzarlo per caricare codice di cui avete bisogno in ogni pagina, se non volete metterlo in un GlobalInitScript ChildInitScript quando siete al vostro primo sviluppo di un sito web.

    | Nota
    Questo codice è valutato globalmente e non all'interno del namespace di dove le pagine sono elaborate.

  ?AfterScript? ?`script`?
    Lo script viene chiamato dopo che ogni server ha analizzato la pagina (.rvt).
  ?ErrorScript? ?`script`?
    Quando Rivet incontra un errore in uno script, costruisce una pagina HTML con alcune informazioni circa l'errore e lo script che è stato valutato. Se è stato specificato un ErrorScript, è possibile creare pagine personalizzate di errore. Questo può essere vantaggioso se cercate di assicurarvi che nessun utente possa mai vedere il vostro codice sorgente.
  ?UploadDirectory? ?`directory`?
    Directory ove posizionare i file caricati.
  ?UploadMaxSize? ?`size`?
    Dimensione massima per i file caricati.
  ?UploadFilesToVar? (yes | no)
    Questa opzione controlla se è possibile caricare i file in una variabile Tcl. Se avete un limite alla dimensione e non potete usare file di grosse dimensioni, questa soluzione potrebbe essere più conveniente che inviare dati ad un file su disco.
  ?SeperateVirtualInterps? (yes | no)
    Se attivo, Rivet creerà un interprete Tcl separato per ogni host virtuale di Apache. Questo è utile in una situazione tipo ISP dove è desiderabile avere un interprete dedicato per ciascun client, cosicché, anche accidentalmente, non possano interferire tra loro.
RivetDirConf (BeforeScript | AfterScript | ErrorScript | UploadDirectory)
  Queste opzioni sono le stesse di RivetServerConf, ad eccezione che sono valide solo per la directory dove sono state specificate e relative sotto directory. Potranno essere dichiarate nelle sezioni Directory.
RivetUserConf (BeforeScript | AfterScript | ErrorScript | UploadDirectory)
  Queste opzioni sono le stesse di RivetServerConf, ad eccezione che sono valide solo per la directory dove sono state specificate e relative sotto directory.

## Comandi e variabili Tcl di Rivet

var (get | list | exists | number | all)
  Il comando var recupera le informazioni circa le variabili GET o POST, inviando lo script tramite una richiesta del client. Il trattamento di entrambe le variabili GET e POST è identico, in considerazione delle loro origini. Notate che vi sono due forme aggiuntive di var: var_qs e var_post. Queste due forme restringono le informazioni sui parametri ottenendo rispettivamente la querystring (?foo=bar&bee=bop) o la POSTing.
  ?get? ?`varname`? ?`?default?`?
    Ritorna il valore della variabile `varname` come una stringa (anche se vi sono valori multipli). Se non esiste come variabile GET o POST, viene restituito il valore `?default?`, altrimenti viene ritornato "" (una stringa vuota).
  ?list? ?`varname`?
    Restituisce il valore della variabile `varname` come una lista, se vi sono valori multipli.
  ?exists? ?`varname`?
    Restituisce 1 se `varname` esiste, 0 se non lo è.
  ?number?
    Restituisce il numero di variabili.
  ?all?
    Restituisce una lista di nomi di variabili e valori.
  Vedete Esempio 3, “Accesso alle variabili”.

upload (channel | save | data | exists | size | type | filename)
  Il comando upload è usato per la manipolazione del caricamento dei file. Vedete le principali direttive di Apache per altri tipi di configurazioni del funzionamento di questa caratteristica di Rivet.
  ?channel? ?`uploadname`?
    Quando date il nome ad un file caricato, `uploadname` restituisce un canale Tcl che può essere usato per accedere allo stesso file.
  ?save? ?`uploadname`? ?`filename`?
    Salva `uploadname` nel file `filename`.
  ?data? ?`uploadname`?
    Restituisce i dati caricati dal server. Questo è il binario pulito. In altre parole, potrà lavorare anche con file come immagini, eseguibili, compressi e così via.
  ?size? ?`uploadname`?
    Restituisce la dimensione del file caricato.
  ?type?
    Se il `Content-type` è impostato, viene restituito il valore, altrimenti una stringa vuota.
  ?filename? ?`uploadname`?
    Viene restituito il nome del file dell'host remoto che ha caricato il file.
  ?names?
    Restituisce i nomi delle variabili, in una lista, di tutti i file caricati.
  See Esempio 4, “Caricare file”.

load_env ?`array_name`?
  Carica l'array delle variabili d'ambiente all'interno dello specificato nome di array. Utilizza l'array ::request::env come valore predefinito.
  Le pagine di Rivet sono eseguite nel namespace ::request, quindi non è necessario precisare il nome dell'array per più utenti, va bene accedervi tramite env.
load_headers ?`array_name`?
  Carica gli header che provengono dalla richiesta di un client all'interno del nome dell'array indicato, o usa headers se non è stato indicato alcun nome.
load_cookies ?`array_name`?
  Carica l'array delle variabili cookie all'interno del nome dell'array indicato. Utilizza l'array cookies come valore predefinito.
include ?`filename_name`?
  Include un file senza analizzarlo per processare i tag <? e ?>. Questo è il metodo migliore per includere un file HTML o qualsiasi altro contenuto statico.
parse ?`filename`?
  Come il comando Tcl source, ma analizza pure i tag di elaborazione per Rivet <? e ?>. Utilizzando questo comando, potete utilizzare diversi file .rvt.
headers (set | redirect | add | type | numeric)
  Il comando headers è per l'assegnazione e l'elaborazione di header HTTP.
  ?set? ?`headername`? ?`value`?
    Assegna in modo discrezionale i valori ed i nomi agli header.
  ?redirect? ?`uri`?
    Redirige dalla pagina corrente ad un nuovo URI. Questo viene fatto nel primo blocco di codice Tcl.
  ?add? ?`headername`? ?`value`?
    Aggiunge testo all'header `headername`.
  ?type? ?`content-type`?
    Questo comando assegna l'header `Content-type` ritornato dallo script, è utile se desiderate inviare, con Rivet, altri contenuti oltre all'HTML (PNG o immagini jpeg, per esempio).
  ?numeric? ?`response code`?
    Assegna un codice di risposta numerico, come per esempio 200, 404 o 500.
makeurl ?`filename`?
  Crea una URL di riferimento a se stesso dal nome di un file. Per esempio:

      makeurl /tclp.gif

  restituisce `http://[hostname]:[port]/tclp.gif`. Dove hostname e port sono il nome dell'host e la porta del server in questione.

## Esempi ed uso

Seguono alcuni esempi sull'uso di Rivet. Si presuppone che conosciate, anche parzialmente, il linguaggio di programmazione Tcl. Se non conoscete molto Tcl, non c'è da preoccuparsi: è semplice e vi sono alcune buone risorse disponibili sul web che vi permetteranno di padroneggiarlo velocemente. A questo proposito, vedete la sezione web sites.

Esempio 1. Hello World

Come qualsiasi altro tool, è piacevole vedere qualcosa al lavoro, così andremo a creare una piccola pagina "Hello World".

Assumendo che sia stato configurato correttamente Apache, create un file chiamato `hello.rvt` in una directory dove Apache lo possa trovare, con il seguente contenuto:

    <?
    puts "Hello World"
    ?>

Se poi vi accederete con vostro browser, sarà possibile vedere una pagina nera con il testo "Hello World" (senza apici).

Esempio 2. Generare una tabella

In un'altro semplice esempio, genereremo dinamicamente una tabella:

    <? puts "<table>\n"
    for {set i 1} { $i <= 8 } {incr i} {
        puts "<tr>\n"
        for {set j 1} {$j <= 8} {incr j} {
            set num [ expr $i * $j * 4 - 1]
            puts [ format "<td bgcolor=\"%02x%02x%02x\" > $num $num $num </td>\n" \
    		   $num $num $num ]
        }
        puts "</tr>\n"
    }
    puts "</table>\n" ?>

Se leggete il codice, è possibile vedere che è puro Tcl. È possibile mantenere lo stesso codice, eseguirlo fuori da Rivet e generare la stessa pagina HTML!

Il risultato sarà qualcosa di simile a questo:

Esempio 3. Accesso alle variabili

In questa sezione mostreremo come accedere alle variabili utilizzando gli operatori GET o POST.

Data una form HTML come la seguente:

         <form action="vars.rvt">
          <table>
    	<tbody>
    	  <tr>
    	    <td><b>Title:</b></td>
    	    <td><input name="title"></td>
    	  </tr>
    	  <tr>
    	    <td><b>Salary:</b></td>
    	    <td><input name="salary"></td>
    	  </tr>
    	  <tr>
    	    <td><b>Boss:</b></td>
    	    <td><input name="boss"></td></tr>
    	  <tr>
    	    <td><b>Skills:</b></td>
    	    <td>
    	      <select name="skills" multiple="multiple">
    		<option>c</option>
    		<option>java</option>
    		<option>Tcl</option>
    		<option>Perl</option>
    	      </select>
    	    </td>
    	  </tr>
    	  <tr>
    	    <td><input type="submit"></td>
    	  </tr>
    	</tbody>
          </table>
        </form>

Potete utilizzare questo script di Rivet per ottenere i valori delle variabili:

    <?
    set errlist {}
    if { [var exists title] } {
        set title [var get title]
    } else {
        set errlist "You need to enter a title"
    }

    if { [var exists salary] } {
        set salary [var get salary]
        if { ! [string is digit $salary] } {
    	lappend errlist "Salary must be a number"
        }
    } else {
        lappend errlist "You need to enter a salary"
    }

    if { [var exists boss] } {
        set boss [var get boss]
    } else {
        set boss "Mr. Burns"
    }

    if { [var exists skills] } {
        set skills [var list skills]
    } else {
        lappend errlist "You need to enter some skills"
    }

    if { [llength $errlist] != 0 } {
        foreach err $errlist {
    	puts "<b> $err </b>"
        }
    } else {
        puts "Thanks for the information!"
        ?>
        <table>
          <tbody>
    	<tr>
    	  <td><b>Title:</b></td>
    	  <td><? puts $title ?></td>
    	</tr>
    	<tr>
    	  <td><b>Boss:</b></td>
    	  <td><? puts $boss ?></td>
    	</tr>
    	<tr>
    	  <td><b>Salary:</b></td>
    	  <td><? puts $salary ?></td>
    	</tr>
    	<tr>
    	  <td><b>Skills:</b></td>
    	  <td><? puts $skills ?></td>
    	</tr>
          </tbody>
        </table>
        <?
    }
    ?>

La prima istruzione si assicura che la variabile `boss` sia passata allo script e poi fa qualcosa con quella informazione. Se non è presente, un errore viene aggiunto alla lista degli errori.

Nel secondo blocco del codice, la variabile `salary` è riportata con un'altro errore di controllo, poiché è un numero, è necessario che sia composto da cifre.

Alla variabile `boss` non è richiesto di essere inviata, la setteremo a "Mr. Burns" se non è tra le informazioni ricevute.

L'ultimo pezzo del codice di gestione delle variabili è un pezzo ingannatore perché `skills` è una listbox e può avere, potenzialmente, valori multipli. Opteremo di riceverla come una lista, in modo da poterla riutilizzare.

Lo script si assicura che la variabile `errlist` sia vuota e restituisce un messaggio di ringraziamento. Se `errlist` non è vuota, viene stampata la lista degli errori riscontrati.

Esempio 4. Caricare file

Il seguente HTML in un file, detto, `upload.html`

    <form action="foo.rvt" enctype="multipart/form-data" method="post">
    <input type="file" name="MyUpload"></input>
    <input type="submit" value="Send File"></input>
    </form>

Può essere usato con il seguente codice Tcl in un secondo file (`upload.rvt` per esempio) per creare una form che carica un file.

    <?
    upload save MyUpload /tmp/uploadfiles/file1
    puts "Saved file [upload filename MyUpload] \
    	([upload size MyUpload] bytes) to server"
    ?>

## Pacchetti Tcl per Rivet

In aggiunta al nucleo del modulo Apache, Rivet fornisce un numero di pacchetti Tcl che includono codice potenzialmente utile.

- commserver è un package providing a .
- dio è un database abstraction layer.
- dtcl è un pacchetto di compatibilità per applicazioni mod_dtcl.
- form - per creare form.
- rivet - alcune aggiunte, routine utili.
- tclrivet

## Risorse - Come ottenere aiuto

### Mailing Lists

Se non avete trovato la soluzione al problema nella documentazione, la mailing list di Rivet è il primo posto da visitare per ottenere aiuto; spedite un'email a `<rivet-user@tcl.apache.org>`. Se avete una domanda, un'idea, o un commento circa il codice di Rivet, per cortesia mandate un'email a `<rivet-dev@tcl.apache.org>`. Per iscriversi ad entrambe le liste, mandate un'email a `<rivet-`list`-subscribe@tcl.apache.org>`.

Gli archivi delle mailing list sono disponibili a questo indirizzo: http://nagoya.apache.org/eyebrowse/SummarizeList?listId=118

### Newsgroup

Il newsgroup news:comp.lang.tcl è un buon posto per porre domande circa Tcl in generale. Gli sviluppatori di Rivet seguono anche il newsgroup, ma è meglio porre domande specifiche su Rivet presso la sua mailing list.

### Siti Web

Ci sono diversi siti web che estensivamente trattano di Apache e Tcl.

- http://tcl.apache.org è la casa del progetto Apache Tcl. Andateci per ottenere l'ultima versione del nostro software (se non state leggendo queste pagine fuori dal sito!).
- http://httpd.apache.org/docs/ è il primo posto da visitare per domande inerenti il web server Apache.
- http://www.tcl.tk è il sito canonico per informazioni su Tcl.
- http://wiki.tcl.tk è il Tcl'er Wiki, un posto dove poter ricercare domande e risposte di aiuto.

### Bug Tracking System

Apache Rivet usa il sistema Apache Bug Tracking presso http://nagoya.apache.org/bugzilla/. Qui è possibile segnalare problemi o verificare se sono già conosciuti e quindi rintracciare pubblicazioni che lo descrivono.

## Rivet Internals

Questa sezione facilmente pare sorpassata, come nuovo codice viene aggiunto, vecchio codice viene rimosso e di conseguenza vengono apportati i relativi cambiamenti. Il miglior posto dove poter verificare se sono state inserite nuove funzionalità è il suo codice sorgente. Se siete interessati ai cambiamenti osservate il FIXME.

### Inizializzazione

Quando Apache è attivo, (o quando i processi figli di Apache sono attivi se un processo Tcl è in uso), `Rivet_InitTclStuff` viene chiamata, creando un nuovo interprete, o un interprete per host virtuale, dipendentemente dalla configurazione. Inoltre inizializza varie cose, come il canale di sistema RivetChan, crea i comandi Tcl specifici di Rivet ed esegue `init.tcl`. Il sistema di caching è anch'esso impostato e se c'è un GlobalInitScript, viene eseguito.

### RivetChan

Il sistema RivetChan fu creato al fine di avere un canale Tcl reale che potesse redirigere lo standard output. Questo permette di usare, per esempio, il comando normale puts nelle pagine .rvt. Lavora creando un canale che bufferizza l'output e, a tempi predeterminati, lo passa al sistema IO di Apache. Il normale standard output di Tcl è rimpiazzato con un'istanza di questo tipo di canale, in modo che, predefinitamente, l'output venga inviato alla pagina web.

### Parsing delle pagine, Esecuzione e Cacheing

Quando una pagina Rivet viene richiesta, è trasformata in un normale script Tcl tramite l'analisi nel file delle etichette di elaborazione delle istruzioni <? ?>. Ogni cosa fuori da queste etichette diviene un'istruzione estesa puts ed ogni cosa dentro rimane codice Tcl.

Ogni file .rvt è valutato nel proprio `::request` namespace, in modo che non sia necessario creare e distruggere gli interpreti dopo ogni pagina. Tuttavia, operando nel proprio namespace, ogni pagina non verrà eseguita sporcando le variabili locali create da altri scripts, perché verranno cancellate automaticamente quando il namespace termina, dopo che Apache ha finito di gestire le richieste.

| Nota
Un problema corrente con questo sistema è che, mentre le variabili usano la garbage collection, e quindi vengono distrutte automaticamente quando non sono più usate, i gestori dei file non lo sono: è molto importante quindi che gli autori di script Rivet si assicurino di chiudere tutti i file che hanno aperto.

Dopo che uno script è stato caricato ed analizzato dentro una form di "puro Tcl", viene pure immagazzinato, affinché possa essere utilizzato in futuro senza ricaricarlo (e rianalizzarlo) da disco. Il numero degli script immagazzinati in memoria è configurabile. Questa caratteristica può significativamente migliorare l'esecuzione.

## Aggiornamenti da mod_dtcl o NeoWebScript

Rivet ha rotto con il passato, in quanto noi, gli autori, ci siamo dedicati ad acquisire ciò che preferivamo dalle nostre passate fatiche e tolto o cambiato ciò che non abbiamo più curato. La compatibilità all'indietro non fu un obiettivo primario quando creammo Rivet, ma abbiamo fornito questa informazione che potrebbere essere utilizzata da chi desideri effettuare l'aggiornamento da installazioni mod_dtcl o NWS.

### mod_dtcl

Rivet era originalmente basato su codice dtcl, ma ne è stata cambiata (migliorata !) una parte. I concetti rimangono gli stessi, ma alcuni dei comandi sono cambiati.

### NeoWebScript

TODO