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_INFO
undREDIRECT_URL
denselben 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_TRANSLATED
beschriebenen) 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_INFO
liefert den Pfadnamen,PATH_TRANSLATION
den Dateinamen, welcher das Ergebnis einer vom Apache-Server zuvor bereits durchgeführten Content Negotiation sein kann, währendPATH_INFO
noch 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-Encoding
den Wertgzip
mitgeliefert)- 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
200
zur Anzeige einer erfolgreichen Verarbeitung. - Sende den HTTP-Header
Date
zur Beschreibung der aktuellen Serverzeit. - Sende den HTTP-Header
Vary
zur 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-Modified
zur 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-Type
zur Beschreibung des Datentyps des ausgelieferten Datei-Inhalts. - Sende den HTTP-Header
Content-Length
zur Beschreibung der Länge des ausgelieferten Datei-Inhalts. - Falls gewünscht, sende die HTTP-Header
Expires
zur Beschreibung der garantierten Gültigkeit des Inhalts im Browser-Cache eines HTTP/1.0-Clients undCache-Control
zur 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-Encoding
zur Beschreibung der Codierung des ausgelieferten Datei-Inhalts. - Falls gewünscht, sende unsere eigenen HTTP-Header:
X-Gzipcnc-Original-File-Size
zur Beschreibung der Größe der Original-Datei,X-Gzipcnc-Version
zur Beschreibung der verwendeten Programm-Version,X-Gzipcnc-Path-Info
zur Beschreibung des URL des angeforderten Dokuments (nur falls der Selbsttest-Modus aktiv ist) undX-Gzipcnc-Path-Translated
zur 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
Location
zur 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)