kostenloser Webspace werbefrei: lima-city


HTTP: Content-Length?

lima-cityForumDie eigene HomepageInternet Allgemein

  1. Autor dieses Themas

    nerdinator

    Kostenloser Webspace von nerdinator, auf Homepage erstellen warten

    nerdinator hat kostenlosen Webspace.

    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 :)
  2. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

  3. kochmarkus

    Co-Admin Kostenloser Webspace von kochmarkus

    kochmarkus hat kostenlosen Webspace.

    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
  4. Autor dieses Themas

    nerdinator

    Kostenloser Webspace von nerdinator, auf Homepage erstellen warten

    nerdinator hat kostenlosen Webspace.

    kochmarkus schrieb:
    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
    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.

    Hier nun nochmal (wenn auch noch recht experimentell) der Quellcode.
    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
    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 ;) )

    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
  5. kochmarkus

    Co-Admin Kostenloser Webspace von kochmarkus

    kochmarkus hat kostenlosen Webspace.

    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.
  6. Autor dieses Themas

    nerdinator

    Kostenloser Webspace von nerdinator, auf Homepage erstellen warten

    nerdinator hat kostenlosen Webspace.

    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?
  7. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

Dir gefällt dieses Thema?

Über lima-city

Login zum Webhosting ohne Werbung!