Problem bei Dateidownload ueber simplen HTTP GET Request



  • bobbobbinson schrieb:

    (edit: hab gerade die exe mit dem texteditor geoeffnet, alles kopiert, in ein neues textfile eingefuegt, zu .exe umbenannt und siehe da.. der gleiche Fehler.. also reicht das bloße Kopieren des Inhalt nicht aus. Weiss jmd mehr?!)

    Hä?
    Dein Text-Editor ist halt nicht binär-safe. D.h. du machst die .exe damit kaputt. Deswegen geht sie dann nimmer. Alles logisch, welcher Teil ist jetzt nicht klar?
    Schreib dein Programm so um, dass es die Header nicht mit abspeichert (oder von mir aus in ein anderes File speichert).



  • File so öffnen:

    downloadedFile = fopen(fileOnDisk, "wb");
    

    Dann wird ein evtl. schon existierendes zuerst geleert.

    ---

    Wenn du eine Binärdatei mit irgendeinem Texteditor öffnest und änderst kannst du nicht sicher sein, daß es danach noch ein funktionierende .exe ist.
    Nimm einen Hexeditor.

    Korrekterweise müsstest du zuerst das Headerende suchen und erst dann anfangen zu schreiben. Das ist aber auch nicht so einfach.
    Wenn der Header z.B. 514 bytes (mit "\r\n\r\n") groß ist, findest du das wirkliche Ende nie in deinem buffer. Du müsstest also den ganzen buffer solange an einen anderen anhängen bis du dort das Ende findest, usw. usf.



  • Wenn du eine Binärdatei mit irgendeinem Texteditor öffnest und änderst kannst du nicht sicher sein, daß es danach noch ein funktionierende .exe ist.
    Nimm einen Hexeditor.

    Ok, klingt logisch, wusst ich nicht...

    Also mal fix den Quellcode geaendert, so dass der Header erst gar nicht mit in das File rueber kopiert wird. (zwar nicht so safe dass, falls das Ende des Headers direkt zwischen zwei recieves liegt, aber habe aus sicherheit mal den buffer auf 1024 byte erhöht, aber speziell bei diesem file weiss ich dass die nutzdaten im response bei ungefähr 505 Bytes anfangen)

    Problem ist beim ersten Auslesen, also da wo der Header noch mit drin ist, stehen immer nur 3 byte Nutzdaten am Ende, egal wie groß ich den Buffer in den ausgelesen wird mache. Wenn ich alles (inklusive Header) in das File kopiere sind die Nutzdaten korrekt, will ich aber dass der header unbeachtet bleibt, schreibt er zwar die ersten Nutzdatenbytes in das File aber ein paar danach stehen nicht mit drin, eben dieses "can not run in DOS mode".

    Wär super wenn mir jmd meinen hoffentlich letzten Fehler erklaeren könnte 😉

    //read the response
        char buffer[1024];
        size_t readBytes = 0;   
        memset(buffer, 0, sizeof(buffer));
    
        FILE *downloadedFile;
        char fileOnDisk[512] = "D:\\";
        strcat(fileOnDisk, "test.exe"); // hier muss spaeter filerequest benutzt werden = helloworld.exe 
        remove(fileOnDisk);
        downloadedFile = fopen(fileOnDisk, "wb");
        bool isBody = false;
    
        while ((readBytes = recv(sDownload, buffer, sizeof(buffer), 0)) > 0)
        {          
              if (isBody)
              {
                 fwrite(buffer, 1, readBytes, downloadedFile);
              }
    
              if (strstr(buffer, "\r\n\r\n") && !isBody)
              {
                 char *tmp = strstr(buffer, "\r\n\r\n");
                 isBody = true;
                 fwrite(tmp+4, 1, strlen(tmp+4), downloadedFile);
              }
        }
    

    Gruß bob



  • fwrite(tmp+4, 1, strlen(tmp+4), downloadedFile);
    

    recv liefert keinen '\0' am Ende des Strings... strlen sucht aber nach '\0':

    while ((readBytes = recv(sDownload, buffer, sizeof(buffer), 0)) > 0)
        {          
              buffer[readBytes]='\0'; // <-----Notwendig
    
              if (isBody)
              {
                 fwrite(buffer, 1, readBytes, downloadedFile);
              }
    
              if (strstr(buffer, "\r\n\r\n") && !isBody)
              {
                 char *tmp = strstr(buffer, "\r\n\r\n");
                 isBody = true;
                 fwrite(tmp+4, 1, strlen(tmp+4), downloadedFile);
              }
        }
    

    Auch möglich durch subtrahieren von Adressen:

    while ((readBytes = recv(sDownload, buffer, sizeof(buffer), 0)) > 0)
        {          
              if (isBody)
              {
                 fwrite(buffer, 1, readBytes, downloadedFile);
              }
    
              if (strstr(buffer, "\r\n\r\n") && !isBody)
              {
                 char *tmp = strstr(buffer, "\r\n\r\n");
                 isBody = true;
    
                 // 3. Parameter angepasst 
                 fwrite(tmp+4, 1, readBytes-((tmp+4)-buffer), downloadedFile);
              }
        }
    

    Ich vermute letzteres ist etwas performanter.



  • DaRe schrieb:

    fwrite(tmp+4, 1, strlen(tmp+4), downloadedFile);
    

    recv liefert keinen '\0' am Ende des Strings... strlen sucht aber nach '\0':

    while ((readBytes = recv(sDownload, buffer, sizeof(buffer), 0)) > 0)
        {          
              buffer[readBytes]='\0'; // <-----Notwendig
    
              if (isBody)
              {
                 fwrite(buffer, 1, readBytes, downloadedFile);
              }
             
              if (strstr(buffer, "\r\n\r\n") && !isBody)
              {
                 char *tmp = strstr(buffer, "\r\n\r\n");
                 isBody = true;
                 fwrite(tmp+4, 1, strlen(tmp+4), downloadedFile);
              }
        }
    

    Auch möglich durch subtrahieren von Adressen:

    while ((readBytes = recv(sDownload, buffer, sizeof(buffer), 0)) > 0)
        {          
              if (isBody)
              {
                 fwrite(buffer, 1, readBytes, downloadedFile);
              }
             
              if (strstr(buffer, "\r\n\r\n") && !isBody)
              {
                 char *tmp = strstr(buffer, "\r\n\r\n");
                 isBody = true;
    
                 // 3. Parameter angepasst 
                 fwrite(tmp+4, 1, readBytes-((tmp+4)-buffer), downloadedFile);
              }
        }
    

    Ich vermute letzteres ist etwas performanter.

    WAAAAAH GEIL ES TUT!!! :-))) vielen Dank an die mitgeholfen haben 😉



  • DaRe schrieb:

    fwrite(tmp+4, 1, strlen(tmp+4), downloadedFile);
    

    recv liefert keinen '\0' am Ende des Strings... strlen sucht aber nach '\0':

    while ((readBytes = recv(sDownload, buffer, sizeof(buffer), 0)) > 0)
        {          
              buffer[readBytes]='\0'; // <-----Notwendig
    
              if (isBody)
              {
                 fwrite(buffer, 1, readBytes, downloadedFile);
              }
             
              if (strstr(buffer, "\r\n\r\n") && !isBody)
              {
                 char *tmp = strstr(buffer, "\r\n\r\n");
                 isBody = true;
                 fwrite(tmp+4, 1, strlen(tmp+4), downloadedFile);
              }
        }
    

    Auch möglich durch subtrahieren von Adressen:

    while ((readBytes = recv(sDownload, buffer, sizeof(buffer), 0)) > 0)
        {          
              if (isBody)
              {
                 fwrite(buffer, 1, readBytes, downloadedFile);
              }
             
              if (strstr(buffer, "\r\n\r\n") && !isBody)
              {
                 char *tmp = strstr(buffer, "\r\n\r\n");
                 isBody = true;
    
                 // 3. Parameter angepasst 
                 fwrite(tmp+4, 1, readBytes-((tmp+4)-buffer), downloadedFile);
              }
        }
    

    Ich vermute letzteres ist etwas performanter.

    Methode 1 funktioniert nicht für Binärdateien.
    Methode 2 schon.

    Etwas optimiert:

    while ((readBytes = recv(sDownload, buffer, sizeof(buffer), 0)) > 0)
    {          
        if (isBody)
        {
            fwrite(buffer,  1, readBytes, downloadedFile);
        }
        else
        {
            char *tmp = strstr(buffer,  "\r\n\r\n");
            if( tmp )
            {
                isBody  = true;
    
                // 3. Parameter angepasst
                fwrite(tmp+4, 1, readBytes-((tmp+4)-buffer), downloadedFile);
            }
        }
    }
    

    Ich hab übrigens auch schon header gehabt bei denen das Cookie alleine schon über 2000 bytes lang war.



  • DaRe schrieb:

    recv liefert keinen '\0' am Ende des Strings... strlen sucht aber nach '\0':

    wenn ich ne http response mit stringfunktionen bearbeite, sorge ich dafür dass der empfangspuffer stets nullterminiert ist:

    char buf [ 1024 ] = { 0 };
    int bytes;
    bytes = recv ( sock, buf, sizeof ( buf ) -1, 0 ); // -1: terminierung ist sichergestellt
    ...
    

    denn sonst kann es passieren, dass strstr und co. bis zum abwinken suchen, wenn sie die 0 nicht finden.

    gruß,
    B.B.



  • Oh ja, langsam lern ich dieses '\0' hassen.

    Wenn sein Header, wie er sagt nicht wirklich größer wird als 505 Byte oder sowas, dann ist die NULL-Prüfung auf strstr eigentlich nicht nötig... aber ich weiß nicht, was er da wirklich für nen Server am Start hat ^^

    Aber na gut, die erste Variante sollte nicht verwendet werden.



  • Big Brother schrieb:

    DaRe schrieb:

    recv liefert keinen '\0' am Ende des Strings... strlen sucht aber nach '\0':

    wenn ich ne http response mit stringfunktionen bearbeite, sorge ich dafür dass der empfangspuffer stets nullterminiert ist:

    char buf [ 1024 ] = { 0 };
    int bytes;
    bytes = recv ( sock, buf, sizeof ( buf ) -1, 0 ); // -1: terminierung ist sichergestellt
    ...
    

    denn sonst kann es passieren, dass strstr und co. bis zum abwinken suchen, wenn sie die 0 nicht finden.

    gruß,
    B.B.

    Kommt immer drauf an, ob man nur

    Content-Type: text/*
    

    erwartet. Dann macht es Sinn

    buf[bytes] = 0
    

    zu setzen.

    Alles andere wird komplizierter und braucht das nicht.
    Du musst dir nur die verschiedenen Positionen in den Puffern merken, die Puffer evtl. neu allozieren, mit memcpy kopieren, von der letzten Suchposition (Suchwortlänge-1) abziehen wenn du optimieren willst, usw. usf.

    Noch komplizierter wird's bei HTTP 1.1 und Transfer-Encoding: chunked.



  • es ging mir hier um den http response header, nicht um den content.
    hast du wohl nicht gemerkt. 😉



  • Big Brother schrieb:

    es ging mir hier um den http response header, nicht um den content.
    hast du wohl nicht gemerkt. 😉

    Ne, hab ich nicht gemerkt.

    Wenn du 300 Byte Header und dann Binärdaten hast, die nach ein paar Bytes ein 0x00 enthalten - was macht es da für einen Sinn ein '\0' anzuhängen?

    OP wollte auch Binärdateien runterladen, strlen ist hier einfach falsch.
    strstr um das Headerende zu finden, dann mem*-Funktionen. So macht man das.

    EDIT: Ok, für strstr ist es notwendig (und ich mach es eigentlich auch grundsätzlich ;)), hab jetzt aber keine Lust meinen post noch zu ändern.


Anmelden zum Antworten