Torsten schrieb:
Habe folgende Konfiguration:
============================= ...
RewriteLog /var/log/apache2/rewrite.log RewriteLogLevel 2 Alias /test /hallo
RewriteEngine On ReWriteOptions Inherit RewriteBase /test RewriteRule $ MouseIDGenes Options FollowSymLinks
AllowOverride None
Order allow,deny Allow from 146.107.x.x
</Directory> </VirtualHost> ==============================
Bei einem request auf /test (http://virtueller_host.domain.de/test)
Ich glaube nicht, dass es ein Request auf /test ist, sondern auf /test/. Du siehst bestimmt, wie sich die URL im Browser von /test in /test/ ändert. Mod_dir ist dafür zuständig bei einem Request, der zu einem Verzeichnis auflöst, einen HTTP Code 301 zu liefern mit einem Location-Header, der auf die ursprüngliche URI mit einem angehängten Slash zeigt. Im Folgenden gehe ich davon aus, dass es /test/ ist.
Stimmt.
passiert folgendes:
========================================= 146.107.x.x - - [26/Mar/2013:21:19:26 +0100] [mouseidgenes.helmholtz-muenchen.de/sid#7fedaa020a28][rid#7fed aa095978/initial] (2) [perdir /hallo/] rewrite '' -> 'MouseIDGenes' 146.107.x.x - - [26/Mar/2013:21:19:26 +0100] [mouseidgenes.helmholtz-muenchen.de/sid#7fedaa020a28][rid#7fed aa095978/initial] (2) [perdir /hallo/] trying to replace prefix /hallo/ with /test 146.107.x.x - - [26/Mar/2013:21:19:26 +0100] [mouseidgenes.helmholtz-muenchen.de/sid#7fedaa020a28][rid#7fed aa095978/initial] (1) [perdir /hallo/] internal redirect with /test/MouseIDGenes [INTERNAL REDIRECT] 146.107.x.x - - [26/Mar/2013:21:19:26 +0100] [mouseidgenes.helmholtz-muenchen.de/sid#7fedaa020a28][rid#7fed aa099f78/initial/redir#1] (2) [perdir /hallo/] rewrite 'MouseIDGenes' -> 'MouseIDGenes' 146.107.x.x - - [26/Mar/2013:21:19:26 +0100] [mouseidgenes.helmholtz-muenchen.de/sid#7fedaa020a28][rid#7fed aa099f78/initial/redir#1] (1) [perdir /hallo/] initial URL equal rewritten URL: /hallo/MouseIDGenes [IGNORING REWRITE] ========================================
Der Apache bearbeitet Requests in mehreren Phasen. Für Dich hier sind 3 davon interessant, "URI Translation", "Map to Storage" und "Fixup". Module, wie mod_rewrite oder mod_alias, können für diese Phasen Handler-Funktionen registrieren. Beide, mod_rewrite und mod_alias, registrieren Handler für URI Translation und Fixup. Ich gehe mal davon aus, dass Du einen Apache aus der 2.x-er Serie benutzt.
Ja.
Die URI Translation Phase kommt zuerst, im wesentlichen direkt nach dem Einlesen des Requests (Request Zeile und HTTP-Header). An dieser Stelle hat der Apache noch keine <Directory> oder ähnliche Blocks auf den Request angewandt. Von Deiner Konfiguration sieht der Apache bisher also nur "Alias /test /hallo" als relevant für die Anfrage an.
OK.
Weiterhin ist wichtig zu wissen, dass die Request-Struktur des Apache ein Feld für die URI und ein weiteres für den Filenamen (außerdem auch path_info, falls das relevant ist) enthält.
Module können in der URI Translation Phase die URI selbst manipulieren. Außerdem können sie das Filename Feld setzen. Die Alias Anweisung setzt also zunächst den Filenamen zu $DocumentRoot/hallo/. Die URI selbst bleibt unangetastet.
Wieso zu $DocumentRoot/hallo/ ? Ich verstehe "Alias /test /hallo" so, daß /hallo im Root des Filesystems liegt, damit also zu /hallo umgeleitet wird. Bei diesem Beispiel http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase liegt das Ziel-Directory auch unterhalb der root des filesystems, nicht unterhalb DocumentRoot.
Direkt im Anschluss an die URI Translation Phase kommt "Map to Storage". Die Aufgabe dieser Phase ist es zum einen die filename und path_info Felder zu füllen, falls das noch nicht geschehen ist. Zum anderen werden <Directory> und <Files> Blöcke und .htaccess Dateien ausgewertet und der Konfiguration des Requests hinzugefügt. Erst jetzt lernt der Apache also Deine RewriteRule kennen.
Bis hierher sieht Dein Request also wie folgt aus:
uri: /test/ filename: $DocumentRoot/hallo/
s.o.
Sofort nach Map to Storage werden nun die <Location> Blocks der Konfiguration hinzugefügt. Dieser Prozess kann von Modulen nicht beeinflusst werden. Danach ist die Konfiguration für den Request komplett. Da Du keinen <Location> Block benutzt, ändert sich an Deiner Anfrage nichts.
Nach ein paar weiteren Phasen bzgl. Zugriffsberechtigungen u.ä. kommt die Fixup Phase direkt bevor der Request-Body eingelesen und die Antwort ausgegeben wird.
Deine RedirectRule konnte bisher noch nicht angewendet werden, weil sie in der URI Translation Phase noch nicht bekannt war. Das passiert jetzt in Fixup.
Aus der Map to Storage Phase hat der Apache sich gemerkt, dass die RewriteRule in einem Container stand, der dem Verzeichnis $DocumentRoot/hallo/ entspricht.
s.o.
Dieser Präfix wird von filename abgeschnitten, übrig bleibt der leere String. Deine Rule passt und aus dem leeren String wird 'MouseIDGenes'.
Da Du eine RewriteBase angegeben hast, wird der Filename entsprechend ergänzt und zu /test/MouseIDGenes. Ohne RewriteBase wäre /hallo/MouseIDGenes herausgekommen. D.h. es wird einfach DocumentRoot abgeschnitten.
Wo kommt die DocumentRoot her, die hier wieder abgeschnitten wird ?
Nun ist /test/MouseIDGenes jedoch kein gültiger Dateiname. Es ist eine URI. Die folgende Phase, in der die Antwort erzeugt wird, könnte mit diesem Dateinamen nichts anfangen. Außerdem könnte das neue Ziel andere Anforderungen bzgl. Zugriffsberechtigungen haben. Eigentlich müsste man also alle Phasen des Requests mit der neuen URI nochmal durchlaufen.
Genau für diesen Zweck hat der Apache einen Mechanismus, der sich "Internal Redirect" nennt. Dabei wird eine neue Request Struktur mit der neuen URI erzeugt. Diese durchläuft den kompletten Zyklus beginnend mit der URI Translation Phase erneut.
Das ist hier gut beschrieben: http://httpd.apache.org/docs/2.2/rewrite/flags.html#flag_l Passiert das /immer/, daß das Ergebnis der RewriteRules in einem directory-context wieder an den Anfang (URI translation phase) weiter gegeben wird ? Außerdem: ist das "[INTERNAL REDIRECT]" im logfile das Zeichen dafür, daß der request noch mal durch alles läuft ? Ich habe nämlich in meinem log "[INTERNAL REDIRECT]"-Einträge, bei denen aber anscheinend danach nichts mehr passiert. Oder matcht da nur einfach nichts, so daß keine Rule angewendet wird ? ================================================================ ... 146.107.x.x - - [27/Mar/2013:15:22:49 +0100] [mouseidgenes.helmholtz-muenchen.de/sid#7f7446a5d838][rid#7f7446ad7958/initial] (2) [perdir /srv/www/vhosts/mouseidgenes/htdocs/] strip document_root prefix: /srv/www/vhosts/mouseidgenes/htdocs/MouseIDGenes -> /MouseIDGenes 146.107.x.x - - [27/Mar/2013:15:22:49 +0100] [mouseidgenes.helmholtz-muenchen.de/sid#7f7446a5d838][rid#7f7446ad7958/initial] (1) [perdir /srv/www/vhosts/mouseidgenes/htdocs/] internal redirect with /MouseIDGenes [INTERNAL REDIRECT] Anm.: sieht nicht so aus, als ob hier noch was passiert. 146.107.x.x - - [27/Mar/2013:15:31:22 +0100] [mouseidgenes.helmholtz-muenchen.de/sid#7f7446a5d838][rid#7f7446ad7958/initial] (3) [perdir /srv/www/vhosts/ mouseidgenes/htdocs/] add path info postfix: /srv/www/vhosts/mouseidgenes/htdocs/test -> /srv/www/vhosts/mouseidgenes/htdocs/test/ =================================================================
Über ein paar Zwischenstufen leitet mod_rewrite nun solch einen Internal Redirect mit der neuen URI (/test/MouseIDGenes) ein.
Nach der URI Translation Phase sieht das dann wie folgt aus:
uri: /test/MouseIDGenes filename: $DocumentRoot/hallo/MouseIDGenes
s.o.
Das kommt in der Fixup Phase in mod_rewrite an (die vorletzte Zeile in Deinem Log). Du hast richtig erkannt, dass es sich hier um eine neue Anfrage handelt. Von dieser hat der Client aber nichts mitgekriegt. Das ist einfach die neue Request Struktur für den Internal Redirect. Alle Request Strukturen, die zu einem vom Client initiierten Request gehören, sind über Listen- bzw. Baum-ähnliche Strukturen miteinander verkettet. Mod_rewrite kann also feststellen, dass der aktuelle Request das Resultat eines Internal Redirects ist. Der "/redir#1" Teil aus dem Log wird genau das besagen. Die aktuelle Anfrage ist ein Internal Redirect und ist eine Ebene vom originalen Request entfernt.
Nun wendet mod_rewrite wieder Deine Rule an und vergleicht "MouseIDGenes" mit der Regexp "$". Es passt, denn auch der String "MouseIDGenes" hat ein Ende.
Muß hier nur ein Zeichen (Wortende) matchen ?
Aus "MouseIDGenes" wird also "MouseIDGenes" und über RewriteBase wieder /test/MouseIDGenes.
Dann merkt mod_rewrite, "ups, hier hat sich ja gar nichts geändert" und lehnt es ab, einen weiteren Internal Redirect zu erzeugen, weil das zu einem Zyklus führen würde.
Zu Deinen Fragen vom 25.3. auf users@httpd:
Danke daß Du Dich derer auch gleich annimmst.
1. Frage:
Mod_rewrite arbeitet eigentlich nur auf dem Filename Feld des Requests. In der URI Translation Phase kann es sein, dass dieses noch nicht gesetzt ist (NULL Pointer). In diesem Fall wird es vor dem Start der Maschine mit r->uri initialisiert. Filename muss dabei nicht einer existierenden Eintrag im Filesystem entsprechen. Es kann eigentlich ein beliebiger String sein.
Substitution in einer RewriteRule ist eigentlich immer ein Pfad im Filesystem (der nicht existieren muss), außer wenn mittels Flags etwas anderes angegeben ist, PT, P oder R. Im Directory-Context wird das PT Flag impliziert. Somit ist Substitution eine URI.
Im Server-Context wird mit dem PT Flag das r->uri Feld geändert, sonst immer r->filename. Im Directory-Context wird ein Internal Redirect mit der neuen URI erzeugt. D.h. es entsteht ein neuer Request mit der neuen URI in r->uri.
Aber erst wenn alle Rules durchlaufen sind, oder ?
2. Frage:
Ich denke, die Antwort ist inzwischen klar. In r->filename steht am Anfang "$DocumentRoot/hallo/bla/bla". Die Directory im Directory-Context lautet "$DocumentRoot/hallo/" (Inhalt von DocumentRoot plus PATH aus <Directory PATH> (stimmt nicht ganz. Für DirectoryMatch und .htaccess wird PATH in Map to Storage ausgerechnet)). Dieser Teil wird entfernt und es bleibt "bla/bla" übrig. Wichtig: dieser String beginnt nie mit einem Slash.
3. Frage:
Das automatische entfernen des Präfix im Directory Context findet immer statt, nicht nur für .htaccess.
Siehe Frage 2.
Das Ziel einer RewriteRule im Directory-Context ist immer eine URI. Wenn RewriteBase angegeben ist, wird der Wert als Präfix ergänzt, sonst wird $DocumentRoot aus "$DocumentRoot/hallo/" entfernt (ergibt "/hallo/") und das als Präfix benutzt.
Diese Ersetzung findet erst statt, wenn alle RewriteRules ausgewertet wurden.
Purzelt aus den Rules eine absolute URL raus, also etwas, das wie scheme://... aussieht, erfolgt ein vom Browser sichtbarer Redirekt, also ein HTTP Code zwischen 300 und 399. Im Directory Context versucht mod_write auch hier, RewriteBase zu ersetzen, damit auch so etwas funktioniert (R Flag in Directory Context):
RewriteRule ^bla blub [R] ...
Hallo Torsten, noch nie habe ich so eine ausführliche Antwort bekommen. Vielen Dank und Respekt ! Bernd Helmholtz Zentrum München Deutsches Forschungszentrum für Gesundheit und Umwelt (GmbH) Ingolstädter Landstr. 1 85764 Neuherberg www.helmholtz-muenchen.de Aufsichtsratsvorsitzende: MinDir´in Bärbel Brumme-Bothe Geschäftsführer: Prof. Dr. Günther Wess und Dr. Nikolaus Blum Registergericht: Amtsgericht München HRB 6466 USt-IdNr: DE 129521671 -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um den Listen Administrator zu erreichen, schicken Sie eine Mail an: opensuse-de+owner@opensuse.org