Die Verarbeitungslogik von gzip_cnc
Der Ablauf des Hauptprogramms
- Liegt ein Wert für den Pfadnamen der auszuliefernden Datei vor?
(in der Environment-VariablenPATH_TRANSLATED- diese wird für jeden Apache-Handler vom Webserver gesetzt.)- nein => führe den Selbsttest durch.
(Wir können nicht als Handler aufgerufen worden sein, denn wir wissen nicht, was wir eigentlich tun sollen.)
- nein => führe den Selbsttest durch.
- Enthalten die Environment-Variablen
PATH_INFOundREDIRECT_URLdenselben Inhalt?- nein => weise die Anforderung mit dem HTTP-Status 403 zurück.
(Dies war offenbar der Versuch, das Skript direkt aufzurufen und dabei bestehende Apache-Zugriffskontrollmechanismen zu umgehen; dieser Test wurde in Version 1.11 hinzugefügt.)
- nein => weise die Anforderung mit dem HTTP-Status 403 zurück.
- Liegt ein Wert für den URL der auszuliefernden Datei vor?
(in der Environment-VariablenPATH_INFO- diese wird für jeden Apache-Handler vom Webserver gesetzt)- nein => liefere den Inhalt der (durch
PATH_TRANSLATEDbeschriebenen) Original-Datei aus.
(Wir wissen nicht, wie wir den Namen der Cache-Datei bilden müßten.)
- nein => liefere den Inhalt der (durch
- Berechne den Namen der zugehörigen Cache-Datei aus den Werten dieser beiden Environment-Variablen.
(PATH_INFOliefert den Pfadnamen,PATH_TRANSLATIONden Dateinamen, welcher das Ergebnis einer vom Apache-Server zuvor bereits durchgeführten Content Negotiation sein kann, währendPATH_INFOnoch den Original-URL der Anforderung enthält.) - Lies die Attribute der Original-Datei.
(mit der Systemfunktionstat())
Hat das geklappt?- nein => führe eine Behandlung einer fehlende Seite durch.
(Wir können nicht auf diese Datei zugreifen - ob die Datei nicht existiert oder ob irgend ein Systemfehler aufgetreten ist, macht für den Besucher keinen Unterschied.)
- nein => führe eine Behandlung einer fehlende Seite durch.
- Hat der UserAgent die Auslieferung komprimierter Daten erlaubt?
(d. h. im HTTP-HeaderAccept-Encodingden Wertgzipmitgeliefert)- nein => liefere den Inhalt der Original-Datei aus.
(Wir dürfen den Browser nicht mit Daten überfordern, die er nicht versteht.)
- nein => liefere den Inhalt der Original-Datei aus.
- Lies die Attribute der komprimierten Datei im Cache.
(mit der Systemfunktionstat())
Hat das geklappt?- nein => versuche, die Cache-Datei anzulegen.
- Ist das Datum der letzten Änderung für die Cache-Datei neuer als für die Original-Datei?
- Ist der Inhalt der Cache-Datei kleiner als für die Original-Datei?
- nein => liefere den Inhalt der Original-Datei aus.
(Die komprimierte Version taugt nichts - es macht aber auch keinen Sinn, sie zu löschen, weil wir sie beim nächsten Zugriff wieder neu anlegen müßten, um zu merken, daß sie nichts taugt.)
- nein => liefere den Inhalt der Original-Datei aus.
- Liefere den Inhalt der Cache-Datei aus.
Das Anlegen (oder Aktualisieren des Inhalts) einer Cache-Datei
Es macht keinen Unterschied, ob
- eine Cache-Datei nicht existiert oder
- ihr Inhalt veraltet ist
- in beiden Fällen ist es erforderlich, diese Cache-Datei mit einer komprimierten Form des aktuellen Inhalts der Original-Datei zu füllen.
- Trenne im Pfadnamen der Cache-Datei zwischen Verzeichnis- und Datei-Teil.
Hat das geklappt?- nein => liefere den Inhalt der Original-Datei aus.
(Der Pfadname ist nicht so aufgebaut, wie wir es erwarten, um damit arbeiten zu können.)
- nein => liefere den Inhalt der Original-Datei aus.
- Berechne den Namen des Cache-Verzeichnisses für die komprimierte Version der angeforderten Datei aus dem Verzeichnis-Teil.
- Falls dieses Verzeichnis noch nicht existiert, versuche, es anzulegen.
Hat das geklappt?- nein => liefere den Inhalt der Original-Datei aus.
(Ohne Cache-Verzeichnis können wir keine Cache-Datei anlegen.)
- nein => liefere den Inhalt der Original-Datei aus.
- Erzeuge einen zufälligen, aber eindeutigen Namen einer temporären Datei innerhalb des Cache-Verzeichnisses.
- Komprimiere den Inhalt der Original-Datei in diese temporäre Datei.
Hat das geklappt?- nein => lösche die temporäre Datei und liefere den Inhalt der Original-Datei aus.
(Das Ergebnis dieser Komprimierung hätten wir im Cache speichern wollen.)
- nein => lösche die temporäre Datei und liefere den Inhalt der Original-Datei aus.
- Benenne die temporäre Datei um in den Namen der Cache-Datei.
Hat das geklappt?- nein => lösche die temporäre Datei und liefere den Inhalt der Original-Datei aus.
(Wir hätten vielleicht auch die komprimierte Version ausliefern dürfen, aber irgend etwas Ungewöhnliches ist hier kaputt, deshalb gehen wir lieber auf Nummer Sicher.)
- nein => lösche die temporäre Datei und liefere den Inhalt der Original-Datei aus.
- Lies die Attribute der komprimierten Datei im Cache
(mit der Systemfunktionstat()).
Hat das geklappt?- nein => lösche die Cache-Datei und liefere den Inhalt der Original-Datei aus.
(Die Cache-Datei ist nicht sinnvoll verwendbar, also weg damit.)
- nein => lösche die Cache-Datei und liefere den Inhalt der Original-Datei aus.
Die Auslieferung eines Datei-Inhalts
Ob der Inhalt einer Datei in komprimierter oder unkomprimierter Form ausgeliefert werden soll, ist ein relativ kleiner Unterschied, deshalb werden beide Vorgänge mit derselben Funktion erledigt.
- Öffne die zu sendende Datei.
Falls das geklappt hat,- Sende den HTTP-Status
200zur Anzeige einer erfolgreichen Verarbeitung. - Sende den HTTP-Header
Datezur Beschreibung der aktuellen Serverzeit. - Sende den HTTP-Header
Varyzur Beschreibung der durchgeführten Content-Negotiation
(als Kennzeichnung der bedingter Auslieferung des Datei-Inhalts, abhängig vom Inhalt des empfangenen HTTP-HeadersAccept-Encoding- ein Proxy-Server soll wissen, daß er solche Seiten nicht bedenkenlos speichern und als Antwort weiterer Anfragen nach demselben URL ausliefern darf). - Sende den HTTP-Header
Last-Modifiedzur Beschreibung des Datums der letzten Änderung des Inhalts.
(Der Browser wird diesen Wert an den Server zurück senden, wenn er die Gültigkeit seines Cache-Inhalts überprüfen will.) - Sende den HTTP-Header
Content-Typezur Beschreibung des Datentyps des ausgelieferten Datei-Inhalts. - Sende den HTTP-Header
Content-Lengthzur Beschreibung der Länge des ausgelieferten Datei-Inhalts. - Falls gewünscht, sende die HTTP-Header
Expireszur Beschreibung der garantierten Gültigkeit des Inhalts im Browser-Cache eines HTTP/1.0-Clients undCache-Controlzur Beschreibung der garantierten Gültigkeit des Inhalts im Browser-Cache eines HTTP/1.1-Clients.
- Ist das eine Auslieferung komprimierter Daten?
- Sende den HTTP-Header
Content-Encodingzur Beschreibung der Codierung des ausgelieferten Datei-Inhalts. - Falls gewünscht, sende unsere eigenen HTTP-Header:
X-Gzipcnc-Original-File-Sizezur Beschreibung der Größe der Original-Datei,X-Gzipcnc-Versionzur Beschreibung der verwendeten Programm-Version,X-Gzipcnc-Path-Infozur Beschreibung des URL des angeforderten Dokuments (nur falls der Selbsttest-Modus aktiv ist) undX-Gzipcnc-Path-Translatedzur Beschreibung des Dateinamens des angeforderten Dokuments (nur falls der Selbsttest-Modus aktiv ist).
- Sende den HTTP-Header
- Sende den Inhalt der Datei.
- Schließe die Datei.
- Führe die Abschlußbehandlung durch
- Sende den HTTP-Status
- Ist das, was wir gerade ausliefern wollten (aber nicht konnten), eine komprimierte Cache-Datei,
- dann liefere wenigstens den Inhalt der Original-Datei aus,
- andernfalls führe eine Behandlung einer fehlenden Seite durch.
Die Behandlung einer fehlenden Seite
- Wurde in gzip_cnc eine anwenderspezifische Fehlerbehandlungsseite
- als URL definiert, dann sende einen HTTP-Header
Locationzur Weiterleitung auf diesen URL, - als Pfadname definiert, dann sende den Inhalt der entsprechenden Datei,
- als URL definiert, dann sende einen HTTP-Header
- andernfalls gib eine eigene Fehlerbehandlungsseite aus.
- Führe die Abschlußbehandlung durch.
Die Abschlußbehandlung
- Falls eine Protokolldatei definiert wurde,
- Berechne eine formatierte Darstellung von aktuellem Datum und Uhrzeit.
- Berechne die verbrauchte CPU-Zeit.
- Berechne das eingesparte Datenvolumen.
- Schreibe eine Meldung in die Protokolldatei.
- Beende den Programmlauf.
(Michael Schröpl, 2002-09-08)