TCPClient GET Request

  • VB.NET

Es gibt 25 Antworten in diesem Thema. Der letzte Beitrag () ist von Kraizy.

    Das es konkret in einem/vielen/allen Fällen, in diesem Augenblick gerade "klappt", heißt nicht, dass es richtig ist.
    Deine Abfrage sbHeaders.ToString().Contains("Content-Length:") kann auf mindestens zwei Arten schief gehen: a) Header sind im allgemeinen case-insensitive (content-length ignorierst du fälschlicherweise also) und b) du prüfst nicht ob der Header existiert, sondern ob der Substring irgendwo in den Headern vorkommt. Was z.B. beim Set-Cookie- oder Referrer-Header schief gehen kann.

    Und du hältst dich nicht an die im Post #17 genannte Reihenfolge: 1. fehlt, du prüfst zunächst 3. statt 2. und schaust bei letzterem gar nicht, ob der Header gesetzt ist.

    Das Problem ist jedoch, wenn ich bei der Seite kein GZip benutze, spuckt es mir über 90.000 als Content-Length aus, was meiner Meinung nach falsch ist - und mein Tool dann irgendwie durcheinander kommt mit dem "Teil für Teil des Bodys lesen". Mit GZip sinds dann nur noch um die 20.000 was auch in Chrome/FireFox angezeigt wird. Jedoch bekomme ich hierbei dann den Fehler bzgl Magic Number.

    Warum sind 90.000 Bytes falsch? Die Startseite (genauer: der decodierte HTTP-Body) von vb-paradise besteht bei mir gerade aus 145.054 Zeichen, als UTF-8 codiert genau 145.410 Bytes.
    Was machst du dann, wenn der Server von Haus aus kein gzip verwendet? Das halbe (+/-) www unterstützt kein gzip.
    "irgendwie durcheinander kommt" ist nur ein Synonym für "ich habe einen Fehler drin". Du behebst dein Problem nicht dadurch, dass du einfach gzip verwendest.

    Deine Abfrage sbHeaders.ToString().Contains("Content-Length:") kann auf mindestens zwei Arten schief gehen: a) Header sind im allgemeinen case-insensitive (content-length ignorierst du fälschlicherweise also) und b) du prüfst nicht ob der Header existiert, sondern ob der Substring irgendwo in den Headern vorkommt. Was z.B. beim Set-Cookie- oder Referrer-Header schief gehen kann.


    Das wird dann natürlich noch alles hinzugefügt und abgefragt, wenn ich es erstmal "hardcoded" für meine benötigte Seite zum Laufen bekomme. Ich mein, durchs Debuggen sehe ich ja, ob es gerade in diesem Moment nötig ist oder nicht, auf Groß-/Kleinschreibung oder auf das Vorhandensein eines Headers zu achten etc.

    Ich schau nochmal bzgl der Reihenfolge und meld mich später.

    Achja noch ne Frage: Was mach ich, wenn der Server keinen gescheiten Encoding Typ als Antwort sendet? Er gibt lediglich Content-Type: text/html und Content-Encoding: gzip zurück. Wenn ich nun mit meinem StreamReader (Encoding.Default) den Body lese, klappt es zwar (Hexwerte der Body Abschnitte werden richtig ausgelesen, und es wird auch nicht zu viel/zu wenig gelesen) jedoch werden dann im Body keine Sonderzeichen angezeigt. Wenn ich jedoch z.B. Encoding.UTF8 beim Reader benutze, dann werden zwar Sonderzeichen angezeigt, aber ich habe wieder das Problem, dass der 2. Hexwert bereits im 1. Abschnitt angezeigt wird. Komischerweise ist das aber nur bei der einen Seite so, bei anderen habe ich mittlerweile keine Probleme mehr den Body richtig auszulesen.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Kraizy“ ()

    HTTP arbeitet in erster Linie nur mit bytes. Sinnvollerweise arbeitest du nicht mit einem StringBuilder, sondern mit einem Buffer auf "byte-Ebene" (z.B. ein byte-Array, wo man natürlich die Größe im Auge behalten muss) und decodiert nach dem Empfangen.
    Wenn kein Encoding angegeben ist, wäre bei HTML der nächste Schritt nach einem passenden Meta-Tag im Head zu suchen (z.B. <meta charset="..."> oder <meta http-equiv="Content-Type" content="text/html; charset=..."/>). Wenn dort auch keine Angaben vorhanden sind, hat man einen cleveren Algorithmus der gut im Raten ist oder überlässt den Anwender die Entscheidung bzw. nimmt einen passenden Default-Wert.
    HTTP arbeitet in erster Linie nur mit bytes. Sinnvollerweise arbeitest du nicht mit einem StringBuilder, sondern mit einem Buffer auf "byte-Ebene" (z.B. ein byte-Array, wo man natürlich die Größe im Auge behalten muss) und decodiert nach dem Empfangen.


    Das würde ich auch gerne tun, jedoch bleibt's hierbei immer hängen. Beispiel:

    VB.NET-Quellcode

    1. Dim size As Integer = 'Content-Length aus dem Header
    2. Dim total As Integer = 0
    3. Dim dataLeft As Integer = size
    4. Dim buffer() As Byte = New Byte(size - 1){}
    5. Dim recv As Integer = 0
    6. While total < size
    7. recv = client.Receive(buffer, total, dataLeft, SocketFlags.None)
    8. If recv = 0
    9. Exit While
    10. End If
    11. total += recv
    12. dataLeft -= recv
    13. End While
    14. Dim s As String = Encoding.UTF8.GetString(buffer)


    Sagen wir mal size beträgt 50.000, es wird nun das erste Mal aus dem Stream gelesen und recv bekommt den Wert 45.000. Da 45 < 50 ist, wird ein 2. Mal aus dem Stream gelesen, nämlich die letzten 5.000. Hier bleibt es jedoch hängen und ich hab kein Plan wieso. Deshalb habe ich stattdessen einfach Byte für Byte ausgelesen, weil das immerhin geklappt hat, auch wenn mir die Lösung mit dem Buffer lieber wäre.
    Mit Buffer meinte ich nur, dass du den StringBuilder durch ein byte-Array ersetzen solltest.
    Beim Header kommst du um Schleifen mit jeweils ein Byte lesen wohl nicht herum. Nachdem du die Header aber gelesen hast und weißt, wie viel du im nächsten Schritt lesen musst, kannst du der einfachheitshalber ja (einen chunk) mit Stream.Read(byte[] buffer, int offset, int count); lesen.
    Nachdem du dann den kompletten Message-Body hast, wandelst du das ganze (bei Text) in einen String und verwendest das richtige Encoding.
    Danke, klappt nun. Sowohl Header als auch Body.
    Hätte da aber noch eine andere Frage. Und zwar, ich würde meiner Klasse gerne eine AutoRedirect Property hinzufügen, die dann - wie der Name schon sagt - bestimmt, ob bei einem Request intern in meiner Request-Funktion automatisch nach Weiterleitungen gesucht wird und ggf. einen weiteren Request abschickt. Dazu einfach entweder im Header nach einer Location schauen, oder im Body nach einem Meta Refresh. Alles kein Problem. Meine Frage ist eher, bei manchen Requests ist ein Referer zwingend erforderlich, da es sonst zu falschen (für mich unbrauchbare) Antworten kommt. Ich könnte natürlich einfach jedesmal die zuletzt benutzte URL, mit der meine Request Funktion aufgerufen wurde benutzen, jedoch habe ich bereits mehrmals feststellen müssen, dass dies nicht immer der Fall sein muss und der Referer (z.B. bei einem POST Request) nicht immer unbedingt die zuletzt aufgerufene URL war. Gibt es da irgendeine Möglichkeit, den richtigen Referer für einen Request rauszufinden?