Problem bei Dateidownload ueber simplen HTTP GET Request
-
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.