HttpRequest bei Yahoo.com



  • Guten Abend.
    Ich habe eine kleine Http(s)Request-Klasse in C++ geschrieben und heute ist mir beim Abrufen von yahoo.com-Seiten aufgefallen, dass diese bei einem chunked transfer ein Padding mittels Leerzeichen verwenden, um bei jeder chunked-size-Angabe auf 7Byte (ohne CRLF) zu kommen. Das eigentliche Problem besteht nun darin, dass meine Klasse scheinbar falsch mit der chunked-size umzugehen scheint, denn manchmal scheint es als ob die vom Server übermittelte chunked-size etwas zu klein wäre. Der Code von mir:

    int HttpRequest::ChunkSize(uint32_t &offset) {
      size_t lf = content_.find_first_of('\n', offset);
      if (lf == std::string::npos)
        return 0;
      std::string size_str = content_.substr(offset, lf - offset);
    
      lf = lf - offset;
      offset += lf + 1;
      while (size_str.find_last_not_of("1234567890abcdefABCDEF", --lf) != std::string::npos) {
        size_str[lf] = '\0';
      }
    
      if (size_str.find_first_of("1234567890abcdefABCDEF") != 0)
        return -1;
    
      return strtoul(size_str.c_str(), NULL, 16);
    }
    
    void HttpRequest::ChunkedEncoding(void) {
      if ((state_ & kChunkedEncoding) == 0)
        return;
    
      uint32_t offset = 0;
      int chunk_size = ChunkSize(offset);
      std::string clean_content = "";
      while (chunk_size) {
        clean_content.append(content_.substr(offset, chunk_size));
        offset += chunk_size;
    
        if (content_.find_first_of('\r', offset) == offset)
          offset += 2;
    
        chunk_size = ChunkSize(offset);
      }
    
      content_.assign(clean_content);
      state_ ^= kChunkedEncoding;
    }
    

    content_ ist hierbei ein member der Klasse und enthält zum Zeitpunkt des Aufrufs den gesamten übermittelten Inhalt. Kleines Beispiel:

    Erhaltene Daten:

    57dd   
    <?xml version="1.0" encoding="UTF-8" ?>[b][...][/b]</body></html>
    <!-- SpaceID:954000104 -->
    
    <!-- lwebgw3.mobile.ch1.yahoo.com uncompressed/chunked Fri Feb 18 20:52:36 GMT 2011 -->
    
    0
    

    Alle empfangenen Daten sind hier hinterlegt: http://pastebin.com/z2cf8vWw

    Mein Code kalkuliert als Offset für die nächste chunk-size diesen Ort (Offset zeigt auf '/'):

    [b]/[/b]chunked Fri Feb 18 20:52:36 GMT 2011 -->[...]
    

    Die Frage ist nun, wieso mein Code bei der Verwendung eines solchen Paddings einen falsches Offset für die nächste chunk-Größe kalkuliert.

    MfG, 0x2A 🙂



  • Poste mal eine URL, damit ich vergleichen kann.





  • Peinlich peinlich... der Inhalt ist als UTF-8 encoded und ich hab es als ANSI behandelt. Ich behandle die Webseite nun als wstring (UTF8ToString16 konvertiert) und dementsprechend erhalte ich nun auch eine andere Größe für den Inhalt. Trotzdem komme ich noch nicht zum nächsten chunk-size.



  • Ok, bei mir funktioniert es problemlos.

    Transfer-Encoding: chunked ist grundsätzlich nicht ganz einfach.

    Ich mache das so, daß ich eine Funktion IsChunkComplete() nach jedem recv() aufrufe. Wenn der chunk komplett ist, verarbeite ich ihn, ansonsten hänge ich die Daten an meinen temporären Puffer an und "empfange weiter".

    Du musst aber auch immer bedenken, daß evtl. nicht alle Daten komplett übertragen wurden. z.B.

    Header\r\n\r\nD5

    Deshalb IsChunkComplete().

    Außerdem funktionieren auch nicht alle server rfc-konform. Deswegen ist es nicht ganz einfach alle Fehler abzufangen.

    Edit:
    UTF-8 oder ANSI interessieren mich gar nicht. Meine Klasse empfängt alles, auch z.B. Binärdaten.



  • Vielen Dank für die Antwort!
    Verwendest du eine UTF8-Konversation? Bei mir sind scheinbar zufällige Abweichungen bei dem Offset für den zweiten (und damit auch letzten) chunk. Zum Beispiel lande ich immer ca. dort:

    <!-- lwebgw1.mobile.ch1.yahoo.com uncompressed/chunked Fri Feb 18 23:43:51 GMT
    

    Dies stellt das Ende meines ersten Chunks da. Wie zu sehen ist fehlen ein paar Bytes. Wenn ich kurz danach exakt dieselbe Seite aufrufe lande ich zB dort:

    [...]<!-- lwebgw12.mobile.ch1.yahoo.com uncompressed/chunked Fri Feb 18 23:45:13 GMT 2011 -->
    

    Man beachte hierbei, dass am Ende des ersten Chunks eine LFCR Folge (falsche Reihenfolge) vorliegt. Zu Beginn des zweiten Chunks (da wo eig. chunk-size liegen sollte) findet man dann das fehlende LF.
    Irgendeine Idee, womit diese scheinbar "zufällige" Inkonsistenz zusammenhängt und wieso ich immer noch ein LF zu Beginn des 2. chunk-teils hängen habe?

    MfG

    Edit:
    Dementsprechend muss UTF8 ja auch nicht beachtet werden, da die Angabe von chunk-size sich ja eh auf Bytes und nicht auf die Anzahl an Zeichen bezieht nehme ich an. Dann stellt sich mir trotzdem die Frage, was an meiner Herangehensweise falsch ist. Es sollte doch auch möglich sein, die chunks im Nachhinein zu trennen ohne dies on-thy-fly so wie bei dir zu machen.
    Edit2:
    Das interessante an der Sachlage ist einfach, dass es bei anderen Webseiten (Google z.B) prima funktioniert und sich daraus folgern lässt, dass entweder das Padding nicht richtig verarbeitet wird oder die Kodierung Probleme bereitet. Hinzu kommt, dass nicht immer dasselbe Offset gewählt wird, was bedeutet, dass scheinbar teilweise verschiedene Webseiten von Yahoo übertragen werden.

    EDIT3:
    Neuste Entwicklung: Ich habe die UTF8-Konvertierung wieder entfernt und weiß der Geier wieso hat er nun teilweise das passende Offset zum 2. chunk-size. Dies ist aber immer noch nicht immer der Fall... ansonsten landet er dort (Ende des ersten chunks):

    <!-- lwebgw2.mobile.ch1.yahoo.com uncompressed/chunked Sat F
    

    Dies dann allerdings immer, wenn er nicht das korrekte Ende findet. Auffällig ist, dass beide male beim ersten Chunk die identische chunk-size angegeben wurde. 2x dieselbe Größe und einmal landet er beim falschen Ende... ich werd des Wahnsinns 🙂

    Edit4:
    Er landet doch nicht immer bei demselben Ende, wenn es inkorrekt ist. Gerade ist es

    <!-- lwebgw2.mobile.ch1.yahoo.com uncompressed/chunked Sat Feb
    

    geworden.



  • Unglaublich. Ungefähr 10x dieselbe Seite aufgerufen und 10x als erste chunk-size 5783h (22403d) erhalten. Dementsprechend 10x als Offset für die 2. chunk-size-Angabe 22412 berechnet, da 9 Bytes durch die erste chunk-size verbraucht wurden ({'5', '7', '8', '3', ' ', ' ', ' ', '\r', '\n'}). Tatsächlich lag aber vllt. 3/10 mal an dem Offset wirklich die 2. chunk-size-Angabe vor. Wie kann das noch an meinem Programm liegen und nicht an dem Server?!


Anmelden zum Antworten