Allowing persistent cookies

Having problems with building or using CEF's C/C++ APIs? This forum is here to help. Please do not post bug reports or feature requests here.

Allowing persistent cookies

Postby callum » Thu Jan 11, 2018 5:40 pm

CEF 3.3239.1723.g071d1c1 / Windows 64

I want to allow cookies to persist in my app between sessions and am using this website to test my code. http://www.html-kit.com/tools/cookietester

In desktop Chrome, I can set a few cookies, close the Chrome and restart and they are still marked as present. In my app, I can set them and the page says they are set but when I restart my app, they are gone.

This behavior only appeared when I added my own implementation of CefRequestContextHandler and created my own cookie manaher with:
Code: Select all
class ContextHandler :
  public CefRequestContextHandler
{
  public:
    ContextHandler(const std::string cookieStorageDirectory)
    {
      bool persist_session_cookies = false;
      CefRefPtr<CefCompletionCallback> callback = nullptr;

      mCookieManager = CefCookieManager::CreateManager(CefString(cookieStorageDirectory), persist_session_cookies, callback);
    }

    CefRefPtr<CefCookieManager> GetCookieManager() override
    {
      return mCookieManager;
    }

    private:
    CefRefPtr<CefCookieManager> mCookieManager;

    IMPLEMENT_REFCOUNTING(ContextHandler);
};


and then refer to my context handler when I create my browser sync
Code: Select all
CefRequestContextSettings contextSettings;
mContextHandler = new ContextHandler("cef_opengl_win_cookies");
CefRefPtr<CefRequestContext> request_context = CefRequestContext::CreateContext(contextSettings, mContextHandler.get());

mBrowser = CefBrowserHost::CreateBrowserSync(window_info, mBrowserClient.get(), gStartURL, browser_settings, request_context);


Previously, when I did not do this and just set the cache path setting, that website worked as expected.

I need my own cookie manager (I think) because I need it to set cookies programatically in my code elsewhere.

Interestingly, that website fails in the same way with CefClient - not sure if that's expected or not. I didn't see a cookie enabled/disabled setting.

What am I doing wrong (and should CefClient work like my desktop browser for that page?)
callum
Expert
 
Posts: 326
Joined: Mon Feb 23, 2015 6:19 pm

Re: Allowing persistent cookies

Postby HarmlessDave » Fri Jan 12, 2018 1:12 pm

> I need it to set cookies programatically in my code elsewhere.

The browser process can set cookies programatically. We've used this code for years, but you might not need the task any longer in 3.3xxx

Code: Select all
   CefRefPtr<CefCookieManager> manager = CefCookieManager::GetGlobalManager(NULL);
   CefCookie cookie;
   CefString(&cookie.name).FromASCII(cookie_name);
   CefString(&cookie.value).FromASCII(cookie_value);
   CefString(&cookie.domain).FromASCII(cookie_domain);
   CefString(&cookie.path).FromASCII("/");
   cookie.has_expires = false;
   cookie.httponly = false;
   CefString cef_cookie_url;
   cef_cookie_url.FromASCII(cookie_url);
   CefRefPtr<CefSetCookieCallback> back = NULL;

   // might not need task -- supposedly can now call from any thread in browser process
   CefPostTask(TID_IO, CefCreateClosureTask(base::Bind(base::IgnoreResult(&CefCookieManager::SetCookie), manager, cef_cookie_url, cookie, back)));
   // can't do this older CEF - windows message thread is not TID_IO thread -  bool ok = manager->SetCookie(cef_cookie_url, cookie);


If you need to set a cookie from the render process you can either execute JavaScript or send a message to the browser process
HarmlessDave
Expert
 
Posts: 370
Joined: Fri Jul 11, 2014 2:02 pm

Re: Allowing persistent cookies

Postby callum » Fri Jan 12, 2018 1:20 pm

Thanks Dave - I see you're using the global cookie manager there - in our app, there may be several browsers open at once and my understanding was I had to create a request context for each that points to a separate cookie store on disk. I thought the only way to do that was via the kind of code I listed - maybe that's not true anymore.
callum
Expert
 
Posts: 326
Joined: Mon Feb 23, 2015 6:19 pm

Re: Allowing persistent cookies

Postby HarmlessDave » Fri Jan 12, 2018 2:09 pm

All browsers can use the global manager, the only reasons to create others are for isolation (beyond Chromium's own security) or for different behavior by the manager in different browsers. For "normal" browser behavior, just use the shared global manager.
HarmlessDave
Expert
 
Posts: 370
Joined: Fri Jul 11, 2014 2:02 pm

Re: Allowing persistent cookies

Postby callum » Fri Jan 12, 2018 2:16 pm

Great - thanks for insight - that makes things much simpler.
callum
Expert
 
Posts: 326
Joined: Mon Feb 23, 2015 6:19 pm

Re: Allowing persistent cookies

Postby callum » Fri Jan 12, 2018 2:48 pm

Something else I've noticed that may be expected is that when a page such as the test I mentioned sets a cookie and you exit the app immediately, the cookie is not always persisted to disk even though I called CefCookieManager::FlushStore(...) as part of my shutdown code.

I have a feeling I asked this a long time ago and was told it was expected behavior so there may not be a solution but if you've dealt with it and have a solution, I'd love to try it.
callum
Expert
 
Posts: 326
Joined: Mon Feb 23, 2015 6:19 pm

Re: Allowing persistent cookies

Postby callum » Fri Jan 12, 2018 3:09 pm

Hopefully not bad form to answer your own question but adding a callback to the FlushStore() call that waits for it to complete before continuing with close down seems to help.
callum
Expert
 
Posts: 326
Joined: Mon Feb 23, 2015 6:19 pm

Re: Allowing persistent cookies

Postby HarmlessDave » Fri Jan 12, 2018 3:17 pm

callum wrote:Hopefully not bad form to answer your own question but adding a callback to the FlushStore() call that waits for it to complete before continuing with close down seems to help.


Not bad form at all, the answer will help someone searching on this topic in the future.

When coding for CEF3 + Chromium always remember that many actions are asynchronous. They return control to you immediately but you often should not assume they have finished their work yet. Think PostMessage in the Windows API.
HarmlessDave
Expert
 
Posts: 370
Joined: Fri Jul 11, 2014 2:02 pm

Re: Allowing persistent cookies

Postby callum » Fri Jan 12, 2018 4:10 pm

Understood and something I'm learning.

I added a callback with a wait for completion as per the CEF unit tests for both setCookie and FlushStore but still, if I start my app, set a cookie and exit immediate it doesn't always get saved out to disk even though both callbacks' onComplete functions are called before exit thanks to the CefWaitableEvent::Wait().

Few more things to try though and it's fun hacking on this.
callum
Expert
 
Posts: 326
Joined: Mon Feb 23, 2015 6:19 pm

Re: Allowing persistent cookies

Postby callum » Fri Jan 12, 2018 5:28 pm

Code: Select all
bool setCookie(const std::string url, const std::string name,
               const std::string value, const std::string domain,
               const std::string path, bool httponly, bool secure)
{
    CefRefPtr<CefCookieManager> manager = CefCookieManager::GetGlobalManager(nullptr);
    if (manager)
    {
        CefCookie cookie;
        CefString(&cookie.name) = name;
        CefString(&cookie.value) = value;
        CefString(&cookie.domain) = domain;
        CefString(&cookie.path) = path;

        cookie.httponly = httponly;
        cookie.secure = secure;

        cookie.has_expires = false;

        class setCookieCallback :
            public CefSetCookieCallback
        {
            public:
                explicit setCookieCallback(CefRefPtr<CefWaitableEvent> event)
                    : mEvent(event)
                {
                }

                void OnComplete(bool success) override
                {
                    mEvent->Signal();
                }

            private:
                CefRefPtr<CefWaitableEvent> mEvent;

                IMPLEMENT_REFCOUNTING(setCookieCallback);
        };

        bool automatically_reset = true;
        bool initially_signaled = false;
        CefRefPtr<CefWaitableEvent> event = CefWaitableEvent::CreateWaitableEvent(automatically_reset, initially_signaled);

        bool result = manager->SetCookie(url, cookie, new setCookieCallback(event));

        event->Wait();

        return result;
    }

    return false;
}


This is my setCookie function - the OnComplete() method is called and the return values indicate success but nothing is written.

If I remove the mEvent->Signal(); call in OnComplete() the code doesn't block at event->Wait() - must be a silly error or am I misunderstanding how that works?
callum
Expert
 
Posts: 326
Joined: Mon Feb 23, 2015 6:19 pm

Next

Return to Support Forum

Who is online

Users browsing this forum: No registered users and 57 guests