Aus Linux-Magazin 08/2002

Web-Anwendungen mit dem Tcl-Webserver Tclhttpd

Der in Tcl programmierte Webserver Tclhttpd ist eine ideale Basis für leistungsfähige Web-Anwendungen, die auch und gerade mit Tcl schnell gebaut sind. Funktionen aus der Tcl-Bibliothek und ihren vielen Erweiterungen helfen dabei. Eine eigene Bibliothek übernimmt die HTML-Fleißarbeit.

Für Web-Anwendungen in Tcl steht eine Reihe von Techniken zur Verfügung. Neben einfachen CGI-Skripten, Tcl-Modulen für den Apache oder umfangreichen Application-Servern bietet sich der Tclhttpd an. Der komplett in Tcl geschriebene Webserver kann auf eine lange Entwicklungsgeschichte zurückblicken, entsprechend ausgereift ist er heute. Er dient mit seinen vielen Funktionen als Basis für ausgefeilte Web-Anwendungen. Dieser Artikel zeigt verschiedene Wege, wie man mit seiner Hilfe HTML-Seiten erzeugen kann oder Anfragen bearbeitet.

Ursprung des Tclhttpd waren 175 Zeilen Tcl, die Brent Welch Mitte der 90er Jahre geschrieben hat. Inzwischen ist der Code auf etwa 12000 Zeilen angewachsen, die umfangreiche Tcllib ist in dieser Zählung noch gar nicht berücksichtigt. Diese stabile Basis unterstützt den schnellen Weg zur Anwendung auf viele Arten. Tclhttpd kann:

  • Statische Webseiten ausliefern,
  • Server Side Includes ausführen,
  • einzelne URLs, ganze Verzeichnisse oder verschiedene MIME-Typen mit Tcl-Skripten verknüpfen,
  • Tcl-Code in HTML einbetten,
  • Cookies setzen und lesen,
  • Sessions verwalten,
  • Benutzer authentifizieren,
  • Formulare auswerten,
  • Files auf den Server laden (Upload),
  • E-Mail unterstützen.

Ziel der Entwicklung war nie, mit dem Platzhirsch Apache zu konkurrieren. Wer mit vielen hundert Anfragen pro Sekunde rechen muss, ist mit Tcl-Modulen wie »mod_tcl«[5] oder »mod_websh«[6] im Apache sicherlich besser bedient. Wer jedoch in erster Linie an eine Web-Anwendung für klein- bis mittelvolumige Websites denkt, dem bietet Tclhttpd eine solide Grundlage.

Für kleine und große Projekte geeignet

Verstecken muss sich Tclhttpd aber auch nicht, immerhin ist er der Server für [www.tcl.tk]. Diese Seite bewältigt ein beachtliches Volumen. Andere große Anwendungen sind ein weltweites Netz für meteorologische Daten von Flugplätzen oder das Medusa-Projekt[4], das auf eine umfangreiche Datenbank zugreift. Hört man sich bei den Anwendern um, dann sind es aber vor allem interne Projekte, die auf dieser Basis durchgeführt werden.

Die Tclhttpd-Quellen sind bei Sourceforge zu finden[1]. Dort gibt es zwei Versionen: die All-inclusive-Variante »tclhttpd-3.2-dist« samt Tcl, Thread und Tcllib[3] und die aktuelle Version »tclhttpd-3.3.1«. Der Vorteil des älteren Pakets ist die einfache Installation. Bis zum komplett laufenden Webserver genügen folgende Schritte:

# tar -xzf tclhttpd3.2-dist.tar.gz
# cd tclhttpd3.2-dist/tclhttpd3.2
# make
# make install
# cd bin
# wish httpd.tcl
Running with 256 file descriptor limit
httpd started on port 8015

Ein beliebiger Browser zeigt dann unter der Adresse »http://localhost:8015« die mitgelieferten Beispiele an, sie illustrieren einige der Möglichkeiten des Pakets. Der Server wird mit der Datei »tclhttpd .rc« konfiguriert, ein Beispiel findet sich in Listing 1.

Am Anfang eigener Entwicklungen bietet es sich an, den Inhalt des Beispiel-Verzeichnisses zu verwenden, um das Control-Panel und die Statistiken zu behalten. Mit dem Control-Panel lassen sich vom Browser aus Variablen abfragen oder Bibliotheken neu laden. Beides ist beim Debugging sehr praktisch.

Der Tclhttpd kann den Inhalt seiner Webseiten dynamisch zur Laufzeit erstellen. Dazu unterstützt er mehrere Verfahren. Die einfachste Variante wird mit »Direct_Url« konfiguriert: Der Server leitet dann alle Anfragen für eine URL an die konfigurierte Tcl-Prozedur. Im Gegensatz zu CGI-Skripten startet er dafür keinen separaten Prozess, die Prozedur läuft direkt im Server. Sie kann daher auch Variablen aus dem Server verwenden, etwa für Zähler oder um Datenbankverbindungen offen zu halten.

Listing 1: Tclhttpd-Konfiguration

01 # Beispielhafte Konfiguration
02 
03 # httpd läuft als User 500 in Gruppe 100
04 Config uid 500
05 Config gid 100
06 
07 # httpd hört auf Port 8015, normaler Hostname
08 Config host     [info hostname]
09 Config port     8015
10 
11 # Eigene Skripts im Verzeichnis .../custom
12 Config library  [file join [Config home] .. custom]
13 
14 # HTML-Dateien liegen in /usr/local/httpd/htdocs
15 Config docRoot  /usr/local/httpd/htdocs
16 
17 # Keine Threads erzeugen
18 Config threads  0
19 Config main     [file join [Config home] httpdthread.tcl]
20 
21 # Logfile: /usr/local/httpd/log
22 Config LogFile  /usr/local/httpd/log
23 
24 Config LogFlushMinutes 0

Dynamik durch Direct Url

Ein einfaches Beispiel zeigt Listing 2. Das Kommando »Direct_Url /listing2 .html listing2« ordnet der URL »http:// localhost:8015/listing2.html« die Prozedur »listing2« zu. Die Tcl-Prozedur erzeugt die gewünschte Seite und gibt sie zurück. Interessant sind diverse Variablen, die im Skript zur Verfügung stehen, etwa »env«. Diese Variable enthält unter anderem eine Reihe von Informationen über die aktuelle Client-Verbindung. Das Kommando »html::tableFromArray« formatiert den Inhalt der globalen Variable, das Ergebnis ist in Abbildung 1 zu sehen.

Damit der Server das Skript auch findet, muss es im »contrib«-Verzeichnis stehen. Alle Skripte aus diesem Directory liest Tclhttpd automatisch beim Start. Während der Entwicklung bietet sich auch das »lib«-Verzeichnis an. Dort liegende Skripte müssen zwar explizit im Hauptskript geladen werden, dafür kann man sie jederzeit mit der »Reload Source«-Funktion aus dem Control-Panel neu laden. Der Code kann somit im laufenden Betrieb geändert werden. Tritt in einem Skript ein Fehler auf, zeigt Tclhttpd die Debugging-Information direkt als HTML-Seite an.

Listing 2: Direct-Url-Skript

01 Direct_Url /listing2.html listing2
02 
03 proc listing2 {args} {
04   puts stderr $args
05 
06   set html    "<html>"
07   append html "<body>"
08   append html [html::tableFromArray ::env "border=1" *]
09   append html "</body></html>"
10   return $html
11 }
Abbildung 1: Die Prozedur aus Listing 2 gibt den Inhalt der globalen Tcl-Variablen »::env« aus. In ihr sind die von CGI-Skripten bekannten Einträge enthalten, etwa »HTTP_USER_AGENT«.

Abbildung 1: Die Prozedur aus Listing 2 gibt den Inhalt der globalen Tcl-Variablen »::env« aus. In ihr sind die von CGI-Skripten bekannten Einträge enthalten, etwa »HTTP_USER_AGENT«.

Elegante Vorlage

Eleganter als die Direct-Url-Lösung sind Templates. Bei ihnen handelt es sich um HTML-Dokumente mit eingebettetem Tcl-Code. Die Tcl-Abschnitte sind in eckigen Klammern gekapselt, der Return- Wert der letzten Funktion vor der schließenden Klammer wird in die HTML-Seite übernommen. Der Wert von Variablen lässt sich im ganzen Template nutzen, nicht nur in den Tcl-Abschnitten.

Damit die Templates funktionieren, muss das »htdocs«-Verzeichnis eine Kopie der Datei ».tml« und des Verzeichnisses »libtml« aus der Distribution enthalten. Das Template-Beispiel in Listing 3 definiert zuerst eine Variable, die wieder die Werte des »env«-Arrays als HTML-Code enthält. Weiter unten wird dieser Inhalt mit »$spaeter« in die Seite integriert, am Ende folgt noch das Änderungsdatum des Templates. Ein Template kann also aus einer bunten Mischung von Skripten, Variablen und HTML bestehen.

Templates benutzen die Datei-Endung ».tml« und liegen wie ein normales HTML-Dokument an der entsprechenden Stelle unter »htdocs«. Ruft ein Browser »listing3.html« auf, führt der Server das Template »listing3.tml« aus und liefert das Ergebnis zurück. Das Ergebnis schreibt Tclhttpd zusätzlich als »listing3.html« auf die Festplatte und verwendet es für weitere Anfragen direkt. Dieses Caching ist besonders praktisch, wenn das Template aufwändige Berechnungen durchführt oder langsame Datenbankabfragen enthält.

Die gespeicherte Version aktualisiert Tclhttpd automatisch, wenn das Template neuer ist als das gespeicherte Ergebnis oder wenn der Browser direkt das Template aufruft. Wie Listing 4 zeigt, kann der Befehl »[Doc_Dynamic]« das Caching auch unterdrücken.

Die Templates bieten einen bequemen Migrationspfad, um statische Websites nach und nach mit dynamischen Funktionen zu erweitern. Neben einfachen Zählern bieten sich etwa Navigationsleisten an, die eine einzelne Prozedur für alle Seiten erstellt. In »htdocs/libtml/sunscript.tcl« ist als Beispiel der entsprechende Quelltext für die ehemalige Sunscript-Seite zu finden.

Listing 3: Einfaches Template

01 <html>
02   <head> <title>Einfaches Template</title> </head>
03 
04   <body>
05     Ein einfaches Template.
06     [ set spaeter "nun kommt's"
07       html::tableFromArray ::env "border=1" *
08     ]
09     <p>
10       $spaeter
11     <hr>
12 
13     Letzte Änderung
14     [clock format [file mtime $::env(PATH_TRANSLATED)]]
15   </body>
16 </html>

Listing 4: Template als Formular

01 <html>
02   <head> <title>Eingaben</title></head>
03   <body>
04     [Doc_Dynamic]
05 
06     [ if {![ncgi::empty projekt] } {
07         Doc_Redirect [ncgi::value projekt].html?[ncgi::query]
08       } else {
09         set message "noch kein Projekt gewählt"
10       }
11     ]
12     <hr>
13     $message
14     <form action=$page(url) method=POST>
15       Text: <input type=text [html::formValue text]> 

16       Projekt: [html::radioSet projekt { } {
17         "Projekt 1" projekt1
18         "Projekt 2" projekt2
19       }] <p>
20       <input value="Abschicken" type=submit>
21     </form> <p>
22 
23     Eingabe war:
24     [html::tableFromList [ncgi::nvlist] "border=1"]
25   </body>
26 </html>

Interaktives Template

Webseiten mit Benutzereingaben sind der nächste Schritt einer Web-Anwendung. Solche Interaktionen bestehen im Prinzip aus zwei Teilen: Die HTML-Seite bildet die Benutzeroberfläche im Browser, ein Skript wertet auf dem Server die Eingaben aus. Praktischerweise erstellt ein Template das Formular und wertet es auch selbst wieder aus, damit kann es bei Fehleingaben gleich eine geänderte Version des Formulars zurückgeben. Wenn alle Eingaben gültig sind, leitet das Template den Browser auf eine andere Seite weiter.

Ein Beispielskript in Listing 4 zeigt, wie ein Template auch Formulare bearbeiten kann. Trotz seiner Kürze enthält das Template eine Menge Funktionen. Zunächst verhindert das Kommando »[Doc _Dynamic]« das bei Formularen sinnlose Caching des Templates.

Der nächste Tcl-Block bearbeitet die Eingabedaten. Hierzu nutzt er einige Funktionen des Ncgi-Pakets aus der Tcllib. Beispielsweise überprüft »ncgi::empty«, ob eine Eingabe für das Formularfeld »projekt« existiert. Ist das der Fall, wird die Anfrage per »Doc_Redirect« an eine HTML-Seite für dieses Projekt weitergereicht. Andernfalls erhält die Variable »message« eine Nachricht, die weiter unten die Konstruktion »$message« in die Seite einfügt.

Der mittlere Teil des Templates enthält ein einfaches Formular, dessen Eingaben per »HTTP-POST« zurück an dieses Template gehen. Das Formular enthält ein Texteingabefeld und eine Auswahl mit Radio-Buttons. Deren Werte sind »projekt1« und »projekt2«, die Beschriftungen lauten »Projekt 1« und »Projekt 2«. Ganz zum Schluss gibt das Skript zu Debugging-Zwecken die Benutzereingaben formatiert aus.

Ruft ein Anwender die Seite »listing4 .html« das erste Mal auf, dann ist kein Projekt gesetzt und ein Druck auf den »Abschicken«-Knopf führt ihn wieder auf dieselbe Seite. Eventuelle Eingaben im Textfeld bleiben dank »html::formValue text« erhalten. Erst wenn er ein Projekt wählt, reicht die Eingabeprüfung den Benutzer an eine andere Seite weiter und gibt die Eingaben gleich mit.

Das Html- und das Ncgi-Paket enthalten Lösungen für die meisten Aufgaben, die bei Formularen und deren Auswertung auftreten. Einige der praktischen Funktionen sind in Tabelle 1 aufgeführt. Die komplette Dokumentation der Pakete findet sich in der Tcllib[3].

Tabelle 1: Befehle für HTML und Ncgi.

Tabelle 1: Befehle für HTML und Ncgi.

Daten-Krümel

Wiederholtes Eintippen ist unbequem und nicht alle Browser können und wollen Benutzereingaben speichern. Die Daten auf dem Server speichern ist leicht, sie einem Anwender zuordnen ist nicht so einfach. HTTP ist zustandslos, jede Anfrage ist unabhängig von den vorangegangenen.

Eine möglich Lösung sind Cookies: Der Server bittet den Browser, einige Daten auf dem Client zu speichern, eben ein Cookie. Besucht der User die Seite später wieder und hat er das Cookie nicht gelöscht, dann kann der Server die von ihm gesetzten Daten wieder lesen.

Das Template in Listing 5 prüft zuerst, ob das Cookie »answer« im Browser existiert. Wenn ja, gibt es seinen Wert aus, andernfalls versucht das Template, ein Cookie zu setzen. Neben dem Server, der es gesetzt hat, kann es auch der Browser selbst lesen, wie Abbildung 2 zeigt. Cookies sind häufig problematisch, vor allem aus rechtlicher Sicht (Gebot der minimalen Datenspeicherung), außerdem aus Sicherheitsgründen. Sie sollten nicht die Basis der Anwendungslogik sein.

Listing 5: Cookies

01 <html> <head> <title>Cookie</title> </head>
02   <body> <h1>Cookie</h1>
03     [ Doc_Dynamic
04       if {[string length [Doc_Cookie answer]] > 0} {
05         set html "Cookie answer ist [Doc_Cookie answer]"
06       } else {
07         Doc_SetCookie -name answer -value 42 -path $page(url)
08         set html "Setze Cookie answer=42"
09     }]
10   </body>
11 </html>
Abbildung 2: Mozilla zeigt den Inhalt des Cookies an, das vom Template in Listing 5 stammt. Es wurde vom Server »192.168.42.150« gesetzt, heißt »test« und hat den Wert »42«.

Abbildung 2: Mozilla zeigt den Inhalt des Cookies an, das vom Template in Listing 5 stammt. Es wurde vom Server »192.168.42.150« gesetzt, heißt »test« und hat den Wert »42«.

Login für Web-Anwendungen

So schön offene Netze sind, manchmal ist eine Zugriffskontrolle für Teile der Website notwendig. Neben den vom Apache bekannten ».htaccess«-Dateien unterstützt Tclhttpd die Authentifizierung über eine Tcl-Prozedur. Hierzu dient eine Datei namens ».tclaccess« (Listing 6) im jeweiligen Verzeichnis. In ihr müssen die Variablen »realm« und »callback« gesetzt werden.

In »callback« steht der Name der Tcl-Prozedur, die für die Authentifizierung zuständig ist. Den Inhalt von »realm« zeigt der Browser als Text im Login-Dialog an. Er wird auch als Parameter an die Callback-Prozedur weitergegeben. Das Beispiel akzeptiert alle Anwender, die das Passwort »federlesen« angeben – eine reale Anwendung würde auf User-Passwort-Einträge in Dateien, Datenbanken oder LDAP-Verzeichnissen zurückgreifen. Nach dem Login steht der Username in der Variable »::env(REMOTE_USER)« zur Verfügung.

Eine fortschrittlichere Variante sind Sessions. Dabei benutzt Tclhttpd eigene Interpreter für jede einzelne Sitzung. Zwischen den Sessions sind die Daten somit getrennt, innerhalb einer Sitzung bleiben sie erhalten. Ein einfaches Beispiel zu Sessions befindet sich in der Listingsammlung auf dem FTP-Server des Linux-Magazins[13].

Listing 6: Authentifizierung

01 set realm "Federlesen"
02 set callback stimmts?
03 
04 proc stimmts? {sock realm user password} {
05   if {[string match $password federlesen]} {
06     return 1
07   } else {
08     return 0
09   }
10 }
Abbildung 3: Die Googbar sieht aus wie die Google-Homepage, ist aber ein Tcl-Programm. Sie leitet die Suchfrage direkt an Google weiter.

Abbildung 3: Die Googbar sieht aus wie die Google-Homepage, ist aber ein Tcl-Programm. Sie leitet die Suchfrage direkt an Google weiter.

Mehr Infos

Die vorgestellten Möglichkeiten beleuchten nur einen kleinen Teil der Funktionen dieses Webservers. Die Beispiele im Tclhttpd-Paket zeigen unter anderem den Upload von Dateien und die Verwendung von Imagemaps. Weitere Informationen finden sich auf[2]. Dort ist unter anderem ein Ausschnitt aus einem Buch von Brent Welch zu lesen, dem Autor von Tclhttpd. Bei Sourceforge gibt es eine Mailingliste, die mit kompetenten Antworten aufwartet und auch Anfängerfragen beantwortet.

In einigen Fällen kann man sich den Aufwand einer eigenen Entwicklung sparen. Mit Infocetera[12] steht eine vollständige Groupware-Applikation zur Verfügung, mit Kalender, Adressbuch, Raumverteilung, Aufgabenverwaltung und weiteren Modulen. Die komplette Anwendung basiert auf Tclhttpd.

Das nächste Feder-Lesen taucht aus den Tiefen der Serveranwendungen wieder auf dem Bildschirm auf. Es wird sich mit Tk und den BWidgets beschäftigen. Abbildung 4 gibt einen Vorgeschmack auf dieses Widget-Set, das nur mit Hilfe der Standard-Tk-Widgets und reinem Tcl-Code leistunsgfähige neue Widgets anbietet. (fjl)

Abbildung 4: Die BWidgets-Demoanwendung zeigt, was in dem Toolkit steckt. Die Widgets sind in Tcl geschrieben und benutzen nur Tk.

Abbildung 4: Die BWidgets-Demoanwendung zeigt, was in dem Toolkit steckt. Die Widgets sind in Tcl geschrieben und benutzen nur Tk.

Abbildung 5: Das Programm »dndspy« (unten) zeigt, welche MIME-Types und welche Aktionen bei einem Drag-Objekt möglich sind. Aus Evolution (oben) wird gerade eine Nachricht (fliegendes Blatt) gezogen.

Abbildung 5: Das Programm »dndspy« (unten) zeigt, welche MIME-Types und welche Aktionen bei einem Drag-Objekt möglich sind. Aus Evolution (oben) wird gerade eine Nachricht (fliegendes Blatt) gezogen.

Abbildung 6: Toucan, eine grafische Entwicklungsumgebung für Palm-Programme. Die IDE und die damit erstellte Software basieren auf Tcl.

Abbildung 6: Toucan, eine grafische Entwicklungsumgebung für Palm-Programme. Die IDE und die damit erstellte Software basieren auf Tcl.

Tcl-Update

Das Wichtigste: Tcl 8.4 wird im Herbst aus dem Betastadium entlassen. Obwohl mir schon lange keine Fehler mehr aufgefallen sind, will das Tcl-Coreteam noch warten, um wieder eine superperfekte Version abzuliefern. Bereits verfügbar ist eine ganze Reihe neuer Anwendungen mit und für Tcl. Die BWidgets mit zusätzlichen GUI-Elementen wie Tree und Combobox – Thema im nächsten Feder-Lesen – sind jetzt in Version 1.4 erhältlich[3]. Als kleiner Vorgeschmack ist die Demo in Abbildung 4 zu sehen.

Neues von Ora Tcl und Tcl XML

Zu zwei in den letzten beiden Feder-Lesen-Folgen behandelten Paketen ist Neues zu melden: Die Datenbank-Erweiterung Ora Tcl[9] unterstützt in der neuesten Version alle Möglichkeiten von Oracle 9i und das Tcl-XML-Paket auf Sourceforge[10] bietet mit »xmlgen« einen neuen Weg, um XML und HTML zu erzeugen. »xmlgen« erzeugt ein Sprachmapping von Tcl zu XML: Statt mit Elementen und Attributen kann man nun eine Ebene höher mit Anwendungsobjekten arbeiten.

Viele kleine Helfer

Neben diesen serverorientierten Dingen gibt es auch Neues bei vielen kleineren Tools. Klein im Bezug auf die Hardware ist Toucan, eine Entwicklungsumgebung für Palm-Programme[8]. Sowohl die Entwicklungsumgebung als auch die entwickelten Anwendungen basieren auf Tcl (Abbildung 6). Klein im Platzbedarf ist Googbar (Abbildung 3), das Anfragen bei Google starten kann[7]. Noch weniger Platz auf dem Bildschirm braucht Tkdnd, die Drag & Drop-Erweiterung für Tk[11]. Sie nutzt das XDND-Protokoll von Gnome- und KDE-Anwendungen, sie läuft auch unter Windows. Mit dabei ist »dndspy« (Abbildung 5). Dieses Programm zeigt die Daten des DND-Protokolls an.

Infos

[1] Homepage des Tclhttpd: [http://sourceforge.net/projects/tclhttpd/]

[2] Informationen zum Tclhttpd: [http://www.tcl.tk/software/tclhttpd/]

[3] Homepage von Tcllib und BWidgets: [http://sourceforge.net/projects/tcllib/]

[4] Medusa-Projekt: [http://ciheam.maich.gr/medusa/]

[5] Tcl-Apache-Modul: [http://tcl.apache.org/mod_tcl/mod_tcl.html]

[6] Websh: [http://websh.com]

[7] Googbar: [http://www.geddy.hpg.ig.com.br/software/googbar/]

[8] Toucan: [http://home.attbi.com/~maccody/]

[9] Ora Tcl: [http://oratcl.sourceforge.net]

[10] Tcl XML: [http://tclxml.sourceforge.net]

[11] Tk DND: [http://www.iit.demokritos.gr/~petasis/]

[12] Infocetera: [http://www.infocetera.com]

[13] Listings zum Artikel: [ftp://ftp.linux-magazin.de/pub/magazin/2002/08/Feder-Lesen]

Der Autor

Carsten Zerbst arbeitet bei Atlantec an einem PDM-System für den Schiffbau. Daneben beschäftigt er sich noch besonders mit dem Einsatz von Tcl/Tk.

LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben