Title: Wie Filter unter Apache 2.0 funktionieren




Dokumentation für Entwickler




    Achtung

Dieses Dokument wurde mit "Ausschneiden und Einfügen" aus einer E-Mail (<[EMAIL PROTECTED]>) erstellt und damit es besser lesbar ist, neu formatiert. Es ist nicht auf aktuellem Stand, kann aber als Ausgangspunkt für weitere Untersuchungen dienen.

Filtertypen

Es gibt drei Grundtypen von Filtern (die sich jeweils in zwei Kategorien unterteilen lassen, worauf später noch eingegangen wird).

CONNECTION
Filter diesen Typs sind für die Dauer dieser Verbindung gültig. (AP_FTYPE_CONNECTION, AP_FTYPE_NETWORK)
PROTOCOL
Filter diesen Typs sind für die Dauer dieser Anfrage aus der Sicht des Client gültig, was bedeutet, dass die Anfrage vom Versenden bis zum Eingang der Antwort gültig ist. (AP_FTYPE_PROTOCOL, AP_FTYPE_TRANSCODE)
RESOURCE
Filter diesen Typs sind für die Zeit gültig, in der dieser Inhalt für eine Anfrage verwendet wird. Bei einfachen Anfragen ist dies identisch mit dem Filter PROTOCOL, aber interne Umleitungen und Unteranfragen können den Inhalt verändern, ohne dass die Anfrage damit beendet ist. (AP_FTYPE_RESOURCE, AP_FTYPE_CONTENT_SET)

Die Unterscheidung zwischen einem Protokoll und einem Ressourcenfilter ist von Bedeutung. Ein Ressourcenfilter ist an eine bestimmte Ressource gebunden, er kann auch an Header-Informationen gebunden sein, die wichtige Bindung ist jedoch die an die Ressource. Wenn Sie einen Filter erstellen und wissen wollen, ob es sich um eine Ressource oder um ein Protokoll handelt, dann lautet die richtige Frage: "Kann dieser Filter verschoben werden, wenn die Anfrage zu einer anderen Ressource umgeleitet wird?" Lautet die Antwort "Ja", dann handelt es sich um einen Ressourcenfilter. Lautet sie "Nein", handelt es sich wahrscheinlich um ein Protokoll oder um einen Verbindungsfilter. Auf Verbindungsfilter wird hier nicht eingegangen, weil sie hinreichend verständlich sind. Die Definitionen können mit einigen Beispielen verdeutlicht werden:

byterange
Dieser Filter wurde so kodiert, dass er für alle Anfragen eingefügt und entfernt werden kann, wenn er nicht verwendet wird. Da dieser Filter zu Beginn aller Anfragen aktiv ist, kann er bei einer Umleitung nicht entfernt werden, dementsprechend handelt es sich um einen Protokollfilter.
http_header
Dieser Filter schreibt eigentlich die Header für das Netzwerk. Er wird offensichtlich benötigt (außer im Sonderfall von mod_asis, worauf weiter unten noch eingegangen wird) und er ist somit ein Protokollfilter.
deflate
Der Administrator konfiguriert diesen Filter entsprechend der angeforderten Datei. Bei einer internen Umleitung von einer Autoindex-Seite zu einer index.html- Seite kann der deflate-Filter entsprechend der Konfiguration hinzugefügt oder entfernt werden, daher handelt es sich um einen Ressourcenfilter.

Die weitere Unterteilung der einzelnen Kategorien in zwei weitere Filtertypen dient ausschließlich der Anordnung. Wir könnten sie aufheben und nur einen Filtertyp zulassen, dann würde aber die Anordnung durcheinander geraten und es wären Eingriffe notwendig, um die Funktion zu gewährleisten. Zur Zeit besitzen die RESOURCE-Filter nur einen Filtertyp, aber das sollte geändert werden.

Wie werden Filter eingefügt?

In der Theorie ist das eigentlich ganz einfach, der Code ist jedoch kompliziert. Zuerst einmal ist es wichtig, dass jeder sich klar macht, dass es drei Filterlisten für jede Anfrage gibt, die aber alle miteinander verkettet sind. Die erste Liste sind r->output_filters, dann folgen r->proto_output_filters und anschließend r->connection->output_filters. Sie entsprechen den RESOURCE-, PROTOCOL- und CONNECTION-Filtern. Vorher bestand das Problem darin, dass eine einfach verknüpfte Liste benutzt wurde, um einen Filter-Stack zu erzeugen. Begonnen wurde dabei mit der "korrekten" Position. War eine RESOURCE-Filter im Stack und ein CONNECTION-Filter wurde hinzugefügt, dann bedeutete das, dass der CONNECTION-Filter ignoriert wird. Das erscheint sinnvoll, weil der Verbindungsfilter am Anfang der c->output_filters-Liste eingefügt wird, während das Ende von r->output_filters auf den Filter zeigt, der normalerweise am Beginn von c->output_filters stand. Das ist offensichtlich falsch. Der neue Code für das Einfügen benutzt eine doppelt verknüpfte Liste. Das hat den Vorteil, dass ein eingefügter Filter niemals verloren geht. Leider gibt es noch anderes Problem.

Es besteht darin, dass es zwei unterschiedliche Fälle gibt, in den wir Unteranfragen verwenden. Im ersten Fall werden weitere Daten in eine Antwort eingefügt. Im zweiten wird die vorhandene Antwort durch eine interne Umleitung ersetzt. Dies sind zwei unterschiedliche Situationen, die entsprechend behandelt werden müssen.

Im ersten Fall erzeugen wir die Unteranfrage aus einem Handler oder Filter heraus. Das bedeutet, dass der nächste Filter an die Funktion make_sub_request weitergereicht werden sollte und dass der letzte Ressourcenfilter der Unteranfrage auf den nächsten Filter der Hauptanfrage verweist. Das ist sinnvoll, wenn die Daten der Unteranfrage durch die gleichen Filter laufen müssen wie die Hauptanfrage. Eine grafische Darstellung kann das verdeutlichen:

Default_handler --> includes_filter --> byterange --> ...

Erzeugt der include_filter eine Unteranfrage, dann sollen die Daten dieser Unteranfrage durch diesen Filter laufen, weil es sich nicht um SSI-Daten handeln kann. Daher nimmt die Unteranfrage folgende Ergänzung vor:

    
Default_handler --> includes_filter -/-> byterange --> ...
                                    /
Default_handler --> sub_request_core

Was geschieht, wenn die Unteranfrage SSI-Daten enthält? Das ist ganz einfach, der includes_filter ist ein Ressourcenfilter, daher wird er der Unteranfrage zwischen dem Default_handler und dem sub_request_core-Filter hinzugefügt.

Der zweite Fall für Unteranfragen liegt vor, wenn eine Unteranfrage zu einer richtigen Anfrage wird. Das geschieht immer dann, wenn eine Unteranfrage außerhalb eines Handler oder Filters erzeugt wird und NULL als nächster Filter an die Funktion make_sub_request weitergegeben wird.

In diesem Fall sind die Ressourcenfilter nicht mehr sinnvoll, weil sich die Ressource geändert hat. Anstatt ganz von vorne zu beginnen, wird einfach auf den Anfang der Ressourcenfilter für die Unteranfrage am Anfang der Protokollfilter für die alte Anfrage verwiesen. Das bedeutet, dass keine Protokollfilter verloren gehen und die Daten auch nicht durch einen Filter geleitet werden, der nicht für sie vorgesehen ist.

Das Problem ist, dass jetzt eine doppelt verknüpfte Liste für die Filter-Stacks benutzt wird. Sie sollten aber beachten, dass es möglich ist, bei zwei Listen dieses Modell zu durchkreuzen. Wie wird mit dem vorherigen Filter umgegangen? Diese Frage ist schwer zu beantworten, weil es keine "richtige" Antwort noch eine gleichermaßen gültige Methode gibt. Ich habe untersucht, warum der Pointer verwendet wird. Der einzige Grund ist, dass Hinzufügen neuer Server zu vereinfachen. Vor diesem Hintergrund habe ich die Lösung gewählt, den vorherigen Pointer immer auf die ursprüngliche Anfrage verweisen zu lassen.

Das führt zu einer etwas komplexeren Logik, funktioniert aber in allen Fällen. Meine Bedenken hinsichtlich der Verschiebung auf die Unteranfrage rühren daher, dass in den allgemeineren Fällen (wo einer Antwort mit der Unteranfrage Daten hinzugefügt werden), die Hauptfilterkette falsch wäre. Das scheint mir keine gute Idee zu sein.

Asis

Der letzte Punkt. :-) mod_asis hat etwas von einem Hack, aber der Handler muss alle Filter mit Ausnahme des Verbindungsfilters entfernen und die Daten senden. Wenn Sie mod_asis benutzen, sind alle anderen außer Kraft gesetzt.

Erläuterungen

Zum Abschluss sei erwähnt, dass der Grund, warum dieser Code so schwer zu formulieren war, die Tatsache war, dass er so stark manipuliert werden musste, damit er funktioniert. Die meisten der Manipulationen habe ich selbst vorgenommen, so dass die Schuld bei mir liegt. Aber jetzt, wo der Code richtig ist, habe ich damit begonnen, einige Hacks zu entfernen. Den meisten sollte aufgefallen seien, dass die Funktionen reset_filters und add_required_filters verschwunden sind. Diese haben auf Protokollebene Filter für Fehlerbedingungen eingefügt und seltsamer Weise haben beide Funktionen nacheinander das Gleiche getan. Da jetzt keine Protokollfilter für Fehlersituationen mehr verloren gehen, sind diese Hacks entfernt worden. Die Filter HTTP_HEADER, content-length und byterange wurden in die insert_filters-Phase eingefügt, denn würden sie vorher eingefügt, dann käme es zu interessanten Interaktionen. Sie konnten jetzt alle so verschoben werden, dass sie mit den Filtern HTTP_IN, CORE und CORE_IN eingefügt werden. Auf diese Weise ist der Code leichter nachzuvollziehen.

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to