HTTP: Content-Length?
lima-city → Forum → Die eigene Homepage → Internet Allgemein
anzahl
byte
code
datum
flag
frage
header
host
http
page
parameter
probier
programm
puffer
server
sprache
start
string
url
verbindung
-
Hallöchen,
da ich nun gerade nicht genau weiss wohin damit, packe ich das nun mal hier rein. Ich bin dabei, einen... Nennen wir es mal "Browser" zu Programmieren. Nun habe ich mir das HTTP-Protokoll bei Wikipedia angeschaut, wie das wohl alles funktioniert. Dort steht geschrieben, dass wohl standard-mäßig beim Response vom Webserver immer ein "Content-Length" im Header zurück geliefert wird. Funktionierte bisher auch immer ganz hübsch, auf meinem heimischen XAMPP-Server usw.. Also habe ich das ganze so aufgebaut, dass er sich erstmal den HTTP-Header durchliest, sich anschaut wie groß der Content sein sollte und dann wartet, bis der Content vollständig ist, bevor er die Verbindung schließt. Funktioniert soweit auch alles ganz wunderbar...
... bis ich auf Google schaute, wo er plötzlich keine Content-Length mehr findet, also nicht weiss, wann die Seite fertig gesendet ist. Auch andere Seiten machen das merkwürdigerweise nicht. Nun ist meine Frage: Ist "Content-Length" da kein Mittel, auf das man vertrauen sollte? Oder liegt das nur an bestimmten Umständen? Und wenn man sich darauf nicht stützen kann: Worauf kann man sich denn dann verlassen? Dass der Server die Verbindung schließt?
Wenn das Thema woanders hin gehört, bitte ich den zuständigen Moderator doch, dies dorthin zu verschieben.
Ich würde mich auf jeden Fall über Antworten freuen :) -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage
-
Wenn ich mir das entsprechnde RFC anschaue [1], dann ist der Content-Length Header nicht unter allen Umständen nötig. Du hast leider nicht geschrieben in welcher Sprache du dein Programm schreibst, aber die bei C verwendete Funktion
int recv(int s, void *msg, int len, int flags)
hat als Rückgabewert die Anzahl der tatsächlich empfangenen Bytes. Solange also der Rückgabewert gleich dem Parameter len des Funktionsaufrufes ist, kommt ziemlich sicher noch was. Wenn der Rückgabewert dagegen kleiner als len ist, dann ist die Übertragung beendet.
[1]: http://tools.ietf.org/html/rfc2616 -
kochmarkus schrieb:
Ich schreibe das ganze in vb6. Das Problem ist dabei ja, dass das ganze praktisch in "schüben" geschickt wird. Also es kommen ein mal meinetwegen die ersten 1024 Byte, danach kommen die darauf folgenden Byte. Das Header-Ende lässt sich recht gut bestimmen, da es da ja den "Marker" von zwei aufeinander folgenden <cr><lf>'s gibt. Nun ist die Frage: Wie stelle ich fest, wann der Content zuende ist? Da die Schübe ja praktisch aussehen könnten "[header]<crlf><crlf>[cont-]", "[-ent]"... Also wenn du verstehst, was ich meine. ^^ So wie ich das verstanden habe, wurde genau dafür die Content-Length eingeführt.
Wenn ich mir das entsprechnde RFC anschaue [1], dann ist der Content-Length Header nicht unter allen Umständen nötig. Du hast leider nicht geschrieben in welcher Sprache du dein Programm schreibst, aber die bei C verwendete Funktion
int recv(int s, void *msg, int len, int flags)
hat als Rückgabewert die Anzahl der tatsächlich empfangenen Bytes. Solange also der Rückgabewert gleich dem Parameter len des Funktionsaufrufes ist, kommt ziemlich sicher noch was. Wenn der Rückgabewert dagegen kleiner als len ist, dann ist die Übertragung beendet.
[1]: http://tools.ietf.org/html/rfc2616
Hier nun nochmal (wenn auch noch recht experimentell) der Quellcode.
Da dabei noch sehr viel irrelevantes Zeugs steht, was ich jetzt mal weg gelassen habe, um es immerhin ein wenig übersichtlich zu behalten. (Falls irgendwas Fehlt um das zu verstehen, ergänze ich das gerne ;) )Public Sub HTTPGet(Server As String, Host As String, Page As String) If m_State = READY Then Dim currtime As Long Dim start As Long Dim request As String Winsock1.Connect Server, 80 Dim tmpArray() As String tmpArray = Split(Time, ":") start = (Int(tmpArray(0)) * 60 * 60) + (Int(tmpArray(1)) * 60) + Int(tmpArray(2)) Do DoEvents tmpArray = Split(Time, ":") currtime = (Int(tmpArray(0)) * 60 * 60) + (Int(tmpArray(1)) * 60) + Int(tmpArray(2)) Loop Until Winsock1.State = 7 Or currtime = start + 60 If currtime = start + 60 Then RaiseEvent Error("Zeitueberschreitung"): Exit Sub request = "GET " & Page & " HTTP/1.0" & vbCrLf & _ "Host:" & Host & vbCrLf & _ "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" & vbCrLf & _ "Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7" & vbCrLf & _ "Cache-Control: no" & vbCrLf & _ "Accept-Language: de,en;q=0.7,en-us;q=0.3" & vbCrLf & _ "Cookie: " & m_Cookie & vbCrLf & vbCrLf m_State = HEADER_RECIEVING Winsock1.SendData request RaiseEvent RequestSended(request) End If End Sub Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long) Dim data As String Winsock1.GetData data m_RohContent = m_RohContent & data If m_State = HEADER_RECIEVING Then Dim tmpArray() As String tmpArray = Split(data, vbCrLf & vbCrLf, 2) m_RequestHeader = tmpArray(0) m_ContentLength = Int(Me.GetHeaderInfo("Content-Length")) data = tmpArray(1) m_State = CONTENT_RECIEVING End If m_RequestContent = m_RequestContent & data If Len(m_RequestContent) = m_ContentLength Then Winsock1.Close RaiseEvent IncomingPage(m_RequestHeader, m_RequestContent) Do DoEvents Loop While Winsock1.State = 0 End If End Sub Public Function GetHeaderInfo(InfoName As String) Dim tmpInfos() As String Dim i As Integer tmpInfos = Split(m_RequestHeader, vbCrLf) For i = 0 To UBound(tmpInfos) Dim ResArray() As String ResArray = Split(tmpInfos(i), ":") If ResArray(0) = InfoName Then GetHeaderInfo = ResArray(1): Exit Function Next i End Function
Prinzipiell funktioniert das ganze also folgendermaßen: Ich habe das ganze in ein Benutzersteuerelement gepackt, wo man praktisch nur die Sub "HTTPGet" ausführt, in dieser Sub wird dann ein Winsock-Control angesprochen, welches dann auf Port 80 zum gewählten Server verbindet und den Request sendet. Soweit funktioniert es ganz gut.
Das Winsock-Control löst nun ein Event aus, wenn Daten rein kommen, was aber nicht zwingend die ganze Webseite ist. Meist handelt es sich dabei nur um "die erste hälfte" oder so. Naja, der Rest ist wie beschrieben: Das Programm lagert das ganze erstmal zwischen, in einigen Variablen, m_RohContent, m_RequestHeader, m_RequestContent, wobei die Namensgebung etwas ungeschickt war ;) Nun ja, aus m_RequestHeader wird dann die Information "Content-Length" extrahiert.
Ich habe auch schon geschaut, ob vielleicht in bytesTotal im Event vom Winsock-Control die "gesammte größe" wiedergegeben wird, aber da steht offenbar auch nur die größe des aktuellen Daten-Blocks, was mir herzlich wenig weiterhilft.
Also ich hoffe die Problematik ist durchschaubar? :S -
Hm, mit VB hast du dir genau die Sprache ausgesucht von der ich am wenigsten Ahnung hab. Ich probier es nochmal mit einem glaub ich gut verständlichen Beispiel in C (der Verbindungsaufbau ist nicht dabei):
[...] const int PUFFERGROESSE = 1024; int DasWars = 0; /* Flag das anzeigt wann wir fertig sind */ char Puffer[PUFFERGROESSE]; /* Empfpfangspuffer mit Groesse PUFFERGROESSE */ int BytesEmpfangen = 0; /* Anzahl der *tatsächlich* empfagenne Bytes */ int Socket; /* Die Verbindung zum Server */ [...] do { /* Empfange *maximal* PUFFERGROESSE an Daten */ BytesEmpfangen = recv(Socket, Puffer, PUFFERGROESSE, 0); if(BytesEmpfangen == PUFFERGROESSE) /* Es kommt noch was */ { /* Was empfangen wurde schonmal auf Konsole ausgeben */ printf("%s", Puffer); } else if(BytesEmpfangen < PUFFERGROESSE) /* Puffer nicht mehr ganz voll */ { DasWars = 1; /* Verbindung trennen */ close(Socket); /* Den Rest ausgeben */ printf("%s", Puffer); } }while(DasWars == 0); /* Wiederholen, solange DasWars == 0 ist */
Wenn die ganze Seite (also Header + Content) jetzt z.B. 2000 Byte sind, dann werden erst 1024 empfanen (die Größe des Empfangspuffers) und dann nochmal 976 Byte (2000-1024). Nach dem zweiten Empfangen ist somit BytesEmpfangen == 976 und damit kleiner als PUFFERGROESSE, dadurch wird die Verbindung getrennt und die do...while(); Schleife beendet.
Ob man das mit VB allerdings ähnlich machen kann weiß ich nicht. -
kochmarkus schrieb: Hm, mit VB hast du dir genau die Sprache ausgesucht von der ich am wenigsten Ahnung hab. Ich probier es nochmal mit einem glaub ich gut verständlichen Beispiel in C (der Verbindungsaufbau ist nicht dabei):
Ähnliches habe ich mir auch schon gedacht. Es ist ziemlich unwahrscheinlich, dass die Größe genau dem Puffer entspricht - allerdings möglich. Die Frage ist, ob das allgemein so "üblich" ist, oder wie beispielsweise Firefox etc. das machen. Ich denke, dass es zwar ein in erwägung zu ziehendes Workaround ist, aber halt keine finale Lösung.
[...]
Ich meine: Es muss da doch einen "Standard" geben, woran sich erkennen lässt, dass die Webseite jetzt zuende ist, oder? -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage