Hi, aus gegebenem Anlaß muß ich mich mit mod_rewrite beschäftigen. Einfach ist anders ! Bin seit Stunden die Doku auf apache.org am Lesen, komme aber im Moment nicht weiter. Bin jetzt am testen. Habe folgende Konfiguration: ============================= ... RewriteLog /var/log/apache2/rewrite.log RewriteLogLevel 2 Alias /test /hallo <Directory "/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) passiert folgendes: ========================================= 146.107.x.x - - [26/Mar/2013:21:19:26 +0100] [mouseidgenes.helmholtz-muenchen.de/sid#7fedaa020a28][rid#7fedaa095978/initial] (2) [perdir /hallo/] rewrite '' -> 'MouseIDGenes' 146.107.x.x - - [26/Mar/2013:21:19:26 +0100] [mouseidgenes.helmholtz-muenchen.de/sid#7fedaa020a28][rid#7fedaa095978/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#7fedaa095978/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#7fedaa099f78/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#7fedaa099f78/initial/redir#1] (1) [perdir /hallo/] initial URL equal rewritten URL: /hallo/MouseIDGenes [IGNORING REWRITE] ======================================== Ich verstehe das folgendermaßen: Durch den Alias landet der Request erst mal im betr. directory-container (hallo), da ja test ein Alias für hallo ist. In diesem Container gibt es einen RewriteRule, die ausgeführt wird. Anschließend wird die RewriteBase vor die substitution geklemmt. OK ? Dieser "neue" request (/test/MouseIDGenes) landet durch den alias test wieder im hallo container. /test/ wird entfernt, MouseIDGenes wird zu MouseIDGenes substituiert, was mod_rewrite richtigerweise als Unsinn erkennt. OK ? Was mir nicht klar ist: wieso wird vor der Substitution in Zeile 4 quasi noch einmal ein neuer request erzeugt ? Wieso gibt sich mod_rewrite nicht mit dem redirect in Zeile 3 zufrieden und hört auf ? Und kann mir bitte jemand helfen, was die Interpretation des mod_rewrite-logs angeht ? Alles was ich beim googeln gefunden habe, war das : https://issues.apache.org/bugzilla/show_bug.cgi?id=49844 Was soll diese "redir#1" in Zeile 4 und 5 bei der Request ID ? Und kann ich die Tatsache, daß die RID in Zeile 4 und 5 eine andere ist als in Zeile 1-3 so interpretieren, daß ein neuer request erzeugt wurde ? Dankbar für jede Hilfe. Bernd -- Bernd Lentes Systemadministration Institut für Entwicklungsgenetik Gebäude 35.34 - Raum 208 HelmholtzZentrum münchen bernd.lentes@helmholtz-muenchen.de phone: +49 89 3187 1241 fax: +49 89 3187 2294 http://www.helmholtz-muenchen.de/idg Leute, versauft's nit Euer ganzes Geld. Kauft lieber Bier davon ! Karl Valentin 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
On 03/26/2013 09:38 PM, Lentes, Bernd wrote:
Hi,
aus gegebenem Anlaß muß ich mich mit mod_rewrite beschäftigen. Einfach ist anders ! Bin seit Stunden die Doku auf apache.org am Lesen, komme aber im Moment nicht weiter. Bin jetzt am testen. Habe folgende Konfiguration:
============================= ...
RewriteLog /var/log/apache2/rewrite.log RewriteLogLevel 2 Alias /test /hallo
<Directory "/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.
passiert folgendes:
========================================= 146.107.x.x - - [26/Mar/2013:21:19:26 +0100] [mouseidgenes.helmholtz-muenchen.de/sid#7fedaa020a28][rid#7fedaa095978/initial] (2) [perdir /hallo/] rewrite '' -> 'MouseIDGenes' 146.107.x.x - - [26/Mar/2013:21:19:26 +0100] [mouseidgenes.helmholtz-muenchen.de/sid#7fedaa020a28][rid#7fedaa095978/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#7fedaa095978/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#7fedaa099f78/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#7fedaa099f78/initial/redir#1] (1) [perdir /hallo/] initial URL equal rewritten URL: /hallo/MouseIDGenes [IGNORING REWRITE] ========================================
Ich verstehe das folgendermaßen: Durch den Alias landet der Request erst mal im betr. directory-container (hallo), da ja test ein Alias für hallo ist.
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. 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. 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. 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/ 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. 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. 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. Ü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 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. 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. Dass die RewriteRule auch auf "MouseIDGenes" passt, ist ein Fehler. Hier solltest Du vielleicht etwas machen, z.B.: RewriteRule ^$ MouseIDGenes oder RewriteRule ^(?!MouseIDGenes)$ MouseIDGenes Sonst macht er eigentlich, was er sollte. Insgesamt ist mod_rewrite in Containern keine gute Idee. Wenn es komplett in der URI Translation Phase arbeiten kann, ist es viel effektiver, insbesondere wenn Du teure Authentifizierung/Autorisierung benutzt.
In diesem Container gibt es einen RewriteRule, die ausgeführt wird. Anschließend wird die RewriteBase vor die substitution geklemmt. OK ?
Dieser "neue" request (/test/MouseIDGenes) landet durch den alias test wieder im hallo container. /test/ wird entfernt, MouseIDGenes wird zu MouseIDGenes substituiert, was mod_rewrite richtigerweise als Unsinn erkennt. OK ?
Was mir nicht klar ist: wieso wird vor der Substitution in Zeile 4 quasi noch einmal ein neuer request erzeugt ? Wieso gibt sich mod_rewrite nicht mit dem redirect in Zeile 3 zufrieden und hört auf ? Und kann mir bitte jemand helfen, was die Interpretation des mod_rewrite-logs angeht ? Alles was ich beim googeln gefunden habe, war das : https://issues.apache.org/bugzilla/show_bug.cgi?id=49844 Was soll diese "redir#1" in Zeile 4 und 5 bei der Request ID ? Und kann ich die Tatsache, daß die RID in Zeile 4 und 5 eine andere ist als in Zeile 1-3 so interpretieren, daß ein neuer request erzeugt wurde ?
Dankbar für jede Hilfe.
Zu Deinen Fragen vom 25.3. auf users@httpd: 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. 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): <Directory ...> RewriteRule ^bla blub [R] ... Viele Grüße, Torsten -- 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
Torsten schrieb:
Habe folgende Konfiguration:
============================= ...
RewriteLog /var/log/apache2/rewrite.log RewriteLogLevel 2 Alias /test /hallo
<Directory "/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):
<Directory ...> 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
On 03/27/2013 09:51 PM, Lentes, Bernd wrote:
Torsten schrieb:
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.
Klar. Hier war ich ein wenig konfus. Alias schreibt natürlich in einen Pfad im Filesystem um. Ursprünglich stand dort auch ServerRoot, was natürlich auch nur stimmt, wenn das Alias Ziel nicht mit einem Slash beginnt. Also vergiss das DocumentRoot Gefasel. Der Rest stimmt aber.
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 ?
Ja. Der Grund ist, dass die neue Location andere Zugriffsberechtigungen erfordern kann. Diese werden aber in den sog. AAA Phasen (Access, Authentication und Authorization) geprüft. Die sind in Fixup vorbei. D.h. um erneut zu prüfen, müssen wir zurück auf Anfang.
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 ?
Wenn er keine RewriteRules anwendet, kommt auch im RewriteLog nichts an.
================================================================ ... 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.
Für /MouseIDGenes gibt es offensichtlich keine RewriteRules, bzw. keinen Container, der RewriteRules enthält.
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 ?
Das habe ich schon beantwortet. RewriteRule ^$ MouseIDGenes würde nur matchen, wenn nach /hallo/ nichts mehr kommt. RewriteRule ^(?!MouseIDGenes)$ MouseIDGenes matcht immer, außer bei /hallo/MouseIDGenes. Hier würde die Rule also auch für /hallo/blub angewendet.
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 ?
Ja freilich. Der Code von mod_rewrite enthält eine Funktion namens apply_rewrite_list. Diese wendet *alle* Rules an, die zur Konfiguration des Requests und zum Context passen. Erst wenn diese Funktion fertig ist, passiert das oben beschriebene.
Hallo Torsten,
noch nie habe ich so eine ausführliche Antwort bekommen. Vielen Dank und Respekt !
Wenn es die Zeit erlaubt, mache ich das schon mal gern. Deine Mail auf users@httpd kam zu einem Zeitpunkt, als ich diese nicht hatte. Außerdem beantworte ich keine Fragen zu distributionsspezifischem Kram, wo die Leute mit den /modernen/, hochgradig zerstückelten Konfigurationsdateien nicht klar kommen. Ich benutze immer meinen eigenen Apache mit einer Konfigurationsdatei und kaum Kommentaren. Da sieht man wenigstens, was passiert. Ich erwarte, dass ein Fragender seine Hausaufgaben gemacht, die Doku gelesen und ggf. schon ein wenig experimentiert hat. Außerdem sollte er ein recht komplettes Bild seines Problems schildern. Du hast in die Kategorie gepasst. Sowas wie, "Wie konfiguriere ich den Apache für besten Durchsatz? Bitte um Ratschläge" beantworte ich nicht. Könnte ich zwar. Aber das ist ein zu komplexes Thema und der Fragende würde die Antwort sowieso nicht verstehen, da er sich vorher nicht damit beschäftigt hat. Mein plötzlicher Fundus an Zeit ist übrigens darin begründet, dass ich ein Opfer der Reutax Geschichte bin. Wenn es also jemanden gibt, der gerade einen Perl/Apache/Linux Spezialisten sucht, könnte er mich finden. Torsten -- 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
Torsten schrieb:
Wenn es die Zeit erlaubt, mache ich das schon mal gern. Deine Mail auf users@httpd kam zu einem Zeitpunkt, als ich diese nicht hatte. Außerdem beantworte ich keine Fragen zu distributionsspezifischem Kram, wo die Leute mit den /modernen/, hochgradig zerstückelten Konfigurationsdateien nicht klar kommen. Ich benutze immer meinen eigenen Apache mit einer Konfigurationsdatei und kaum Kommentaren. Da sieht man wenigstens, was passiert.
Ich erwarte, dass ein Fragender seine Hausaufgaben gemacht, die Doku gelesen und ggf. schon ein wenig experimentiert hat. Außerdem sollte er ein recht komplettes Bild seines Problems schildern. Du hast in die Kategorie gepasst.
Sowas wie, "Wie konfiguriere ich den Apache für besten Durchsatz? Bitte um Ratschläge" beantworte ich nicht. Könnte ich zwar. Aber das ist ein zu komplexes Thema und der Fragende würde die Antwort sowieso nicht verstehen, da er sich vorher nicht damit beschäftigt hat.
Mein plötzlicher Fundus an Zeit ist übrigens darin begründet, dass ich ein Opfer der Reutax Geschichte bin. Wenn es also jemanden gibt, der gerade einen Perl/Apache/Linux Spezialisten sucht, könnte er mich finden.
Torsten []
Hi, ich werde mir das über die Feiertage noch mal in Ruhe anschauen und eventl. hier noch mal mit einigen Fragen auftauchen. Dir viel Glück bei der Jobsuche ! Bist Du mobil und ungebunden ? Das hat meine Möglichkeiten bei der Jobsuche vor 8 Jahren vervielfacht. 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
Hi, jetzt habe ich das mit der substitution soweit verstanden. Jetzt noch mal ein paar Fragen zum matching. Ich beziehe mich auf folgenden Abschnitt der Doku: "What is matched? In VirtualHost context, The Pattern will initially be matched against the part of the URL after the hostname and port, and before the query string (e.g. "/app1/index.html"). In Directory and htaccess context, the Pattern will initially be matched against the filesystem path, after removing the prefix that lead the server to the current RewriteRule (e.g. "app1/index.html" or "index.html" depending on where the directives are defined)." Was bedeutet " In Directory and htaccess context, ... against the filesystem path, after removing the prefix that lead the server to the current RewriteRule" ? Welches Prefix wird genau entfernt ? Ist da der Pfad gemeint, der im <Directory ...> steht ? Was ist, wenn mehrere Rewrite Rules hintereinander folgen ? Erste Rule wird gematcht, ggf. substituiert, dann nächste Rule gematcht (gegen die Substitution der ersten Rule), ggf. substituiert ... ? Folgendes Szenario: ein vhost mit RewriteRule im vhost container. Im diesem vhost ein directory container für DocumentRoot, ebenfalls mit einer Rewrite Rule. Es kommt ein request für den vhost, der im directory container landet. Welche RewriteRule wird zuerst abgearbeitet ? " On the first RewriteRule it is applied to the (%-decoded) URL-path of the request; subsequent patterns ...": gilt das/ immer/ für die erste RewriteRule, das gegen die URL gematcht wird ? Unabhängig vom context ? Sorry, wenn ich da viell. doppelt frage. Ich will's aber verstehen und nicht nur rumklicken und probieren. Vielen Dank. 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
Hallo Bernd, On 03/31/2013 02:52 PM, Lentes, Bernd wrote:
jetzt habe ich das mit der substitution soweit verstanden. Jetzt noch mal ein paar Fragen zum matching.
vorab folgendes. Alles außerhalb von <directory> oder .htaccess (oder auch <location> oder <files>), also alles, was entweder in keinem Container oder direkt unterhalb eines <VirtualHost> Containers steht nennt sich server-context bzw. vhost-context. Innerhalb <directory> oder .htaccess ist directory-context. Innerhalb <location> heißt auch directory-context, unterscheidet sich aber in Details. Hier muss in der Doku die Balance gewahrt werden zwischen Genauigkeit und Verwirrung der Leser. In den meisten Fällen passt die Trennung zwischen server-context und directory-context recht gut. Der große Unterschied zwischen server-context und directory-context ist, dass die Konfiguration für den Servercontext beim Start des Apache berechnet werden kann. Für alle Container kann die Konfiguration des Containers auch vorausberechnet werden, nicht aber für .htaccess Files. Zur Laufzeit wird dann die Konfiguration eines konkreten Requests berechnet, indem praktisch ein Klon der Servercontextkonfiguration genommen und mit allen passenden Directorycontextkonfigurationen ergänzt wird. Das passiert in der "Map to Storage" Phase. Eine RewriteRule im Directorycontext ist eigentlich ein komplett anderes Ding als eine RewriteRule im Servercontext. Sie tun etwas Ähnliches, haben aber eigentlich nicht viel miteinander zu tun. Sie werden zu unterschiedlichen Zeitpunkten während der Abarbeitung des Requests ausgewertet.
Ich beziehe mich auf folgenden Abschnitt der Doku: "What is matched? In VirtualHost context, The Pattern will initially be matched against the part of the URL after the hostname and port, and before the query string (e.g. "/app1/index.html").
Das stimmt so nicht. Verglichen wird immer mit r->filename. Eine RewriteRule im Servercontext (oder VHost) wird in der "URI Translation Phase" abgearbeitet. Normalerweise ist zu diesem Zeitpunkt r->filename leer. Wenn dem so ist, initialisiert mod_rewrite r->filename mit r->uri vor der Verarbeitung der ersten RewriteRule. Mod_rewrite enthält (ziemlich am Ende) folgende Funktion. Ich habe den Kram entfernt, die für die aktuelle Diskussion unwichtig sind. static void register_hooks(apr_pool_t *p) { ... ap_hook_handler(handler_redirect, NULL, NULL, APR_HOOK_MIDDLE); ... ap_hook_fixups(hook_fixup, aszPre, NULL, APR_HOOK_FIRST); ap_hook_fixups(hook_mimetype, NULL, NULL, APR_HOOK_LAST); ap_hook_translate_name(hook_uri2file, NULL, NULL, APR_HOOK_FIRST); } Zunächst ist die letzte Zeile interessant. Sie deklariert die Funktion, die in der URI Translation Phase ausgeführt werden soll. Der letzte Parameter gibt an, dass sie als eine der ersten Funktionen in dieser Phase ausgeführt werden will. Mod_alias enthält hier diese ähnliche Zeile: ap_hook_translate_name(translate_alias_redir,NULL,aszSucc,APR_HOOK_MIDDLE); Damit wird bekanntgegeben, dass die Funktion translate_alias_redir in der URI Translation Phase aufgerufen werden soll. APR_HOOK_MIDDLE besagt, dass es keine Präferenzen gibt, wann das geschehen soll. Modperl benutzt auch einen Handler für die URI Translation Phase. Dieser wird aber mit APR_HOOK_REALLY_FIRST als letztem Parameter installiert. Er soll also auf jedem Fall vor mod_rewrite aufgerufen werden. Wenn Du also alle 3 Module benutzt, wird in der URI Translation Phase zuerst der modperl Handler, dann der von mod_rewrite und als letzter der von mod_alias aufgerufen. Das stimmt nicht ganz, denn jeder Handler kann durch seinen Return-Code angeben, ob die Phase beendet ist oder ob der nächste Handler auch noch aufgerufen werden soll. Jetzt könnte ein modperl Handler in der Translation Phase r->filename setzen und mit dem Return Code OK anzeigen, dass die Phase beendet ist. Dann würden die Handler von mod_rewrite und mod_alias nicht mehr aufgerufen werden. Er könnte aber auch r->filename setzen und DECLINED zurück geben. Damit sagt er, dass die nächsten Handler auch noch aufgerufen werden sollen, solange bis entweder keine Handler für die Phase mehr da sind, oder bis einer OK liefert. Der mod_rewrite Handler liefert DECLINED, wenn z.B. "RewriteEngine Off" angegeben ist. Er liefert auch DECLINED, wenn keine passenden RewriteRules gefunden wurden, oder wenn das PT Flag angegeben wurde. Nur in dem Fall hat mod_alias eine Chance einzugreifen. Findet mod_rewrite eine passende Rule ohne PT Flag gibt der Handler OK zurück und beendet damit die URI Translation Phase. Setzt nun in unserem hypothetischen Setup der modperl Handler r->filename und gibt DECLINED zurück, wird der mod_rewrite Handler aufgerufen. Er stellt fest, dass r->filename bereits gesetzt ist und wendet die erste Rule darauf an. Der entsprechende Code sieht so aus: if (r->filename == NULL) { r->filename = apr_pstrdup(r->pool, r->uri); rewritelog((r, 2, NULL, "init rewrite engine with requested uri %s", r->filename)); } else { rewritelog((r, 2, NULL, "init rewrite engine with passed filename " "%s. Original uri = %s", r->filename, r->uri)); } /* * now apply the rules ... */ rulestatus = apply_rewrite_list(r, conf->rewriterules, NULL); Die zweite Zeile kopiert r->uri nach r->filename. r->uri wurde in einer früheren Phase aus dem Request gebildet. Wenn Du folgende Frage stellst: GET /bla/blub?fritz=12 dann ist /bla/blub die URI als r->uri verfügbar. "fritz=12" steht in r->args. Das ist der Grund, warum Du in einer RewriteRule keinen Zugriff auf den Querystring hast. Dafür brauchst Du RewriteCond. conf->rewriterules enthält nur die Rules im Servercontext. Die Rules aus <directory> Containern kann er an der Stelle noch nicht kennen.
In Directory and htaccess context, the Pattern will initially be matched against the filesystem path, after removing the prefix that lead the server to the current RewriteRule (e.g. "app1/index.html" or "index.html" depending on where the directives are defined)."
Also ganz genau ist das auch nicht. Und das komplette Bild ist recht komplex. Der Apache kennt in diesem Zusammenhang folgende 2 Felder, r->filename und r->path_info. Diese werden normalerweise von default-Handler der "Map to Storage" Phase gesetzt. Das muss aber nicht sein. Solche Module wie modperl können die "Map to Storage" Phase komplett übernehmen und tun, was sie wollen. Sie können die Felder auch später ändern. Ich beschreibe jetzt den Normalfall. Angenommen vor der "Map to Storage" Phase ist r->filename /mein/existierender/Pfad und dieser Pfad existiert im Filesystem wirklich, egal ob Directory oder plain File. Dann ist nach der "Map to Storage" Phase r->filename immer noch /mein/existierender/Pfad. Jetzt nehmen wir an, vor Map to Storage ist r->filename /eine/directory/nicht-existierender-Teil, wobei /eine/directory/ als Verzeichnis existiert, nicht-existierender-Teil aber nicht. Auch hier ändert sich r->filename nicht. Es bleibt bei /eine/directory/nicht-existierender-Teil. Nun nehmen wir an, vor Map to Storage ist r->filename /eine/directory/nicht-existierend/bla/bla. Nach Map to Storage enthält r->filename nur noch /eine/directory/nicht-existierend. r->path_info wurde zu /bla/bla. Noch ein anderer Fall, vor Map to Storage ist r->filename /eine/directory/existing-plain-file/bla/bla. Danach wird r->filename zu /eine/directory/existing-plain-file und r->path_info zu /bla/bla. Ich glaube, ich habe jetzt alle Fälle. Gewöhnlich ändern sich r->filename und r->path_info dann nicht nochmal. D.h. sie kommen so in der Fixup Phase an. Wie oben angedeutet ist das aber kein Gesetz. Der Fixup-Handler von mod_rewrite führt nun nach ein wenig Initialisierung folgende Funktion aus: rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory); "dconf" steht dabei für Directory Configuration. "dconf->rewriterules" enthält die Rules aus einem <Directory> Container oder einem .htaccess File. In dconf->directory hat sich mod_rewrite das Verzeichnis gemerkt, das zu dem Container bzw. dem .htaccess File gehört. Bei der Verarbeitung JEDER Rule wird nun Folgendes zur Initialisierung ausgeführt. (Ich habe wieder unwichtige Teile gelöscht.) ctx->uri = r->filename; if (ctx->perdir) { apr_size_t dirlen = strlen(ctx->perdir); ... /* Since we want to match against the (so called) full URL, we have * to re-add the PATH_INFO postfix */ if (r->path_info && *r->path_info) { rewritelog((r, 3, ctx->perdir, "add path info postfix: %s -> %s%s", ctx->uri, ctx->uri, r->path_info)); ctx->uri = apr_pstrcat(r->pool, ctx->uri, r->path_info, NULL); } /* Additionally we strip the physical path from the url to match * it independent from the underlaying filesystem. */ if (!is_proxyreq && strlen(ctx->uri) >= dirlen && !strncmp(ctx->uri, ctx->perdir, dirlen)) { rewritelog((r, 3, ctx->perdir, "strip per-dir prefix: %s -> %s", ctx->uri, ctx->uri + dirlen)); ctx->uri = ctx->uri + dirlen; } } /* Try to match the URI against the RewriteRule pattern * and exit immediately if it didn't apply. */ rewritelog((r, 3, ctx->perdir, "applying pattern '%s' to uri '%s'", p->pattern, ctx->uri)); rc = !ap_regexec(p->regexp, ctx->uri, AP_MAX_REG_MATCH, regmatch, 0); Zunächst sehen wir, dass auf r->filename gearbeitet wird. Dieser Wert wird in ctx->uri geschrieben und in der letzten Zeile verwendet, um zu ermitteln, ob die Rule passt. "ctx->perdir" enthält hier den Wert aus "dconf->directory", d.h. "/dir" aus "<Directory /dir>". Wenn r->path_info gesetzt ist, wird es an ctx->uri angehängt. Dann wird geprüft, ob ctx->uri mit ctx->perdir beginnt. Wenn ja, wird dieser Präfix abgeschnitten. Das Resultat wird gegen die Rule geprüft.
Was bedeutet " In Directory and htaccess context, ... against the filesystem path, after removing the prefix that lead the server to the current RewriteRule" ?
Siehe oben.
Welches Prefix wird genau entfernt ? Ist da der Pfad gemeint, der im <Directory ...> steht ?
Im Prinzip ja, aber siehe oben.
Was ist, wenn mehrere Rewrite Rules hintereinander folgen ? Erste Rule wird gematcht, ggf. substituiert, dann nächste Rule gematcht (gegen die Substitution der ersten Rule), ggf. substituiert ... ?
Wenn eine passende Regel gefunden wurde, enthält der Folgecode u.a. folgendes: /* Add the previously stripped per-directory location prefix, unless * (1) it's an absolute URL path and * (2) it's a full qualified URL */ if ( ctx->perdir && !is_proxyreq && *r->filename != '/' && !is_absolute_uri(r->filename)) { rewritelog((r, 3, ctx->perdir, "add per-dir prefix: %s -> %s%s", r->filename, ctx->perdir, r->filename)); r->filename = apr_pstrcat(r->pool, ctx->perdir, r->filename, NULL); } D.h. r->filename wird für die nächste Rule gesetzt. Wenn das Ergebnis der Substitution nicht mit einem Slash beginnt und auch keine absolute URI (scheme://...) ist, wird ctx->perdir vorangestellt.
Folgendes Szenario: ein vhost mit RewriteRule im vhost container. Im diesem vhost ein directory container für DocumentRoot, ebenfalls mit einer Rewrite Rule. Es kommt ein request für den vhost, der im directory container landet. Welche RewriteRule wird zuerst abgearbeitet ?
Die Frage solltest Du inzwischen selbst beantworten können.
" On the first RewriteRule it is applied to the (%-decoded) URL-path of the request; subsequent patterns ...": gilt das/ immer/ für die erste RewriteRule, das gegen die URL gematcht wird ? Unabhängig vom context ?
Die Frage solltest Du inzwischen fast selbst beantworten können. Hier die bisher fehlende Information: Auch der Fixup Handler von mod_rewrite enthält vor dem Aufruf von apply_rewrite_list folgenden Code: if (r->filename == NULL) { r->filename = apr_pstrdup(r->pool, r->uri); rewritelog((r, 2, "init rewrite engine with requested uri %s", r->filename)); } Normalerweise kommt es nicht vor, dass in der Fixup Phase r->filename nicht gesetzt ist. Wenn aber doch, wird es mit r->uri initialisiert. So, noch eine solche Mail werde ich nicht schreiben. Wenn Du es genauer wissen willst, nimm die ultimative Doku, den Source Code, und lies. Das ist gar nicht so schwer, wie man vermuten würde. Torsten -- 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
Hi, habe noch einige Fragen zu mod_rewrite. Ich beziehe mich auf die Beispiele in http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html . Fangen wir mit dem Beispiel im Server-Kontext an: Given Rule resulting substitution ^/somepath(.*) otherpath$1 invalid, not supported Ist das invalid, weil otherpath ohne Pfad angegeben wurde und man daher nicht weiß, wo otherpath sein soll ? 2. Beispiel: ^/somepath(.*) /otherpath$1 /otherpath/pathinfo Passt, da das result einen Pfad hat. Ist der absolut oder relativ zu DocumentRoot ? DirectoryContext: ^localpath(.*) otherpath$1 /somepath/otherpath/pathinfo otherpath wird an die RewriteBase angehangen, passt. Oder ? ^localpath(.*) /otherpath$1 /otherpath/pathinfo Da /otherpath angegeben wurde, wird die RewriteBase ignoriert. Oder ? Danke. 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
On 17/04/13 20:33, Lentes, Bernd wrote:
habe noch einige Fragen zu mod_rewrite. Ich beziehe mich auf die Beispiele in http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html . Fangen wir mit dem Beispiel im Server-Kontext an:
Given Rule resulting substitution ^/somepath(.*) otherpath$1 invalid, not supported
Ist das invalid, weil otherpath ohne Pfad angegeben wurde und man daher nicht weiß, wo otherpath sein soll ?
ja.
2. Beispiel: ^/somepath(.*) /otherpath$1 /otherpath/pathinfo Passt, da das result einen Pfad hat. Ist der absolut oder relativ zu DocumentRoot ?
"/otherpath/pathinfo" ist ein Filename. Also genau wie bei Alias, nix DocRoot.
DirectoryContext: ^localpath(.*) otherpath$1 /somepath/otherpath/pathinfo otherpath wird an die RewriteBase angehangen, passt. Oder ?
"/somepath/otherpath/pathinfo" ist hier *kein* Filename, sondern eine URI. Deine Frage zu RewriteBase konnte ich nicht parsen. Daher eine Erklärung, wozu RewriteBase gebraucht wird. Wenn Deine Dokumente alle unter DocumentRoot liegen, brauchst Du kein RewriteBase. Dann passiert nämlich folgendes: URI /a/b/c wird zu Filename /Doc/Root/a/b/c. In <Directory /Doc/Root/a> steht eine RewriteRule ^([a-z])(.*) X/_$1_$2. Modrewrite macht also aus /Doc/Root/a/b/c schneidet davon /Doc/Root/a/ ab und prüft, ob die RewriteRule passt. Da das b/c mit einem kleinen Buchstaben beginnt, wird also aus /Doc/Root/a/b/c zunächst /Doc/Root/a/X/_b_/c. Nun ist das ein Filename. Modrewrite muss daraus aber eine URI machen. Ist keine RewriteBase angegeben, wird angenommen, die Abbildung URI=>Filename passierte einfach durch Voranstellen von DocumentRoot. Also besteht die umgekehrte Abbildung Filename=>URI einfach im Abschneiden des Präfixes. Damit wird aus dem Filenamen /Doc/Root/a/X/_b_/c die URI /a/X/_b_/c. Mit dieser URI wird praktisch eine neue Anfrage gestartet, die über Alias oder Proxy oder irgendwas anderes ganz woanders rauskommen kann. Wenn nun die Abbildung URI=>Filename geändert wurde, beispielsweise durch Alias, ist die umgekehrte Abbildung auch eine andere. Jetzt brauchst Du RewriteBase, um dem Apache diese Umkehrabbildung zu erklären. Angenommen, Du hast ein Alias /a /Wo/Anders. Weiterhin angenommen, Du hast einen Container <Directory /Wo/Anders/b> mit einer RewriteRule ^([a-z])(.*) X/_$1_$2. Dann macht Alias aus der URI /a/b/c/d zunächst den Filenamen /Wo/Anders/b/c/d. Der Container passt. ModRewrite schneidet den Container-Präfix ab und erhält c/d. Die RewriteRule passt auch und aus /Wo/Anders/b/c/d wird /Wo/Anders/b/X/_c_/d. Von diesem Filenamen kannst Du aber /Doc/Root nicht abschneiden. Wenn Du nun keine RewriteBase angegeben hast, wird der Apache /Wo/Anders/b/X/_c_/d als neue URI benutzen und wahrscheinlich einen 404 erzeugen, es sei denn der zweite Punkt aus der Doku zu RewriteBase trifft zu: Sie brauchen keine RewriteBase, wenn folgendes zutrifft: * The filesystem path to the directory containing the RewriteRule, suffixed by the relative substitution is also valid as a URL path on the server (this is rare). Wenn Du in dem Container nun RewriteBase /a/b gesagt hast, ersetzt der Apache für die Umkehrabbildung den Directory Container /Wo/Anders/b im Filenamen durch RewriteBase /a/b. Damit wird aus dem Filenamen /Wo/Anders/b/X/_c_/d die URI /a/b/X/_c_/d. RewriteBase ist also praktisch die URI, die zum Directory Container führt.
^localpath(.*) /otherpath$1 /otherpath/pathinfo Da /otherpath angegeben wurde, wird die RewriteBase ignoriert. Oder ?
Ja. Aber wie schon gesagt, "/otherpath/pathinfo" wird als URI interpretiert und praktisch als neuer Request durch das System geschleust. Bernd, es geht nicht nur Dir so. Als ich so um das Jahr 2000 rum das erste mal mit mod_rewrite experimentieren durfte, habe ich RewriteBase auch nicht verstanden. Ich habe damals alles im Server-Context gemacht und Dir-Context gemieden wie der Teufel das Weihwasser. Ich glaube, erst, wenn Du im Prinzip weißt, wie der Apache einen Request bearbeitet - die Phasen, von denen ich letztes mal gesprochen habe, und wenn Du weißt, was diese Phasen machen, und wenn Du zusätzlich weißt, dass mod_rewrite ausschließlich r->filename bearbeitet, erst dann kannst Du RewriteBase wirklich verstehen. Vorher bleibt das schwammig. Eine recht gute Doku zum Thema findest Du bei mod_perl: http://perl.apache.org/docs/2.0/user/handlers/http.html Torsten -- 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
Torsten Förtsch schrieb:
Wenn nun die Abbildung URI=>Filename geändert wurde, beispielsweise durch Alias, ist die umgekehrte Abbildung auch eine andere. Jetzt brauchst Du RewriteBase, um dem Apache diese Umkehrabbildung zu erklären. Angenommen, Du hast ein Alias /a /Wo/Anders. Weiterhin angenommen, Du hast einen Container <Directory /Wo/Anders/b> mit einer RewriteRule ^([a-z])(.*) X/_$1_$2. Dann macht Alias aus der URI /a/b/c/d zunächst den Filenamen /Wo/Anders/b/c/d. Der Container passt. ModRewrite schneidet den Container-Präfix ab und erhält c/d. Die RewriteRule passt auch und aus /Wo/Anders/b/c/d wird /Wo/Anders/b/X/_c_/d. Von diesem Filenamen kannst Du aber /Doc/Root nicht abschneiden.
Wenn Du nun keine RewriteBase angegeben hast, wird der Apache /Wo/Anders/b/X/_c_/d als neue URI benutzen und wahrscheinlich einen 404 erzeugen, es sei denn der zweite Punkt aus der Doku zu RewriteBase trifft zu:
Sie brauchen keine RewriteBase, wenn folgendes zutrifft:
* The filesystem path to the directory containing the RewriteRule, suffixed by the relative substitution is also valid as a URL path on the server (this is rare).
filesystem path /Wo/Anders/b/X/_c/_d müßte demzufolge dann zugänglich sein über http://host.domain.tld/Wo/Anders/b/X/_c/_d . Dann müßte es eine DocumentRoot / geben, oder ? Oder eine Location /Wo/Anders/b/X/_c/_d ?
Wenn Du in dem Container nun RewriteBase /a/b gesagt hast, ersetzt der Apache für die Umkehrabbildung den Directory Container /Wo/Anders/b im Filenamen durch RewriteBase /a/b. Damit wird aus dem Filenamen /Wo/Anders/b/X/_c_/d die URI /a/b/X/_c_/d.
RewriteBase ist also praktisch die URI, die zum Directory Container führt.
^localpath(.*) /otherpath$1 /otherpath/pathinfo Da /otherpath angegeben wurde, wird die RewriteBase ignoriert. Oder ?
Ja. Aber wie schon gesagt, "/otherpath/pathinfo" wird als URI interpretiert und praktisch als neuer Request durch das System geschleust.
OK. 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
On 18/04/13 14:50, Lentes, Bernd wrote:
Wenn Du nun keine RewriteBase angegeben hast, wird der Apache
/Wo/Anders/b/X/_c_/d als neue URI benutzen und wahrscheinlich einen 404 erzeugen, es sei denn der zweite Punkt aus der Doku zu RewriteBase trifft zu:
Sie brauchen keine RewriteBase, wenn folgendes zutrifft:
* The filesystem path to the directory containing the RewriteRule, suffixed by the relative substitution is also valid as a URL path on the server (this is rare).
filesystem path /Wo/Anders/b/X/_c/_d müßte demzufolge dann zugänglich sein über http://host.domain.tld/Wo/Anders/b/X/_c/_d . Dann müßte es eine DocumentRoot / geben, oder ? Oder eine Location /Wo/Anders/b/X/_c/_d ?
Ja, DocumentRoot / wäre eine Möglichkeit. Eine andere wäre ein Alias oder z.B. auch <Location /Wo> mit einem ProxyPass drinnen, halt irgendwas, was die URI gültig macht. Möglich wäre auch /Doc/Root/Wo/Anders/b/X/_c/_d Torsten -- 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
Torsten schrieb:
On 18/04/13 14:50, Lentes, Bernd wrote:
Wenn Du nun keine RewriteBase angegeben hast, wird der Apache
/Wo/Anders/b/X/_c_/d als neue URI benutzen und wahrscheinlich einen 404 erzeugen, es sei denn der zweite Punkt aus der Doku zu RewriteBase trifft zu:
Sie brauchen keine RewriteBase, wenn folgendes zutrifft:
* The filesystem path to the directory containing the RewriteRule, suffixed by the relative substitution is also valid as a URL path on the server (this is rare).
filesystem path /Wo/Anders/b/X/_c/_d müßte demzufolge dann zugänglich sein über http://host.domain.tld/Wo/Anders/b/X/_c/_d . Dann müßte es eine DocumentRoot / geben, oder ? Oder eine Location /Wo/Anders/b/X/_c/_d ?
Ja, DocumentRoot / wäre eine Möglichkeit. Eine andere wäre ein Alias oder z.B. auch <Location /Wo> mit einem ProxyPass drinnen, halt irgendwas, was die URI gültig macht. Möglich wäre auch
/Doc/Root/Wo/Anders/b/X/_c/_d
Torsten
Hi, was für das Verständnis auch sehr hilft, ist ein Hochschrauben des LogLevels (z.B. auf 6) und ein Lesen des Logfiles von mod_rewrite. Schwer getan habe ich mich allerdings mit dem Eintrag "add path info postfix". Nach einigem googeln (http://forum.modrewrite.de/topic2220.html) und Probieren habe ich folgendes herausgefunden: Wenn ich hinter dem hostnamen und dem Port einen Pfad angebe, dessen erster Teil nicht existiert, taucht dieser Eintrag auf. Beispiel: http://hostname.domain.tld/hallo/hallohallo . hallo existiert nicht, dann steht im Log: [perdir /srv/www/vhosts/mouseidgenes/htdocs/] add path info postfix: /srv/www/vhosts/mouseidgenes/htdocs/hallo -> /srv/www/vhosts/mouseidgenes/htdocs/hallo/hallohallo . Wichtig ist, das der fehlende Teil mindestens ein abschließendes slash hat, sonst taucht der Eintrag im log nicht auf (also /hallo/... ) Alles was hinter dem fehlenden Anfang steht, wird in der Variablen PATH_INFO gespeichert. Habe ich das so richtig verstanden ? Und die Gretchenfrage: wozu soll das alles gut sein ? 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
On 19/04/13 18:53, Lentes, Bernd wrote:
was für das Verständnis auch sehr hilft, ist ein Hochschrauben des LogLevels (z.B. auf 6) und ein Lesen des Logfiles von mod_rewrite. Schwer getan habe ich mich allerdings mit dem Eintrag "add path info postfix". Nach einigem googeln (http://forum.modrewrite.de/topic2220.html) und Probieren habe ich folgendes herausgefunden: Wenn ich hinter dem hostnamen und dem Port einen Pfad angebe, dessen erster Teil nicht existiert, taucht dieser Eintrag auf. Beispiel: http://hostname.domain.tld/hallo/hallohallo . hallo existiert nicht, dann steht im Log:
[perdir /srv/www/vhosts/mouseidgenes/htdocs/] add path info postfix: /srv/www/vhosts/mouseidgenes/htdocs/hallo -> /srv/www/vhosts/mouseidgenes/htdocs/hallo/hallohallo . Wichtig ist, das der fehlende Teil mindestens ein abschließendes slash hat, sonst taucht der Eintrag im log nicht auf (also /hallo/... ) Alles was hinter dem fehlenden Anfang steht, wird in der Variablen PATH_INFO gespeichert. Habe ich das so richtig verstanden ?
Und die Gretchenfrage: wozu soll das alles gut sein ?
PATH_INFO ist ein Teil der CGI Spezifikation. Du kannst z.B. ein CGI Script unter der URL http://dom.ain/cgi/script.pl haben, das Du dann als http://dom.ain/cgi/script.pl/path/info aufrufst. Die Umgebungsvariable $PATH_INFO enthält dann /path/info. Es gibt eine parallele Variable, $PATH_TRANSLATED, die $PATH_INFO ins Filesystem abgebildet enthält. Wie (und ob) der WEB Server PATH_INFO in PATH_TRANSLATED abbildet, ist lt. Standard ihm überlassen. Eine Anwendung, wo das sinnvoll gebraucht werden kann, ist z.B., wenn Du einen Teil der Dokumente dynamisch erzeugen willst, es aber nicht so aussehen soll. Dann bildest Du mittels mod_rewrite /dyn/(.*) auf /cgi/script.pl/dyn/$1 ab. Das Script findet dann in $PATH_INFO die ursprüngliche URI und in $PATH_TRANSLATED das File, das es bearbeiten ausliefern soll. Wie und wann PATH_INFO gebildet werden, habe ich in meiner Mail vom 31.3. ausführlich beschrieben. Torsten -- 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
participants (2)
-
Lentes, Bernd
-
Torsten Förtsch