mirror of
https://github.com/oxen-io/oxen-core.git
synced 2023-12-14 02:22:56 +01:00
Close established HTTP requests when trying to shut down (#1308)
Currently we only close the listening HTTP socket(s) but not established connections, which means a client make repeated keep-alive requests will keep the HTTP server alive for potentially a very long time when we're trying to shut down or restart. This commit changes the logic to more forcefully close request connections with the next reply, so that we properly shut down within a few seconds but give clients a chance to finish up their current request.
This commit is contained in:
parent
e2068a5a33
commit
d16899104e
4 changed files with 18 additions and 0 deletions
|
@ -249,6 +249,7 @@ namespace cryptonote::rpc {
|
|||
auto& res = data->res;
|
||||
res.writeHeader("Server", data->http.server_header());
|
||||
res.writeHeader("Content-Type", data->call->is_binary ? "application/octet-stream"sv : "application/json"sv);
|
||||
if (data->http.closing()) res.writeHeader("Connection", "close");
|
||||
for (const auto& [name, value] : data->extra_headers)
|
||||
res.writeHeader(name, value);
|
||||
|
||||
|
@ -256,6 +257,7 @@ namespace cryptonote::rpc {
|
|||
res.write(piece);
|
||||
|
||||
res.end();
|
||||
if (data->http.closing()) res.close();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -600,6 +602,8 @@ namespace cryptonote::rpc {
|
|||
for (auto* s : m_listen_socks)
|
||||
us_listen_socket_close(/*ssl=*/false, s);
|
||||
|
||||
m_closing = true;
|
||||
|
||||
{
|
||||
// Destroy any pending long poll connections as well
|
||||
MTRACE("closing pending long poll requests");
|
||||
|
|
|
@ -48,8 +48,10 @@ namespace cryptonote::rpc {
|
|||
res.writeHeader("Server", m_server_header);
|
||||
res.writeHeader("WWW-Authenticate", *www_auth);
|
||||
res.writeHeader("Content-Type", "text/plain");
|
||||
if (m_closing) res.writeHeader("Connection", "close");
|
||||
if (req.getMethod() != "HEAD"sv)
|
||||
res.end("Login required\n");
|
||||
if (m_closing) res.close();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -63,10 +65,12 @@ namespace cryptonote::rpc {
|
|||
res.writeStatus(std::to_string(code.first) + " " + std::string{code.second});
|
||||
res.writeHeader("Server", m_server_header);
|
||||
res.writeHeader("Content-Type", "text/plain");
|
||||
if (m_closing) res.writeHeader("Connection", "close");
|
||||
if (body)
|
||||
res.end(*body);
|
||||
else
|
||||
res.end(std::string{code.second} + "\n");
|
||||
if (m_closing) res.close();
|
||||
}
|
||||
|
||||
// Similar to the above, but for JSON errors (which are 200 OK + error embedded in JSON)
|
||||
|
@ -85,7 +89,9 @@ namespace cryptonote::rpc {
|
|||
res.writeStatus("200 OK"sv);
|
||||
res.writeHeader("Server", m_server_header);
|
||||
res.writeHeader("Content-Type", "application/json");
|
||||
if (m_closing) res.writeHeader("Connection", "close");
|
||||
res.end(body);
|
||||
if (m_closing) res.close();
|
||||
}
|
||||
|
||||
std::string http_server_base::get_remote_address(HttpResponse& res) {
|
||||
|
|
|
@ -52,6 +52,8 @@ namespace cryptonote::rpc {
|
|||
|
||||
const std::string& server_header() { return m_server_header; }
|
||||
|
||||
bool closing() const { return m_closing; }
|
||||
|
||||
static constexpr http_response_code
|
||||
HTTP_OK{200, "OK"sv},
|
||||
HTTP_BAD_REQUEST{400, "Bad Request"sv},
|
||||
|
@ -80,6 +82,9 @@ namespace cryptonote::rpc {
|
|||
// Access-Control-Allow-Origin header values; if one of these match the incoming Origin header
|
||||
// we return it in the ACAO header; otherwise (or if this is empty) we omit the header entirely.
|
||||
std::unordered_set<std::string> m_cors;
|
||||
// Will be set to true when we're trying to shut down which closes any connections as we reply
|
||||
// to them. Should only be read/write from inside the uWS loop.
|
||||
bool m_closing = false;
|
||||
// If true then always reply with 'Access-Control-Allow-Origin: *' to allow anything.
|
||||
bool m_cors_any = false;
|
||||
};
|
||||
|
|
|
@ -311,8 +311,10 @@ namespace tools
|
|||
res.writeHeader("Content-Type", "application/json");
|
||||
for (const auto& [name, value] : extra_headers)
|
||||
res.writeHeader(name, value);
|
||||
if (closing()) res.writeHeader("Connection", "close");
|
||||
|
||||
res.end(result);
|
||||
if (closing()) res.close();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -415,6 +417,7 @@ namespace tools
|
|||
// Stopped: close the sockets, cancel the long poll, and rejoin the threads
|
||||
for (auto* s : m_listen_socks)
|
||||
us_listen_socket_close(/*ssl=*/false, s);
|
||||
m_closing = true;
|
||||
|
||||
stop_long_poll_thread();
|
||||
|
||||
|
|
Loading…
Reference in a new issue