-
Notifications
You must be signed in to change notification settings - Fork 11
Description
Subjective
In an HTTPS call, the client detects the end of a message using Content-Length Header
The Content-Length header specifies the exact byte length of the HTTP message body. The client reads the response until it has received the specified number of bytes.
How it works:
- The server includes a Content-Length header in the response.
- The client reads the header, determines the size of the message body, and continues reading from the network until it has received that exact number of bytes.
We as a proxy server are not able to decrypt and detect the Content-Length header, so we need to find a way to detect when the message is over.
Current solution
I implemented a way to read till end of message like the following, which is not stable.
You can check the function TCPClient::doRead which is reading the socket in a loop and check the available bytes on socket. I also wait at the end of each round in the loop to give a pause for possible data over socket.
Both repeatWait
and timeWait
used in this function are configurable from config file
for (auto i = 0; i <= config_->general().repeatWait; i++) {
while (true) {
if (!socket_.is_open()) {
log_->write("[TCPClient doRead] Socket is not OPEN",
Log::Level::DEBUG);
socket_.close();
return;
}
if (socket_.available() == 0) break;
boost::asio::read(socket_, readBuffer_,
boost::asio::transfer_exactly(1), error);
if (error == boost::asio::error::eof) {
log_->write("[TCPClient doRead] [EOF] Connection closed by peer.",
Log::Level::TRACE);
socket_.close();
return; // Exit after closing the socket
} else if (error) {
log_->write(
std::string("[TCPClient doRead] [error] ") + error.message(),
Log::Level::ERROR);
socket_.close();
return; // Exit after closing the socket
}
}
timer.expires_from_now(
boost::posix_time::milliseconds(config_->general().timeWait));
timer.wait();
}
Current Issues
We have two basic issues with the solution above
-
This method is not reliable since the data may come with delay on socket, then our loop will end before reading all data from socket. So the parameter
socket_.available()
is not reliable in this situation -
This method will read from socket while there is something on socket to read and then pack all red data and send it to the nipoAgent. So imagine I want to download a file with size of 100Mb, then following steps will be happened
- Client send http request to nipoAgent
- nipoAgent send request to nipoServer
- nipoServer send request to origin server
- origin server start to write 100Mb on socket to nipoServer
- nipoServer read all 100Mb from socket (which is in several packets or chunks)
- nipoServer pack all 100Mb to a single response and send back to nipoAgent
This is not good and client needs to get the data chunk by chunk and not all once