Reputation:
Writing a small http server, I have to handle "Connection: keep-alive" header. Before that I used the standard request processing model: one connection is opened for one request, then processed, a response is sent, and then the connection is closed. But “Keep Alive” allows you to re-use the connection. The question is, how can I do that? What algorithm should I use?
I tried to do it like this: opening a connection using accept -> reading data from the client socket using recv -> processing a request -> sending a response using send. This loop continues until recv returns a value = 0, and on exiting the loop the connection is closed. But the problem is that on the second iteration of the loop, after processing the first request, recv is blocked. Please tell me at what step I was wrong.
for(;;)
{
client *current = client::listen_port(cone.get_socket());//called here to accept
httpHandler worker(current);//this class handles requests, we pass a pointer to the class object in it, which contains information about the client
for(;;)
{
httpParser* temp = new httpParser(current->get_client());// recv is called and the httpParser class parses the request
if (temp->get_recvByte() > 0)
worker.handle(temp);//if recv returned something, we process the request and respond to it
if (temp->get_recvByte() == 0)
break;
if (temp->get_recvByte())
std::cout << "error";
delete temp;
}
}
this constructor forms the header
heading::heading(const int content_size, const std::string &file)
{
head = "HTTP/1.1 200 OK\r\n";
std::string Content_Type, Content_Length;
std::string extension = file.substr(file.find(".") + 1);
if (extension == "png" || extension == "gif")
Content_Type = "Content-Type: image/apng\r\n";
else if(extension == "jpg")
Content_Type = "Content-Type: image/jpeg\r\n";
else
Content_Type = "Content-Type: text/html\r\n";
Content_Length = "Content-Lenght: " + std::to_string(content_size) + "\r\n";
head = head + "Server: Cone \r\n" + Content_Type + Content_Length + "Connection: keep-alive\r\n\r\n";
}
processing function
void httpHandler::handle(httpParser *temp)
{
parser = temp;
if (parser->get_type() == HEAD)
{
heading head;
send(newclient->get_client(), head.get_head().c_str(), head.get_head().length(), 0);
return;
}
if (parser->get_type() == UNKNOWN)
send(newclient->get_client(), heading::error404().c_str(), heading::error404().length(), 0);
if (!parser->get_dynamic())
static_handle();
else
dynamic_handle();
parser = nullptr;
}
static content processing
void httpHandler::static_handle()
{
std::string buffer;
std::ifstream file(getenv("path") + parser->get_file(), std::ifstream::binary);
if (file)
{
auto const size{file.tellg()};
file.seekg(0);
char current;
buffer.reserve(size);
while(file.get(current)) //читаем файл
buffer.push_back(current);
heading head(buffer.length(), parser->get_file());
buffer = head.get_head() + buffer; заголовок к буферу
send(newclient->get_client(), buffer.c_str(), buffer.length(), 0);
}
else
send(newclient->get_client(), heading::error404().c_str(), heading::error404().length(), 0);
file.close();
}
parser
httpParser::httpParser(int client_d)
{
char buffer[req_buff_size];
std::cout << "Calling recv() on socket " << client_d << std::endl;
recvByte = recv(client_d, buffer,req_buff_size - 1, 0); // получаем сообщение из сокета
if (recvByte > 0)
{
buffer[recvByte] = '\0';
reqest = buffer;
std::cout << reqest <<std::endl; // для тестов
if (recvByte < 0)
throw std::invalid_argument( "error recv\n" );
if (reqest.find("GET") == 0)
{
type = GET;
GET_parse();
}
else if (reqest.find("POST") == 0)
{
type = POST;
POST_Parse();
}
else if (reqest.find("HEAD") == 0)
type = HEAD;
else
throw std::invalid_argument( "invalid REQ\n" );
requestedFile();
}
}
connection closes in client destructor
Upvotes: 0
Views: 990
Reputation: 104559
You have:
"Connection: keep-alive\n\n";
Should be:
"Connection: keep-alive\r\n";
Similarly, this doesn't look correct either with the forward slashes
"Server: Cone /r/n"
Should be:
"Server: Cone\r\n"
Upvotes: 1