Fix 3rd party login issue on macOS (#4739)

* Fix use-after-free error

* Ignore http OPTIONS method

* Make sure response has sent before closing the http server
This commit is contained in:
Noisyfox 2024-03-28 23:07:10 +08:00 committed by GitHub
parent f36c22385b
commit 9f3bafb04e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 21 additions and 12 deletions

View file

@ -77,13 +77,20 @@ void session::read_next_line()
if (line.length() == 0) { if (line.length() == 0) {
if (headers.content_length() == 0) { if (headers.content_length() == 0) {
std::cout << "Request received: " << headers.method << " " << headers.get_url();
if (headers.method == "OPTIONS") {
// Ignore http OPTIONS
server.stop(self);
return;
}
const std::string url_str = Http::url_decode(headers.get_url()); const std::string url_str = Http::url_decode(headers.get_url());
const auto resp = server.server.m_request_handler(url_str); const auto resp = server.server.m_request_handler(url_str);
std::stringstream ssOut; std::stringstream ssOut;
resp->write_response(ssOut); resp->write_response(ssOut);
std::shared_ptr<std::string> str = std::make_shared<std::string>(ssOut.str()); std::shared_ptr<std::string> str = std::make_shared<std::string>(ssOut.str());
async_write(socket, boost::asio::buffer(str->c_str(), str->length()), async_write(socket, boost::asio::buffer(str->c_str(), str->length()),
[this, self](const boost::beast::error_code& e, std::size_t s) { [this, self, str](const boost::beast::error_code& e, std::size_t s) {
std::cout << "done" << std::endl; std::cout << "done" << std::endl;
server.stop(self); server.stop(self);
}); });
@ -159,6 +166,7 @@ void HttpServer::stop()
if (server_) { if (server_) {
server_->acceptor.close(); server_->acceptor.close();
server_->stop_all(); server_->stop_all();
server_->io_service.stop();
} }
if (m_http_server_thread.joinable()) if (m_http_server_thread.joinable())
m_http_server_thread.join(); m_http_server_thread.join();

View file

@ -28,6 +28,7 @@ class http_headers
std::map<std::string, std::string> headers; std::map<std::string, std::string> headers;
friend class session;
public: public:
std::string get_url() { return url; } std::string get_url() { return url; }

View file

@ -36,16 +36,16 @@ void OAuthJob::parse_token_response(const std::string& body, bool error, OAuthRe
void OAuthJob::process(Ctl& ctl) void OAuthJob::process(Ctl& ctl)
{ {
// Prepare auth process // Prepare auth process
ThreadSafeQueueSPSC<OAuthResult> queue; std::shared_ptr<ThreadSafeQueueSPSC<OAuthResult>> queue = std::make_shared<ThreadSafeQueueSPSC<OAuthResult>>();
// Setup auth server to receive OAuth code from callback url // Setup auth server to receive OAuth code from callback url
local_authorization_server.set_request_handler([this, &queue](const std::string& url) -> std::shared_ptr<HttpServer::Response> { local_authorization_server.set_request_handler([this, queue](const std::string& url) -> std::shared_ptr<HttpServer::Response> {
if (boost::contains(url, "/callback")) { if (boost::contains(url, "/callback")) {
const auto code = url_get_param(url, "code"); const auto code = url_get_param(url, "code");
const auto state = url_get_param(url, "state"); const auto state = url_get_param(url, "state");
const auto handle_auth_fail = [this, &queue](const std::string& message) -> std::shared_ptr<HttpServer::ResponseRedirect> { const auto handle_auth_fail = [this, queue](const std::string& message) -> std::shared_ptr<HttpServer::ResponseRedirect> {
queue.push(OAuthResult{false, message}); queue->push(OAuthResult{false, message});
return std::make_shared<HttpServer::ResponseRedirect>(this->_data.params.auth_fail_redirect_url); return std::make_shared<HttpServer::ResponseRedirect>(this->_data.params.auth_fail_redirect_url);
}; };
@ -81,11 +81,11 @@ void OAuthJob::process(Ctl& ctl)
.on_error([&](std::string body, std::string error, unsigned status) { parse_token_response(body, true, r); }) .on_error([&](std::string body, std::string error, unsigned status) { parse_token_response(body, true, r); })
.perform_sync(); .perform_sync();
queue.push(r); queue->push(r);
return std::make_shared<HttpServer::ResponseRedirect>(r.success ? _data.params.auth_success_redirect_url : return std::make_shared<HttpServer::ResponseRedirect>(r.success ? _data.params.auth_success_redirect_url :
_data.params.auth_fail_redirect_url); _data.params.auth_fail_redirect_url);
} else { } else {
queue.push(OAuthResult{false}); queue->push(OAuthResult{false});
return std::make_shared<HttpServer::ResponseNotFound>(); return std::make_shared<HttpServer::ResponseNotFound>();
} }
}); });
@ -96,18 +96,18 @@ void OAuthJob::process(Ctl& ctl)
// Wait until we received the result // Wait until we received the result
bool received = false; bool received = false;
while (!ctl.was_canceled() && !received ) { while (!ctl.was_canceled() && !received ) {
queue.consume_one(BlockingWait{1000}, [this, &received](const OAuthResult& result) { queue->consume_one(BlockingWait{1000}, [this, &received](const OAuthResult& result) {
*_data.result = result; *_data.result = result;
received = true; received = true;
}); });
} }
// Handle timeout // Handle timeout
if (!received && !ctl.was_canceled()) { if (!received && ctl.was_canceled()) {
BOOST_LOG_TRIVIAL(debug) << "Timeout when authenticating with the account server.";
_data.result->error_message = _u8L("Timeout when authenticating with the account server.");
} else if (ctl.was_canceled()) {
_data.result->error_message = _u8L("User cancelled."); _data.result->error_message = _u8L("User cancelled.");
} else {
// Wait a while to ensure the response has sent
std::this_thread::sleep_for(std::chrono::milliseconds(1500));
} }
} }