Check HTTP response header with partial recv() in C++
You can't use a while(recv(...) > 0)
loop, like you are trying to, to read HTTP messages (especially if HTTP keep-alives are used). You need to parse a message's headers to know how the message's body is actually formatted on the connection, and thus can discover how the message is terminated. You can't make decisions about the routing of the message before you have looked at its headers. An HTTP message can be terminated in one of several different manners, see RFC 2616 Section 4.4 and RFC Section 3.34 for specific details, and also look at past answers of mine on this very topic.
You will have to receive and process the message's headers, THEN look for its Content-Type
header, THEN do whatever you need with the headers you already have, then receive and process the message's body as needed until it is terminated. THEN repeat for the next message.
So, something to the effect of the following (pseudo-code):
std::vector<std::string> headers;
std::string header, entire_response;
char buff[1024];
int nbytes;
std::string response_line = readALine(...);
while ((header = readALine(...)) != "")
{
headers.push_back(header);
}
// analyze headers to discover if message body is present and
// what its transfer format is in order to know how the message
// is terminated ...
std::function<void(const std::string &)> process_string;
std::function<void(char*, int)> process_bytes;
if (headers contains "Content-Type: text/html")
{
process_string = [&entire_response](const std::string &str){
entire_response += str;
};
process_bytes = [&entire_response](char* buf, int bufSize) {
entire_response.append(buf, bufSize);
);
}
else
{
process_string = [](const std::string &str){
send_all(str.c_str(), str.size());
};
process_bytes = [](char* buf, int bufSize) {
send_all(buf, bufSize);
};
}
else
process_string(response_line);
process_string("\r\n");
for (const std::string &header : headers) {
process_string(header);
process_string("\r\n");
}
process_string("\r\n");
while (message is not terminated)
{
// decide how many bytes to read, based on the message's transfer format...
nbytes = std::min(..., sizeof(buff));
nbytes = recv_all(buff, nbytes);
process_bytes(buff, nbytes);
}
if (!entire_response.empty())
{
// use entire_response as needed...
}