Preise

Projektüberblick

Quelldateien

Diese Seite wurde aus den folgenden Quelldateien erstellt:

Tinyhttpd ist ein leichtgewichtiger HTTP-Server, der als Lernprojekt für die Grundlagen der Webserver-Entwicklung konzipiert ist. Das Projekt bietet eine minimale, aber vollständige Implementierung eines HTTP-Servers mit CGI-Unterstützung (Common Gateway Interface). Der Quellcode ist bewusst einfach gehalten, um Entwicklern das Verständnis der Kernkonzepte von HTTP-Servern zu erleichtern (README.md:1-5).

Der Server unterstützt sowohl statische Dateiauslieferung als auch dynamische Inhalte durch CGI-Programme. Die Implementierung nutzt POSIX-Threads (oder alternative Forking-Mechanismen für Linux) zur Behandlung gleichzeitiger Verbindungen. Die CGI-Funktionalität ermöglicht die Ausführung von Perl-Skripten und anderen ausführbaren Programmen zur dynamischen Inhaltserzeugung.

Technologie-Stack und Voraussetzungen

KomponenteBeschreibungVersion/Anforderung
SpracheCStandard C
ThreadingPOSIX Threadspthread-Bibliothek
CGI-UnterstützungPerlPerl + perl-cgi Modul
Socket-APIBSD Sockets-lsocket (Solaris) / Standard (Linux)
ZielplattformUnix-ähnlichLinux, Solaris

Plattform-spezifische Kompilierung

Für Linux-Systeme sind folgende Anpassungen erforderlich:

  1. Auskommentieren von #include <pthread.h>
  2. Auskommentieren der Variable newthread
  3. Auskommentieren der pthread_create() Aufrufe
  4. Aktivieren des direkten accept_request() Aufrufs
  5. Entfernen von -lsocket aus dem Makefile

(README.md:6-14)

Projektstruktur

tinyhttpd/
├── htdocs/              # Statische Webdateien und CGI-Skripte
│   ├── index.html       # Standard-Startseite
│   └── *.cgi            # CGI-Programme (Perl, Shell, etc.)
├── simpleclient.c       # Einfacher HTTP-Client zum Testen
├── httpd.c              # Hauptimplementierung des Servers
├── Makefile             # Build-Konfiguration
└── README.md            # Projektdokumentation

Kernmodule und deren Verantwortlichkeiten

Modulübersicht

Der Server besteht aus mehreren funktionalen Modulen, die jeweils spezifische Aufgaben innerhalb des HTTP-Anfragezyklus übernehmen. Die folgende Tabelle fasst die Kernfunktionen zusammen:

FunktionVerantwortlichkeitEingabeAusgabe
mainEinstiegspunkt, Server-StartKommandozeilenargumenteExit-Code
startupSocket-Initialisierung und Port-BindungPortnummerServer-Socket
accept_requestHTTP-AnfrageverarbeitungClient-SocketHTTP-Antwort
execute_cgiCGI-ProgrammausführungPfad, Methode, DatenCGI-Ausgabe
catDateiinhalt lesen und sendenDateipfad, SocketDateiinhalt
get_lineZeilenweise Socket-LesungSocketZeilenstring
headersHTTP-Header generierenStatus, SocketHeader-Bytes
bad_request400-Fehler sendenSocketFehlerantwort
not_found404-Fehler sendenSocketFehlerantwort
cannot_execute500-Fehler bei CGI sendenSocketFehlerantwort
unimplemented501-Fehler sendenSocketFehlerantwort
error_dieFehlerbehandlung und ExitFehlernachrichtExit

(README.md:16-28)

Modul 1: Server-Initialisierung (startup)

Verantwortlichkeitsgrenzen:

  • Erstellt den Server-Socket
  • Führt bind() und listen() Systemaufrufe aus
  • Weist einen Port zu (festgelegt oder zufällig)
  • Gibt den Socket-Deskriptor an den Aufrufer zurück

Nicht verantwortlich für:

  • Annahme von Client-Verbindungen
  • Anfrageverarbeitung
  • Thread-Management

Eintrittspunkt und API:

c
1int startup(u_short *port);

Wichtige Datenstrukturen:

  • struct sockaddr_in: Server-Adressinformationen
  • u_short *port: Zeiger auf Portnummer (Eingabe/Ausgabe)

Aufrufkette:

  1. socket() erstellt TCP-Socket
  2. setsockopt() aktiviert SO_REUSEADDR
  3. bind() weist Adresse zu
  4. listen() aktiviert Warteschlange

Fehlerbehandlung:

  • Bei Socket-Erstellung: perror() und Exit
  • Bei Bind-Fehler: perror() und Exit
  • Bei Port 0: Automatische Portzuweisung durch System

(README.md:27-27)

Modul 2: HTTP-Anfrageverarbeitung (accept_request)

Verantwortlichkeitsgrenzen:

  • Liest und parst HTTP-Anfragezeile
  • Extrahiert HTTP-Methode (GET/POST)
  • Verarbeitet URL und Query-String
  • Entscheidet zwischen statischer Auslieferung und CGI

Nicht verantwortlich für:

  • Socket-Erstellung
  • CGI-Prozess-Management (delegiert an execute_cgi)

Eintrittspunkt und API:

c
1void accept_request(int client);

Wichtige Datenstrukturen:

  • char method[255]: HTTP-Methode
  • char url[255]: Angeforderte URL
  • char path[512]: Dateisystempfad
  • char *query_string: GET-Parameter

Aufrufkette:

  1. get_line() liest Anfragezeile
  2. Parsing von Methode und URL
  3. Pfadkonstruktion mit htdocs-Präfix
  4. Verzeichnisprüfung → index.html anhängen
  5. Verzweigung: serve_file() oder execute_cgi()

Fehlerbehandlung:

  • Ungültige Methode → unimplemented()
  • Datei nicht gefunden → not_found()
  • Pfad außerhalb htdocs → bad_request()

(README.md:17-17)

Modul 3: CGI-Ausführung (execute_cgi)

Verantwortlichkeitsgrenzen:

  • Erstellt Pipes für Interprozesskommunikation
  • Führt fork() zur Prozessisolierung durch
  • Setzt CGI-Umgebungsvariablen
  • Leitet STDIN/STDOUT um
  • Führt CGI-Programm via execl() aus

Nicht verantwortlich für:

  • HTTP-Header-Parsing
  • Statische Dateiauslieferung

Eintrittspunkt und API:

c
1void execute_cgi(int client, const char *path,
2                 const char *method, const char *query_string);

Wichtige Datenstrukturen:

  • int cgi_input[2]: Pipe für CGI-Eingabe
  • int cgi_output[2]: Pipe für CGI-Ausgabe
  • pid_t pid: Prozess-ID des Kindprozesses
  • Umgebungsvariablen: REQUEST_METHOD, QUERY_STRING, CONTENT_LENGTH

Aufrufkette (Elternprozess):

  1. Schließt nicht benötigte Pipe-Enden
  2. Bei POST: Schreibt Daten in cgi_input[1]
  3. Liest CGI-Ausgabe von cgi_output[0]
  4. Sendet Ausgabe an Client-Socket
  5. waitpid() wartet auf Kindprozess

Aufrufkette (Kindprozess):

  1. dup2() leitet STDOUT auf cgi_output[1] um
  2. dup2() leitet STDIN auf cgi_input[0] um
  3. setenv() setzt Umgebungsvariablen
  4. execl() ersetzt Prozess durch CGI-Programm

Fehlerbehandlung:

  • Pipe-Erstellung fehlgeschlagen → cannot_execute()
  • Fork fehlgeschlagen → cannot_execute()
  • execl fehlgeschlagen → Exit

(README.md:22-22)

Modul 4: Hilfsfunktionen (cat, get_line, headers)

cat-Funktion:

  • Liest Dateiinhalt blockweise
  • Schreibt direkt in Socket
  • Verantwortlich für statische Dateiauslieferung

get_line-Funktion:

  • Liest Zeichen für Zeichen vom Socket
  • Normalisiert Zeilenenden (\r\n → \n)
  • Handelt Timeout und Pufferüberlauf

headers-Funktion:

  • Sendet HTTP-Statuszeile
  • Sendet Standard-Header (Server, Content-Type)
  • Terminiert Header-Block mit Leerzeile

(README.md:19-24)

Systemarchitektur

正在加载图表渲染器...

Architektur-Erklärung:

  1. Netzwerk-Layer: Das startup()-Modul initialisiert den Server-Socket und bindet ihn an einen Port. Der accept()-Aufruf wartet auf eingehende Verbindungen und erstellt für jede Verbindung einen neuen Client-Socket.

  2. Anfrage-Verarbeitung: accept_request() ist die zentrale Verarbeitungsfunktion. Sie nutzt get_line() zum zeilenweisen Lesen der HTTP-Anfrage und entscheidet basierend auf Methode und URL über den weiteren Verarbeitungspfad.

  3. Statische Inhalte: Bei einfachen GET-Anfragen ohne Parameter wird serve_file() aufgerufen, das über cat() den Dateiinhalt direkt an den Client sendet.

  4. CGI-Subsystem: Für dynamische Inhalte (POST, GET mit Parametern, ausführbare Dateien) wird execute_cgi() aktiviert. Dieses Modul nutzt fork() zur Prozessisolierung und Pipes zur Kommunikation zwischen Eltern- und Kindprozess.

  5. Fehlerbehandlung: Verschiedene Fehlerfunktionen behandeln spezifische Fehlerszenarien und senden entsprechende HTTP-Statuscodes an den Client.

(README.md:35-43)

HTTP-Anfrageverarbeitungsfluss

正在加载图表渲染器...

Ablauf-Erklärung:

  1. Verbindungsannahme: Der Server akzeptiert eine TCP-Verbindung und erstellt einen neuen Thread (oder ruft direkt accept_request() auf).

  2. Anfrage-Parsing: accept_request() liest die HTTP-Anfragezeile, extrahiert Methode und URL, und konstruiert den Dateisystempfad.

  3. Verzweigung: Bei GET-Anfragen ohne Parameter wird die Datei direkt ausgeliefert. Bei POST oder GET mit Parametern wird die CGI-Verarbeitung aktiviert.

  4. CGI-Prozess: Der Elternprozess erstellt zwei Pipes und forkt einen Kindprozess. Der Kindprozess leitet STDIN/STDOUT um und führt das CGI-Programm aus. Der Elternprozess sendet ggf. POST-Daten und liest die CGI-Ausgabe.

  5. Antwort: Die generierte Antwort wird an den Client gesendet und die Verbindung geschlossen.

(README.md:37-43)

CGI-Implementierung und Interprozesskommunikation

Pipe-Architektur

Die CGI-Implementierung nutzt zwei unidirektionale Pipes für die Kommunikation zwischen Server und CGI-Programm:

Pipe-Konfiguration:

PipeRichtungElternprozessKindprozess
cgi_inputServer → CGISchreibt in [1]Liest von [0] (STDIN)
cgi_outputCGI → ServerLiest von [0]Schreibt in [1] (STDOUT)

Anfangszustand (nach pipe()-Aufruf):

cgi_input:  [0] ← Lesen    [1] ← Schreiben
cgi_output: [0] ← Lesen    [1] ← Schreiben

Endzustand (nach dup2() und close()):

Kindprozess:
  STDIN  → cgi_input[0]
  STDOUT → cgi_output[1]
  
Elternprozess:
  Schreibt POST-Daten → cgi_input[1]
  Liest CGI-Ausgabe   ← cgi_output[0]

(README.md:46-55)

Umgebungsvariablen

Das CGI-Modul setzt folgende Umgebungsvariablen für die Kommunikation mit dem CGI-Programm:

VariableBeschreibungBeispielwert
REQUEST_METHODHTTP-MethodeGET oder POST
QUERY_STRINGURL-Parametername=value&foo=bar
CONTENT_LENGTHLänge der POST-Daten42

(README.md:42-43)

Datenfluss bei POST-Anfragen

正在加载图表渲染器...

Datenfluss-Erklärung:

  1. Der Elternprozess empfängt POST-Daten vom Client
  2. Daten werden über cgi_input[1] in die Pipe geschrieben
  3. Der Kindprozess liest die Daten von cgi_input[0] über STDIN
  4. Das CGI-Programm verarbeitet die Daten
  5. Die Ausgabe wird über STDOUT an cgi_output[1] gesendet
  6. Der Elternprozess liest von cgi_output[0] und sendet an den Client

(README.md:41-44)

Kernfunktionen im Detail

Fehlerbehandlungsmodul

Der Server implementiert mehrere spezialisierte Fehlerfunktionen:

bad_request(): Sendet HTTP 400 Bad Request

  • Wird aufgerufen bei malformed HTTP-Anfragen
  • Schreibt Standard-Fehlerseite an Client

not_found(): Sendet HTTP 404 Not Found

  • Wird aufgerufen wenn angeforderte Datei nicht existiert
  • Generiert HTML-Fehlerseite

cannot_execute(): Sendet HTTP 500 Internal Server Error

  • Wird aufgerufen bei CGI-Ausführungsfehlern
  • Meldet Server-seitige Probleme

unimplemented(): Sendet HTTP 501 Not Implemented

  • Wird aufgerufen bei nicht unterstützten HTTP-Methoden
  • Listet unterstützte Methoden auf

error_die(): Kritische Fehlerbehandlung

  • Schreibt Fehlermeldung via perror()
  • Beendet Prozess mit Exit

(README.md:18-28)

Empfohlene Lesereihenfolge

Für ein tiefgreifendes Verständnis des Quellcodes wird folgende Reihenfolge empfohlen:

  1. main() — Einstiegspunkt und Server-Lebenszyklus
  2. startup() — Socket-Initialisierung
  3. accept_request() — Kern-Verarbeitungslogik
  4. execute_cgi() — CGI-Implementierung

Nach dem Verständnis des Hauptflusses sollten die Hilfsfunktionen (cat, get_line, headers) und Fehlerbehandlungsfunktionen studiert werden.

(README.md:31-31)

Quantifizierte Projektkennzahlen

MetrikWert
Kernfunktionen12
Unterstützte HTTP-Methoden2 (GET, POST)
CGI-Umgebungsvariablen3
Pipes pro CGI-Aufruf2
Prozesse pro CGI-Anfrage2 (Eltern + Kind)
Standard-Webverzeichnis1 (htdocs)
Fehlerbehandlungsfunktionen5

Anwendungsgebiete

Bildungszwecke:

  • Verständnis von HTTP-Protokoll-Grundlagen
  • Lernen von Socket-Programmierung
  • Verstehen von CGI-Mechanismen
  • Studium von Interprozesskommunikation

Einschränkungen:

  • Nicht für Produktionsumgebungen geeignet
  • Keine HTTPS-Unterstützung
  • Eingeschränkte Sicherheitsfunktionen
  • Kein HTTP/1.1 Keep-Alive

Erweiterungsmöglichkeiten:

  • Hinzufügen von HTTPS/TLS-Unterstützung
  • Implementierung von HTTP/1.1 Persistent Connections
  • Erweiterte MIME-Type-Erkennung
  • Logging-Funktionalität
  • Konfigurationsdatei-Unterstützung

Berichts-Navigationsübersicht

正在加载图表渲染器...

Lesepfad-Erklärung:

  1. Projektüberblick (aktuelle Seite): Einführung in Tinyhttpd, Kernmodule und Systemarchitektur
  2. Architektur: Detaillierte Analyse der Komponentenstruktur und Abhängigkeiten
  3. Datenfluss: Tiefgehende Untersuchung der HTTP-Anfrageverarbeitung und CGI-Kommunikation
  4. API-Design: Schnittstellenbeschreibung und Funktions-APIs
  5. Deployment: Build-Prozess und Betriebshinweise