recv HTTP problem
-
Hey. ein bessere Titel ist mir leider nicht eingefallen xD.
Naja, auf jeden fall hab ich mir ne kleine Klasse aufgebaut, ich poste mal nur die relevante Funktion, da ich keinen Spoiler finden kann xD.
Leider kann ich die Seite, dich ich als Vorlage genommen habe nicht mehr finden

Erstaml etwas erklärt. Ich empfange erst den HTTP header. Anhand des headers wird dann ausgelesen, wie der reste empfangen wird, per content-size, chunked, oder per no given size.
Wird der rest per chunked empfangen, habe im empfangenen quelltext immer mal wider Zeichen wie diese:
ÌÌÌÌÌÌÌÌIch kann mir nicht erklären, wo diese her kommen.
Die einzige plausieble erklärung für mich wäre, dass das der Hex code ist, welcher ja die größe des zu empfangenen parts darstellt.Nun die Frage, wie bekomme die diese raus ?
hier mein Code :
bool WebTCP::navigate(std::string url, std::string post) { std::string oldUrl = url; removeHttp(url); std::string hostname = RemoveHostname(url); hostent* phe = gethostbyname(hostname.c_str()); if(phe == NULL) { std::cout << "Host konnte nicht aufgelöst werden" << std::endl; return false; } if(phe->h_addrtype != AF_INET) { std::cout << "Ungueltiger Adresstyp!" << std::endl; return false; } if(phe->h_length != 4) { std::cout << "Ungueltiger IP-Typ!" << std::endl; return false; } int Socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if(Socket == -1) { std::cout << "Socket konnte nicht erstellt werden!" << std::endl; return false; } sockaddr_in service; service.sin_family = AF_INET; service.sin_port = htons(80); // Das HTTP-Protokoll benutzt Port 80 char** p = phe->h_addr_list; // p mit erstem Listenelement initialisieren int result; // Ergebnis von connect do { if(*p == NULL) // Ende der Liste { std::cout << "Verbindung fehlgschlagen!" << std::endl; return false; } service.sin_addr.s_addr = *reinterpret_cast<unsigned long*>(*p); ++p; result = connect(Socket, reinterpret_cast<sockaddr*>(&service), sizeof(service)); } while(result == -1); std::cout << "Verbindung erfolgreich!" << std::endl; std::string packet; if(post.length() < 1) { packet = "GET " + url + " HTTP/1.1\n"; packet += "Host: " + hostname + "\n"; packet += "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.2.4) Gecko/20100611 AskTbUT2V5/3.8.0.12304 Firefox/3.6.4\n"; packet += "Accept: text/javascript, text/html, application/xml, text/xml, */*\n"; packet += "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\n"; if(referer.length() > 1) packet += "Referer: " + referer + "\n"; packet += "Keep-Alive: 115\n"; packet += "Connection: keep-alive\n\n"; }else{ std::ostringstream Str; Str << post.length(); std::string postSize(Str.str()); packet = "POST " + url + " HTTP/1.1\n"; packet += "Host: " + hostname + "\n"; packet += "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.2.4) Gecko/20100611 AskTbUT2V5/3.8.0.12304 Firefox/3.6.4\n"; packet += "Accept: text/javascript, text/html, application/xml, text/xml, */*\n"; packet += "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\n"; if(referer.length() > 1) packet += "Referer: " + referer + "\n"; packet += "Keep-Alive: 115\n"; packet += "Connection: keep-alive\n"; packet += "Content-Type: application/x-www-form-urlencoded\n"; packet += "Content-Length: " + postSize; packet += "\n\n" + post; } std::fstream fout("header", std::ios::binary | std::ios::out); if(!fout) { std::cout << "Could Not Create File!" << std::endl; return false; } fout.write(packet.c_str(), packet.length()); std::cout << packet << std::endl; header.clear(); try { SendAll(Socket, packet.c_str(), packet.size()); int code = 100; // 100 = Continue std::string line; std::string msg; // HTTP/1.1 200 OK boost::regex PatternFirstline("[^\w]+ ([0-9]+) ([^\n]+)"); boost::cmatch match; std::cout << "recv header" << std::endl; while(code == 100) { GetLine(Socket, line); if(boost::regex_match(line.c_str(), match, PatternFirstline)) { code = atof(match[1].str().c_str()); msg = match[2]; }else{ if(line.length() > 1) { std::cout << "unerwarteter Fehler!" << std::endl; return false; } } if(code == 100) { GetLine(Socket, line); // Leere Zeile nach Continue ignorieren } } std::cout << "Msg: " << msg << std::endl; if(code == 500) { std::cout << "Error #" << code << " - " << msg << std::endl; return false; } bool chunked = false; const int noSizeGiven = -1; int size = noSizeGiven; boost::regex PatternLine("([^:]+): ([^\n]+)"); while(true) { GetLine(Socket, line); if(line.find("\r") != std::string::npos && line.length() < 2) // Header zu Ende? { break; } if(line.length() > 1) { if(boost::regex_match(line.c_str(), match, PatternLine)) { if(match[1].str().find("Content-Length") != std::string::npos) { size = atof(match[2].str().c_str()); } else if(match[1].str().find("Transfer-Encoding") != std::string::npos) { if(match[2].str().find("chunked") != std::string::npos) chunked = true; } else if (match[1].str().find("Location") != std::string::npos) { if(match[2].str().c_str()[0] == '/') hostname += match[2]; else hostname = match[2]; location = hostname; std::cout << "Location found: " << hostname << std::endl; if (autoLocation) { navigate(hostname); closesocket(Socket); return true; } } } else { std::cout << "unerwarteter Fehler!" << std::endl; return false; } } } // if we come to here no location was found ! //location.clear(); int recvSize = 0; // Empfangene Bytes insgesamt char buf[1024]; int bytesRecv = -1; // Empfangene Bytes des letzten recv body.clear(); std::string tmpBody; if(size != noSizeGiven) // Wenn die Größe über Content-length gegeben wurde { std::cout << "0%"; while(recvSize < size) { if((bytesRecv = recv(Socket, buf, sizeof(buf), 0)) <= 0) { std::cout << "Error while resiving via content-length" << std::endl; return false; } recvSize += bytesRecv; tmpBody += buf; std::cout << "\r" << recvSize * 100 / size << "%" << std::flush; // Mit \r springen wir an den Anfang der Zeile } } else { if(!chunked) { std::cout << "Downloading... (Unknown Filesize)" << std::endl; while(bytesRecv != 0) // Wenn recv 0 zurück gibt, wurde die Verbindung beendet { if((bytesRecv = recv(Socket, buf, sizeof(buf), 0)) < 0) { std::cout << "Error while resiving via unknow size" << std::endl; return false; } tmpBody += buf; } } else { std::cout << "Downloading... (Chunked)" << std::endl; while(true) { std::stringstream sstream; GetLine(Socket, sstream); int chunkSize = -1; sstream >> std::hex >> chunkSize; // Größe des nächsten Parts einlesen if(chunkSize <= 0) // Wenn 0 komplett ! { break; } std::cout << "Downloading Part (" << chunkSize << " Bytes)... " << std::endl; recvSize = 0; // Vor jeder Schleife wieder auf 0 setzen while(recvSize < chunkSize) { int bytesToRecv = chunkSize - recvSize; if((bytesRecv = recv(Socket, buf, bytesToRecv > sizeof(buf) ? sizeof(buf) : bytesToRecv, 0)) <= 0) { std::cout << "Error while resiving via chunked" << std::endl; return false; } recvSize += bytesRecv; tmpBody += buf; std::cout << "\r" << recvSize * 100 / chunkSize << "%" << std::flush; } std::cout << std::endl; for(int i = 0; i < 2; ++i) { char temp; recv(Socket, &temp, 1, 0); } } } } std::cout << std::endl << "Finished!" << std::endl; //std::cout << tmpBody << std::endl; body = tmpBody; removeHttp(oldUrl); referer = "http://" + oldUrl; } catch(std::exception& e) { std::cout << std::endl; std::cerr << e.what() << std::endl; } closesocket(Socket); return true; }mfg Darter
-
Debugger
-
EOutOfResources schrieb:
Debugger
Ich les mir das jetzt nicht alles haarklein durch, aber ein typischer Fehler wäre eine vergessene Nullterminierung.
-
cooky451 schrieb:
aber ein typischer Fehler wäre eine vergessene Nullterminierung.
Oder aber nicht beachtet, dass recv und Konsorten eben keine Nullterminierung einbauen sondern zurückgeben, wie viele Zeichen epfangen wurden. Wenn man dann mehr als das einliest, gibts am Ende Zeichensalat frisch aus dem uninitialisierten Buffer.
-
Darter schrieb:
if(phe->h_length != 4) { std::cout << "Ungueltiger IP-Typ!" << std::endl; return false; }Ich vermute du tust das, weil du kein IPv6 unterstützt. Das ist jedoch nicht nötig, da es für IPv4 (das von dir abgefragte) AF_INET und für IPv6 AF_INET6 gibt.
-
Eine gängige Technik wäre
int recvSize = 0; // Empfangene Bytes insgesamt char buf[1024]; int bytesRecv = -1; // Empfangene Bytes des letzten recv body.clear(); std::string tmpBody; if(size != noSizeGiven) // Wenn die Größe über Content-length gegeben wurde { std::cout << "0%"; while(recvSize < size) { if((bytesRecv = recv(Socket, buf, sizeof(buf)-1, 0)) <= 0) // das letzte Byte in buf gehört der \0 { std::cout << "Error while resiving via content-length" << std::endl; return false; } recvSize += bytesRecv; buf[bytesRecv] = \0; // die string::operator+(char*) Methode liest bis zum \0 Byte tmpBody += buf; std::cout << "\r" << recvSize * 100 / size << "%" << std::flush; // Mit \r springen wir an den Anfang der Zeile } }
-
Hey.
Der letzte beitrag klinkt für mich einleuchten.
allerdings wird das so nicht funktionieren:buf[bytesRecv] = \0;eher so:
buf[bytesRecv] = '\0';So habe ich es dann auch Probiert, alerdings erhalte ich dann folgenen runtime-Error:
Run-Time Check Failure #2 - Stack around the variable 'buf' was corrupted.Also dachte ich mir, ich überlaufe den Index des Arrays und hab es so Probiert:
EDIT: meinte natürlich so:buf[bytesRecv - 1] = '\0';So wird mir aber leider bei jedem Part das letzte Zeichen "geklaut".
Außerdem ensteht dieser runtime-Error immer erst dann, wenn der ganze Quelltext schon empfangen wurde.
EDIT: Nun hab ich überprüft wie viele bytes bei jedem druchlauf der Schleife tatsächlich empfangen werden. Bis zum letzen Schleifendurchgang werden immer 1024 Bytes empfangen, also sie größe meines Buffers. Beim letzten durchgang sind es natürlich weniger, da es schon ein extremer Zufall wäre, dass es genau aufgeht, und genau da ensteht der Fehler, was ich mir noch nicht ganz erklären kann
mfg Darter
-
Du mußt auch daran denken, daß der Buffer groß genug ist für die pro Durchlauf empfangenen Daten UND den Null-Terminator. Darum steht in mugga's Beitrag auch "sizeof(buf)-1" beim recv()-Befehl.
(der Fehler entsteht schon viel früher, wird allerdings erst am Funktionsende bemerkt, wenn die Debug-Sicherungen überprüfen, ob du nichts kaputt gemacht hast)
-
Sorry, hätte das wohl deutlicher kennzeichnen müssen.
-
Ok, sry hab ich doch tatsächlich übersehen, also lag ich doch richtig, dass ich den Index des Array überlaufe. (so nebenbei, sagt man dass so ? ^^)
-
Im englischen sagt man "Index out of range" - wie man das ordentlich ins Deutsche übersetzen soll, keine Ahnung.
-
Darter schrieb:
dass ich den Index des Array überlaufe. (so nebenbei, sagt man dass so ? ^^)
Das Array hat keinen Index, also kannst du ihn auch nicht überlaufen. Du greifst mit dem Index auf das Array zu. Und in diesem Fall überschreitest du den bereich des Arrays.
theliquidwave schrieb:
Im englischen sagt man "Index out of range"
Ich meine, was von "Bereichsüberlauf" oder "Bereichsüberschreitung" im Hinterkopf zu haben.