Host-Feld im HTTP-Header manipulieren funktionert nicht

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
sysrq1
User
Beiträge: 8
Registriert: Donnerstag 15. März 2007, 17:45

Woher bekommt ein Webserver (wie es z.B. Apache einer ist) Informationen von einem Webclient (wie es z.B. Firefox einer ist), der ihm ein Request schickt?
Handelt es sich dabei nur um die Informationen, die sich im HTTP-Header finden lassen, oder gibt es noch mehr Informationsquellen?

Ich frage danach, da ich bei einem Code immer einen 'HTTP Error 404: Not found' Fehler erhalte, obwohl ich den HTTP-Header 'geeignet' manipuliert habe.

Ich beschreibe es mal ein wenig:
ich will diese Seite mit Firefox aufrufen http://www.aist.go.jp/RIODB/SDBS/cgi-bi ... laimer.cgi klappt auch wunderbar.

Dann habe ich mal ein DNS-Lookup unter http://www.dnsreport.com/tools/dnsrepor ... aist.go.jp durchgeführt und als Ergebnis die IP-Adressen 150.29.246.137 und 150.29.246.153 erhalten.

Sind diese beiden Adressen 'gleichberechtigt', oder gibt es eine falsche und eine richtige?

Nun versuche ich das 'www.aist.go.jp' mit einem 150.29.246.137 zu ersetzen. Ich rufe also mit Firefox http://150.29.246.137/RIODB/SDBS/cgi-bi ... laimer.cgi auf. Dabei kommt es aber zu dem 'HTTP Error 404: Not found' Fehler.

Was ist hier schief gelaufen?

Mein erster Gedanke war, dass bei dem fehlgeschlagenen Versuch das Head-Feld im HTTP-Header '150.29.246.137' und nicht mehr 'www.aist.go.jp' lautet. Könnte das denn Server stören.

Um das zu überprüfen habe ich ein kleines Python-Skript geschrieben, welches http://150.29.246.137/RIODB/SDBS/cgi-bi ... laimer.cgi aufruft, ABER das Host-Feld im HTTP-Header auf 'www.aist.go.jp' setzt.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*- 

import urllib
import urllib2

opener = urllib2.build_opener()
opener.addheaders = [('Host','www.aist.go.jp'),('User-agent', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20060601 Firefox/2.0.0.3 (Ubuntu-edgy)'),('Accept','text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5'),('Accept-Language','de-de,en-us;q=0.7,en;q=0.3'),('Accept-Encoding','gzip,deflate'),('Accept-Charset','ISO-8859-1,utf-8;q=0.7,*;q=0.7'), ('Keep-Alive','300'),('Connection','keep-alive')]
#response = opener.open("http://www.aist.go.jp/RIODB/SDBS/cgi-bin/cre_disclaimer.cgi")
response = opener.open("http://150.29.246.137/RIODB/SDBS/cgi-bin/cre_disclaimer.cgi")

print response.read()
Dennoch kommt es auch in dem Skript zu dem HTTP 404 Fehler. Wie kann das sein? Kann sich das hier jemand erklären?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

sysrq1 hat geschrieben:Nun versuche ich das 'www.aist.go.jp' mit einem 150.29.246.137 zu ersetzen. Ich rufe also mit Firefox http://150.29.246.137/RIODB/SDBS/cgi-bi ... laimer.cgi auf. Dabei kommt es aber zu dem 'HTTP Error 404: Not found' Fehler.

Was ist hier schief gelaufen?
Du hast die Domain-Informationen weggelassen und daher weiß der Webserver nicht aus welchem Kontext du ihn aufgerufen hast und kann auch nicht den entsprechenden vHost-Eintrag nehmen und dir die Daten so nicht schicken.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
sysrq1
User
Beiträge: 8
Registriert: Donnerstag 15. März 2007, 17:45

Ich habe im Internet nach einer HTTP-Header Spezifikation gesucht und das hier gefunden http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

Dort kann ich aber kein 'domain'-Feld finden. Leonidas, du hast von '...Domain-Informationen...' gesprochen, ergo gehe ich mal davon aus, dass du mehrere Felder meinst. Welche Header-Felder meinst du? Wie heissen diese?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

sysrq1 hat geschrieben:Dort kann ich aber kein 'domain'-Feld finden. Leonidas, du hast von '...Domain-Informationen...' gesprochen, ergo gehe ich mal davon aus, dass du mehrere Felder meinst. Welche Header-Felder meinst du? Wie heissen diese?
Ein HTTP-Request sieht so aus, dass zu einem Host eine Verbindung aufgebaut wird und dort wird dann eine GET-Aktion ausgeführt.

Nun ist es aber so, dass ein HTTP-Server ermitteln kann, über welchen Domainnamen er angesprochen wurde und je nachdem unterschiedlichen Inhalt bieten kann, sowas nennt man dann vHost und je vHost kann dort dann ganz unterschiedlicher Inhalt übertragen werden.

Ein Beispiel: Wenn man mit host, nslookup oder dig den A-Record von xivilization.net ansieht, dann bekommt man 80.86.91.40 zurückgeliefert. Selbiges gilt für den A-Record von marek.homelinux.net, jedoch kommt man an einer ganz anderen Stelle an. Wenn man nun aber direkt auf 80.86.91.40 geht, bekommt man eine ganz, ganz andere Seite zu sehen.

Das selbe ist bei dir der Fall: du greifst auf die Server-IP direkt zu und der Server kann ihr auf diese weise nicht den entsprechenden vHost zuordnen, weil er die Domain-Informationen nicht bekommt.

Was spricht dagegen, auf die Seite mit dem Domainnamen und nicht dem Hostnamen zuzugreifen? Es scheint mir, dass der Host-Header erst in HTTP 1.1 eingeführt wurde (zumindest konnte ich dazu im RFC 1945 nichts finden) und ich weiß nicht, ob urllib2 HTTP 1.1 unterstützt (in der Doku steht dazu leider nichts).
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
sysrq1
User
Beiträge: 8
Registriert: Donnerstag 15. März 2007, 17:45

Bei einem DNS-Lookup habe ich erfahren, dass die Seite gleich zwei mögliche Adressen hat. Im Internet habe ich dann gelesen, dass es dabei um eine Art von Load-Sharing handelt. Evtl. um die Last auf zwei verschiedene Webserver zu verteilen.

Nun ist es so, dass die Seite mit Cookie's UND auch mit 'Keep-Alive' arbeitet.

Das HTTP-Protokoll ist von sich selber aus eigentlich ein Zustandsloses Protokoll. Die Cookie's sollen dabei abhilfe schaffen. Ein HTTP-Header kann aber auch den Eintrag 'Connection : Keep-Alive' haben, um so eine 'persistente HTTP-Verbindung' auszubauen.

Was meint man mit 'persistenter HTTP-Verbindung'? Wie wird das realisiert? Merkt sich der Server da was?

Wenn ich mit meinem Firefox die Seite aufrufe, dann geht alles wunderbar, da ja Firefox auch die 'Keep_Alive' Option unterstützt. Aber bei python mit den urrlib und urllib2 modulen scheint das nicht standardmässig aktiviert zu sein.


Was muss ich tun, um eine Keep-Alive Verbindung aufzubauen? Haben etwa urllib und urllib2 dieses feature nicht? Welche Lösungen gibt es?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

sysrq1 hat geschrieben:Das HTTP-Protokoll ist von sich selber aus eigentlich ein Zustandsloses Protokoll. Die Cookie's sollen dabei abhilfe schaffen. Ein HTTP-Header kann aber auch den Eintrag 'Connection : Keep-Alive' haben, um so eine 'persistente HTTP-Verbindung' auszubauen.

Was meint man mit 'persistenter HTTP-Verbindung'? Wie wird das realisiert? Merkt sich der Server da was?
Nein, es geht nur darum, dass nach der Server-Reponse die TCP-Verbindung nicht geschlossen wird. Somit kann man mehrere Requests in der gleichen Verbindung schicken, womit der Overhead zum aufbauen und Schließen der Verbindungen entfällt. Im Artikel HTTP persistent connection gibt es ein Bild welches dies veranschaulicht.

Man merkt es zum Beispiel stark, wenn man viele Dateien von einem HTTP-Server runterlädt, wie beispielsweise mit APT oder insbesondere Jigdo. Mit Keepalive läuft alles wesentlich schneller, ohne wird es ziemlich schleppend, da das Aufbauen der Verbindung für jede Datei doch seine Zeit dauert (bei Jidgo sind das mehrere Tausend Dateien von einem Server).
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
sysrq1
User
Beiträge: 8
Registriert: Donnerstag 15. März 2007, 17:45

Ich habe nun mal mit Ethereal-Netzwerk-Sniffer (heute heisst er glaube ich WireShark) den Verkehr aufgezeichnet. Dabei sind mir interessante Unterschiede zwischen augefallen.

Bei einem Aufruf mit Firefox wird am Anfang ein normaler DNS-Lookup durchgeführt und die erhaltene IP-Adresse DURCHGÄNGIG für die nächsten Anfragen verwendet. Weitere DNS-Anfragen finden nicht statt.

Bei dem python-Skript sieht das anders aus. Es wird mehrmals ein DNS-Loopup durchgeführt. Das Problem scheint hier zu sein, dass zufällig aus den zwei vorhandenen IP-Adressen (siehe oberen Post) eine ausgewählt wird. Es werden also die beiden vorhandenen Webserver angesprochen. Das muss aber zu einem Fehler führen, da der eine Server nichts von den Besuchern des anderen Servers weiss und daher die Cookies (oder sonst was) nicht wiedererkennt.


Kommen solche Probleme häufiger vor? Handelt es sich hierbei um das 'HTTP-persistent-connection'-Problem? Wenn ja, wie kann ich es umgehen und fixen?
Wenn nein: wie nennt sich dieses Problem?
sysrq1
User
Beiträge: 8
Registriert: Donnerstag 15. März 2007, 17:45

Endlich habe ich den Fehler gefunden:
im Grunde habe ich alles richtig gemacht. Das setzen des Host-Feldes war genau richtig, gewessen, nur leider hat die urllib2 eine Eigenart, die mir nicht passt. Diese ist hier http://docs.python.org/lib/urllib2-examples.html ganz untern beschrieben. Dort heisst es:
Also, remember that a few standard headers (Content-Length:, Content-Type: and Host:) are added when the Request is passed to urlopen() (or OpenerDirector.open()).
Mein vorher gesetztes Headerfeld wird kurz vor dem Abschicken also nocheinmal ÜBERSCHRIEBEN, daher kommt es zu dem Fehlverhalten.

Wie könnte man wohl das beheben? Was ich müsste ich da jetzt manuell ändern? Ist das überhaupt möglich?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

sysrq1 hat geschrieben:Wie könnte man wohl das beheben? Was ich müsste ich da jetzt manuell ändern? Ist das überhaupt möglich?
Urllib2 patchen. Ich schau grad ob das im Bugtracker steht, wenn nicht dann kann ich mal schauen, dass ich einen Patch dafür schreibe.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten