From 4c54fae69b1c4bb656a0ddc0028b7cf4383e32da Mon Sep 17 00:00:00 2001 From: Ilya Melamed Date: Wed, 6 Mar 2019 14:53:08 +0200 Subject: [PATCH] obs-browser: flush panel cookie store on exit If cookie store is not flushed, state might become inconsistent: reading from the cookies file will become impossible. No errors will be returned, yet no information will be available, and no information will be stored: the cookie manager will appear to be empty at all times and the `Cookies` file modified date will not update moving forward. This will result, for example, in Twitch chat window re-opening for users which connected their Twitch account, but not having the `auth-token` cookie available: once the user will try to send a message to the chat, they will be redirected to Twitch login screen. --- obs-browser-plugin.cpp | 68 +++++++++++++++++++++++++++++++++++++++++ panel/browser-panel.cpp | 4 +++ 2 files changed, 72 insertions(+) diff --git a/obs-browser-plugin.cpp b/obs-browser-plugin.cpp index ef52d9786..fcb13bac4 100644 --- a/obs-browser-plugin.cpp +++ b/obs-browser-plugin.cpp @@ -77,6 +77,72 @@ bool QueueCEFTask(std::function task) /* ========================================================================= */ +static std::mutex cookie_managers_mutex; +static std::vector> cookie_managers; + +void register_cookie_manager(CefRefPtr cm) +{ + std::lock_guard guard(cookie_managers_mutex); + + cookie_managers.emplace_back(cm); +} + +static void flush_cookie_manager(CefRefPtr cm) +{ + os_event_t* complete_event; + + os_event_init(&complete_event, OS_EVENT_TYPE_AUTO); + + class CompletionCallback : public CefCompletionCallback + { + public: + CompletionCallback(os_event_t* complete_event) : m_complete_event(complete_event) + { + } + + virtual void OnComplete() override + { + os_event_signal(m_complete_event); + } + + IMPLEMENT_REFCOUNTING(CompletionCallback); + + private: + os_event_t* m_complete_event; + }; + + CefRefPtr callback = + new CompletionCallback(complete_event); + + auto task = [&]() { + if (!cm->FlushStore(callback)) { + blog(LOG_WARNING, + "Failed flushing cookie store"); + + os_event_signal(complete_event); + } + else { + blog(LOG_INFO, "Flushed cookie store"); + } + }; + + CefPostTask(TID_IO, CefRefPtr(new BrowserTask(task))); + + os_event_wait(complete_event); + os_event_destroy(complete_event); +} + +static void flush_cookie_managers() +{ + std::lock_guard guard(cookie_managers_mutex); + + for (auto cm : cookie_managers) { + flush_cookie_manager(cm); + } +} + +/* ========================================================================= */ + static const char *default_css = "\ body { \ background-color: rgba(0, 0, 0, 0); \ @@ -500,6 +566,8 @@ bool obs_module_load(void) void obs_module_unload(void) { + flush_cookie_managers(); + if (manager_thread.joinable()) { while (!QueueCEFTask([] () {CefQuitMessageLoop();})) os_sleep_ms(5); diff --git a/panel/browser-panel.cpp b/panel/browser-panel.cpp index 37f627f56..c999f7779 100644 --- a/panel/browser-panel.cpp +++ b/panel/browser-panel.cpp @@ -13,6 +13,8 @@ extern bool QueueCEFTask(std::function task); extern "C" void obs_browser_initialize(void); extern os_event_t *cef_started_event; +void register_cookie_manager(CefRefPtr cm); + std::mutex popup_whitelist_mutex; std::vector popup_whitelist; std::vector forced_popups; @@ -83,6 +85,8 @@ struct QCefCookieManagerInternal : QCefCookieManager { if (!cm) throw "Failed to create cookie manager"; + register_cookie_manager(cm); + rch = new QCefRequestContextHandler(cm); rc = CefRequestContext::CreateContext(