CGI-Programmierung Am Beispiel eines Servers für numerische Berechnungen FH Wiesbaden - Marius Mertz - Alexander Küken
Teil 1: CGI Einführung 2
Was ist CGI? Motivation In den Anfangszeiten des Internets waren Webinhalte rein statisch Bei statischen Inhalten reicht der Webserver die HTML-Seiten einfach an den Client (Browser) weiter Die HTML-Seiten liegen fertig im Dateisystem des Webservers 3
Statische Inhalte Client 1. Request Webserver 3. Datei einlesen 4. Response 2. Datei suchen Dateisystem 4
Was ist CGI? Motivation Die Entwickler der ersten Webserver suchten bald nach Möglichkeiten, die Webinhalte dynamisch zu gestalten Bei dynamischen Inhalten startet der Webserver einen Prozess, welcher die angeforderten Daten zusammenstellt Beispiel: Abfrage einer Datenbank 5
Dynamische Inhalte Client 1. Request Webserver 5. HTML Ausgeben 6. Response 2. Datei suchen Dateisystem 3. Prozess starten Prozess auf Systemebene 4. DB Anfrage Datenbank 6
Was ist CGI? Historisches Die ersten Webserver 1991: CERN httpd 1993: NSCA httpd (später: Apache) Beide Entwicklerteams implementierten eigene Methoden für: den Aufruf externer Programme (Prozesse) die Parameterübergabe an die Prozesse 7
Was ist CGI? Historisches Problem Scripte und Programme, die für einen der Server entwickelt wurden, waren nicht kompatibel mit dem Konkurrenz-Produkt Lösung Die Entwicklerteams beider Server einigten sich auf einen Standard für Aufruf und Parameterversorgung 8
Was ist CGI? Common Gateway Interface Schnittstelle, um Anwendungen mit Eingaben zu versorgen und deren Ausgaben weiterzuleiten CGI-Anwendungen können praktisch in jeder Programmiersprache erstellt werden Prozesse, welche vom Webserver gestartet werden 9
Kommunikation zwischen Webserver und CGI Request stdin Response Webserver stdout CGI stderr System z.b. Log-Dateien, syslogd, usw. 10
Was ist CGI? Common Gateway Interface Zwei Wege der Datenübergabe an CGI- Anwendungen GET: Direkt über die URL POST: Von der HTML-Seite selbst z.b. über ein Eingabeformular 11
Was ist CGI? Umgebungsvariablen enthalten Informationen zum Webserver und zum Client (Browser) werden aus drei verschiedenen Quellen erzeugt HTTP-Anfrage-Paket Webserver HTTP-Anfrage-Header des Browsers 12
Was ist CGI? CGI-Umgebungsvariablen: Beispiele CONTENT_LENGTH Größe der Daten (stdin) in Bytes CONTENT_TYPE Typ der übermittelten Daten QUERY_STRING Datenstring, welcher an der URL hängt 13
Was ist CGI? CGI-Umgebungsvariablen: Beispiele REQUEST_METHOD Methode der HTTP-Anfrage (GET oder POST) REMOTE_ADDR Die IP des Clients, der den HTTP-Request geschickt hat HTTP_ACCEPT Die vom Client akzeptierten MIME-Typen 14
Was ist CGI? GET-Methode Die zu übermittelnden Daten werden direkt an die URL angehängt Beispiel:.../meinskript.cgi?var1=wert&var2=wert Der Server trennt die Daten von der URL und legt sie in der Umgebungsvariablen QUERY_STRING ab Übermittelbare Datenmenge ist beschränkt 15
Querystring von HTTP GET bestimmen Beispielaufruf: get_example.cgi?var1=val1&var2=val2 char * get_querystring() { return getenv( QUERY_STRING ); } Ergebnis: var1=val1&var2=val2 16
Was ist CGI? POST-Methode Der Nachrichten-Body der Anfrage (HTTP Request) wird über stdin an die CGI Anwendung weitergeleitet Die CGI Anwendung muss dann von stdin die richtige Menge an Daten lesen Die Anzahl der einzulesenden Bytes steht in der Umgebungsvariable CONTENT_LENGTH Quasi keine Einschränkung der Datenmenge 17
Querystring von HTTP POST bestimmen Beispielaufruf: post_example.cgi char * post_querystring() { int content_length; char * result = NULL; content_length = atoi(getenv( CONTENT_LENGTH )); result = calloc(content_length + 1, sizeof(char)); fread(result, sizeof(char), content_length, stdin); return result; } Ergebnis: var1=val1&var2=val2 18
Ein allgemeinere Ansatz char * get_querystring() { int content_length; char * result = NULL; } if (strcmp(getenv( REQUEST_METHOD ), GET ) { return getenv( QUERY_STRING ); } else { content_length = atoi(getenv( CONTENT_LENGTH )); result = calloc(content_length + 1, sizeof(char)); fread(result, sizeof(char), content_length, stdin); return result; } 19
Beispiel für CGI/C Beispiel eines CGI Skriptes, implementiert in C Das Skript sammelt alle CGI-Umgebungsvariablen und gibt diese in tabellarischer Form über den Browser aus Methode: GET Datenübergabe via URL 20
Beispiel für CGI/C: Der Code Ein Array von Strings mit den Namen der Umgebungsvariablen: char *env[] = { "AUTH_TYPE", "CONTENT_LENGTH", "CONTENT_TYPE", "GATEWAY_INTERFACE", "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_LANGUAGE", "HTTP_COOKIE", "HTTP_CONNECTION", "HTTP_HOST", "HTTP_REFERER", "HTTP_USER_AGENT", "PATH_INFO", "PATH_TRANSLATET", "QUERY_STRING", "REMOTE_ADDR", "REMOTE_HOST", "REMOTE_IDENT", "REMOTE_USER", "REQUEST_METHOD", "SCRIPT_NAME", "SERVER_NAME", "SERVER_PORT", "SERVER_PROTOCOL", "SERVER_SOFTWARE", NULL }; 21
Beispiel für CGI/C: Der Code Methode, um den Kopf einer HTML-Datei zu schreiben: void print_html_header(char *titel) { printf("<html><head>\n"); printf("<title>%s</title>\n",titel); printf("</head><body><pre>\n"); } Methode, um den HTML-Code abzuschließen: void print_html_end(void) { printf("</pre></body></html>\n"); } 22
Beispiel für CGI/C: Der Code Methode, um den HTML-Header für den Browser zu schreiben. Dieser wird dadurch informiert, dass der nun folgende Inhalt Text, bzw. HTML darstellt. void print_header(void) { printf("content-type: text/html\n\n"); } 23
Beispiel für CGI/C: Der Code Die environment()-funktion: void environment(const char *s, int j) { char *p; p = getenv(s); printf("<tr>\n"); printf("<td>"); printf ("%d.", j); /* Index */ printf("</td>"); printf("<td>"); printf ("%s", s); /* Variablenname */ printf("</td>"); printf("<td>"); if(p!=null) printf ("%s", p); /* Variablenwert */ else printf("(<i>keine Angaben</i>)"); printf("</td>\n"); printf("</tr>\n"); } 24
Beispiel für CGI/C: Der Code Die Main-Funktion: int main(void) { int i; print_header(); print_html_header("cgi-umgebungsvariablen");... for(i=0; env[i]!= NULL; i++) { environment(env[i], i+1); }... print_html_end(); exit(0); } 25
Online Demo: Umgebungsvariablen 26
Sicherheit Vorsicht bei der Rechtevergabe für CGI Prozesse! Manche Provider lassen z.b. einen Apache-Server als Root laufen Dies hat Vorteile bei der Administration Logfiles können z.b. in alle Homeverzeichnisse geschrieben werden Vom Server gestartete Kind-Prozesse sollten NICHT als Root gestartet werden! 27
Sicherheit Da CGI Prozesse direkt auf dem Server- System als Kindprozesse gestartet werden, ist es möglich, auf diesem Weg Systembefehle auszuführen! Dies eröffnet Angreifern eine Hintertür, um auf dem Webserver schlimmstenfalls Schaden anzurichten 28
Sicherheit Beispiel: Gefahr besteht immer dann, wenn z.b. Eingaben aus einem HTML-Formular ungeprüft als Systemkommando ausgeführt werden Perl-Script: $result = qx(ping -c 5 $eingabestring); qx() setzt die eingeschlossene Zeichenkette in einen Kommandozeilenaufruf um 29
Sicherheit $result = qx(ping -c 5 $eingabestring); eingabestring enthält das Ping-Ziel result soll das Ergebnis im Browser darstellen Was passiert, wenn eingabestring einen Pipe- Operator enthält? foo ls -la qx(ping -c 5 foo ls -la); 30
Sicherheit $qx(ping -c 5 foo ls -la); Das Ergebnis dieses Kommandozeilenaufrufes enthält, auf einem Webserver ausgeführt das komplette Directory-Listing des Verzeichnisses /cgi-bin/! Natürlich könnten auf diesem Weg auch ganz andere Kommandos abgesetzt werden... 31
Sicherheit Deshalb gilt: Strings, welche ohne Prüfung an Systembefehle übergeben werden, haben in CGI- Skripten nichts zu suchen Solche Eingabestrings sollten unbedingt auf verdächtige Zeichen wie Pipe-Operatoren untersucht werden, bevor sie auf das Systen angewendet werden 32
CGI Performance C (GCC 4.0.1) 145 Fortran (G77 3.4.6) 121 Perl 5.8.8 87 Ruby 1.8.6 64 PHP 5.2.4 17 Java 1.5.0_13 3 0 38 75 113 150 33
Teil 2: Projekt-Dokumentation 34
Aufgabenstellung Entwicklung eines CGI basierten Servers für numerische Berechnungen in C. 35
Ansätze für die Entwicklung Das System soll einfach zu erweitern sein Kapselung in Bibliotheken libcgi: Ein- und Ausgabe libnum: numerische Funktionen libhtml: kapselung von HTML-Tags Unterstützung grafischer Ausgabe SVG Unterstützung (libsvg) Verzicht auf CGI Bibliotheken 36
Anwendungsstruktur HTTP-Client HTTP 1.1 kompatibler Browser Anwendungsschicht CGI 1 CGI 2 CGI 3 libcgi libhtml libsvg libnum Webserver lighttpd 1.4.8 System POSIX kompatible Betriebsysteme 37
libcgi: Eingabeverarbeitung Aufruf von cgi_get_input() liefert die Eingabedaten: key1=value1&key2=value2&key3=value3 Eingabedaten werden am Trennzeichen & zerlegt: key1=value1 key2=value2 key3=value3 key/value Paare werden zerschnitten und als verkettete Liste abgelegt: key1 value1 key2 value2 key3 value3 Zugriff ähnlich wie bei einer HashMap 38
libcgi: Eingabeverarbeitung - Beispiel CGI_INPUTITEM *first = NULL; CGI_INPUTITEM *newitem; char *input; char *token; char *tok_save; input = cgi_get_input(); token = strtok_r(input, "&", &tok_save); while (token) { newitem = cgi_generate_inputitem(token); newitem->next = first; first = newitem; token = strtok_r(null, "&", &tok_save); } printf("key1: %s\n", get_inputitembykey(first, "key1")); printf("key2: %s\n", get_inputitembykey(first, "key2")); printf("key3: %s\n", get_inputitembykey(first, "key3")); 39
libcgi: Ausgabeverarbeitung Zentralisierte Ausgabe über Ausgabequeue Angelehnt an die MessageQueue aus der Systemprogrammierung Funktionen um HTML, SVG und Fehler in die Queue einzufügen Die Queue berechnet die Größe des Inhaltes in Byte um die Informationen im HTTP Header mitzusenden. 40
libnum: numerische Verfahren Sammlung von Funktionen für numerische Berechnungen ursprünglich von Herrn Weber in Turbo Pascal entwickelt später von ihm und Herrn Friedl nach C portiert kleinere Schönheitskorrekturen vorgenommen als Bibliothek übersetzt 41
libhtml: HTML-Ausgabe Kapselung der HTML-Tags als C-Funktionen Übersichtlicher Programmcode Zentrale Formatierung Wiederverwendbarkeit 42
libsvg: grafische Ausgabe Scalable Vector Graphics XML basierter Standard libsvg kapselt die SVG Ausgabe 43
Problemfelder: Stringverarbeitung Stringfunktionen in C eher rudimentär keine regulären Ausdrücke, kein String Replace, kein Substring, usw. Schaffung eigener Funktionsbibliotheken für die Stringverarbeitung auf Basis der vorhandenen Funktionen. Nutzung von Dritthersteller Bibliotheken: libstrfunc (www.sourceforge.net/projects/libstrfunc) String Handling Library (shl.sourceforge.net) PCRE (www.pcre.org) 44
Problemfelder: Debugging Problemstellung: Browser gibt im Fehlerfall meist nur einen Serverfehler aus. Log-Einträge im Fehlerprotokoll des Servers meist nicht sehr hilfreich gdb und ddd können nicht verwendet werden Lösungsansatz: Debugging als Konsolenanwendung Umgebungsvariablen manuell setzen CGI wie eine normale Anwendung testen 45
Online Demo: Horner-Schema Mit Hilfe dieses Schemas können Funktions- und Ableitungswerte eines Polynoms an einer festen Auswertungsstelle berechnet werden. 46
Teil 3: Weiterführende Themen 47
CGI und mod_* im Vergleich Standard CGI offener Standard mod_* abhängig vom Serverhersteller, teils properitär Skalierbarkeit Geschwindigkeit Sprachabhängikeit Systemabhängigkeit Serverabhängigkeit Persistenz skaliert nicht, Einsatz mehrerer Server und Loadbalancer notwendig langsam bei interpretierten Sprachen, da Interpreter bei jedem Request geladen wird Sprachunabhängig Systemunabhängig Serverunabhängig transient skaliert nicht, Einsatz mehrerer Server und Loadbalancer notwendig gute Geschwindigkeit durch vorladen des Interpreters herstellerspezifisch, meist nur interpretierte Sprachen herstellerspezifisch Serverabhängig transient 48
FastCGI offene Erweiterung des CGI Standards ein Versuch die Schwächen von CGI auszugleichen Protokoll für den Datenaustausch zwischen Webserver und Anwendungsprozess 1996 entwickelt von Open Market dennoch heute weitgehend unbekannt 49
Kommunikation zwischen Webserver und FCGI Request full-duplex socket Response Webserver FastCGI Prozess System z.b. Log-Dateien, syslogd, usw. 50
FastCGI: ein Beispiel #include <stdlib.h> #include "fcgi_stdio.h" void main(void) { /* Initialisierung */ int count = 0; /* Auf Requests warten */ while(fcgi_accept() >= 0) { /* Implementierung */ printf("content-type: text/html\n\n"); printf("<title>fastcgi Hello!</title>"); printf("<h1>fastcgi Hello!</h1>"); printf("request number %d\n", ++count); } } 51
FastCGI Performance static HTML 1.519 Ruby FCGI 1.184 mod_ruby 574 Ruby CGI 95 0 500 1.000 1.500 2.000 52
CGI und FastCGI im Vergleich Standard CGI offener Standard FCGI offener Standard Skalierbarkeit Geschwindigkeit Sprachabhängikeit Systemabhängigkeit Serverabhängigkeit Persistenz skaliert nicht, Einsatz mehrerer Server und Loadbalancer notwendig langsam bei interpretierten Sprachen, da Interpreter bei jedem Request geladen wird Sprachunabhängig Systemunabhängig Serverunabhängig transient skaliert sehr gut, Prozesse können ausgelagert werden sehr schnell durch Vorladen und Initialisierung mit Serverstart es gibt nicht für alle Sprachen FCGI Implementierungen ja, Quellen liegen vor Serverabhängig persistent 53
(F)CGI und Systemprogrammierung Warum ist das Thema interessant? Webbasierte Anwendungen werden immer interessanter und mächtiger Der Benutzer braucht nur einen Browser Nutzung der Bibliotheken des Systems Konfiguration für embedded Systeme Alternative zu RPC und verwandten Techniken 54
Representational State Transfer Alternative Technologie zu Remote Procedure Calls und ähnliche Techniken erstmals erwähnt in einer Dissertation aus dem Jahr 2000 Ressourcen basierter Ansatz URL identifiziert eine Ressource HTTP Method bestimmt die Aktion 55
Representational State Transfer HTTP CRUD SQL GET Read SELECT Ressource beziehen POST Create INSERT Ressource anlegen PUT Update UPDATE Ressource aktualisieren DELETE Delete DELETE Ressource löschen HEAD - - OPTIONS - - Informationen über Ressource beziehen Abfragen, welche Aktionen die Ressource unterstützt 56
Representational State Transfer URL identifiziert die Ressource/Entität HTTP Methode identifiziert die Aktion Dateiendung identifiziert das Format Beispiel: GET students/137293.xml HTTP/1.1 Host: fh-wiesbaden.intern Hole den Datensatz des Studenten mit der Matrikelnummer 137293 und liefere ihn als XML- Dokument 57
Fragen? 58