|
|
|
@ -27,21 +27,35 @@ void Connection::Start() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Connection::Close() {
|
|
|
|
|
LOG_INFO("Close socket...");
|
|
|
|
|
LOG_INFO("Shutdown socket...");
|
|
|
|
|
|
|
|
|
|
// Initiate graceful connection closure.
|
|
|
|
|
// Socket close VS. shutdown:
|
|
|
|
|
// https://stackoverflow.com/questions/4160347/close-vs-shutdown-socket
|
|
|
|
|
boost::system::error_code ec;
|
|
|
|
|
socket_.shutdown(tcp::socket::shutdown_both, ec);
|
|
|
|
|
|
|
|
|
|
if (ec) {
|
|
|
|
|
LOG_WARN("Socket shutdown error (%s).", ec.message().c_str());
|
|
|
|
|
ec.clear();
|
|
|
|
|
// Don't return, try to close the socket anywhere.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_INFO("Close socket...");
|
|
|
|
|
|
|
|
|
|
socket_.close(ec);
|
|
|
|
|
|
|
|
|
|
if (ec) {
|
|
|
|
|
LOG_ERRO("Socket close error (%s).", ec.message().c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Connection::SendResponse(ResponsePtr response) {
|
|
|
|
|
void Connection::SendResponse(ResponsePtr response, bool no_keep_alive) {
|
|
|
|
|
assert(response);
|
|
|
|
|
|
|
|
|
|
response_ = response;
|
|
|
|
|
|
|
|
|
|
if (request_->IsConnectionKeepAlive()) {
|
|
|
|
|
if (!no_keep_alive && request_->IsConnectionKeepAlive()) {
|
|
|
|
|
response_->SetHeader(headers::kConnection, "Keep-Alive");
|
|
|
|
|
} else {
|
|
|
|
|
response_->SetHeader(headers::kConnection, "Close");
|
|
|
|
@ -52,7 +66,7 @@ void Connection::SendResponse(ResponsePtr response) {
|
|
|
|
|
DoWrite();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Connection::SendResponse(Status status) {
|
|
|
|
|
void Connection::SendResponse(Status status, bool no_keep_alive) {
|
|
|
|
|
auto response = std::make_shared<Response>(status);
|
|
|
|
|
|
|
|
|
|
// According to the testing based on HTTPie (and Chrome), the `Content-Length`
|
|
|
|
@ -60,7 +74,7 @@ void Connection::SendResponse(Status status) {
|
|
|
|
|
// is empty.
|
|
|
|
|
response->SetBody(std::make_shared<Body>(), true);
|
|
|
|
|
|
|
|
|
|
SendResponse(response);
|
|
|
|
|
SendResponse(response, no_keep_alive);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Connection::DoRead() {
|
|
|
|
@ -72,29 +86,31 @@ void Connection::DoRead() {
|
|
|
|
|
|
|
|
|
|
void Connection::OnRead(boost::system::error_code ec, std::size_t length) {
|
|
|
|
|
if (ec) {
|
|
|
|
|
// TODO
|
|
|
|
|
if (ec == boost::asio::error::eof) {
|
|
|
|
|
LOG_WARN("Socket read EOF.");
|
|
|
|
|
//} else if (ec == boost::asio::error::operation_aborted) {
|
|
|
|
|
// LOG_WARN("Socket read aborted.");
|
|
|
|
|
//} else if (ec == boost::asio::error::connection_aborted) {
|
|
|
|
|
// LOG_WARN("Socket connection aborted.");
|
|
|
|
|
LOG_WARN("Socket read EOF (%s).", ec.message().c_str());
|
|
|
|
|
} else if (ec == boost::asio::error::operation_aborted) {
|
|
|
|
|
// The socket of this connection has been closed.
|
|
|
|
|
// This happens, e.g., when the server was stopped by a signal (Ctrl-C).
|
|
|
|
|
LOG_WARN("Socket operation aborted (%s).", ec.message().c_str());
|
|
|
|
|
} else {
|
|
|
|
|
LOG_ERRO("Socket read error (%s).", ec.message().c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Don't try to send any response back.
|
|
|
|
|
|
|
|
|
|
if (ec != boost::asio::error::operation_aborted) {
|
|
|
|
|
pool_->Close(shared_from_this());
|
|
|
|
|
}
|
|
|
|
|
} // else: The socket of this connection has already been closed.
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!request_parser_.Parse(buffer_.data(), length)) {
|
|
|
|
|
// Bad request.
|
|
|
|
|
// TODO: Always close the connection?
|
|
|
|
|
LOG_ERRO("Failed to parse HTTP request.");
|
|
|
|
|
SendResponse(Status::kBadRequest);
|
|
|
|
|
// Send Bad Request (400) to the client and no Keep-Alive.
|
|
|
|
|
SendResponse(Status::kBadRequest, true);
|
|
|
|
|
// Close the socket connection.
|
|
|
|
|
pool_->Close(shared_from_this());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -163,7 +179,6 @@ void Connection::OnWriteOK() {
|
|
|
|
|
LOG_INFO("Continue to read the next request...");
|
|
|
|
|
Start();
|
|
|
|
|
} else {
|
|
|
|
|
Shutdown();
|
|
|
|
|
pool_->Close(shared_from_this());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -176,18 +191,4 @@ void Connection::OnWriteError(boost::system::error_code ec) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Socket close VS. shutdown:
|
|
|
|
|
// https://stackoverflow.com/questions/4160347/close-vs-shutdown-socket
|
|
|
|
|
void Connection::Shutdown() {
|
|
|
|
|
LOG_INFO("Shutdown socket...");
|
|
|
|
|
|
|
|
|
|
// Initiate graceful connection closure.
|
|
|
|
|
boost::system::error_code ec;
|
|
|
|
|
socket_.shutdown(tcp::socket::shutdown_both, ec);
|
|
|
|
|
|
|
|
|
|
if (ec) {
|
|
|
|
|
LOG_ERRO("Socket shutdown error (%s).", ec.message().c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace webcc
|
|
|
|
|