-
Stefano Crocco authored
Summary: KHTML part and KWebKitPart both use KCookieServer to manage cookies, while WebEnginePart doesn't. This has at least two consequences: - cookie settings made using the ""Cookie" page in Konqueror settings dialog or in SystemSettings aren't honoured - you can't use KIO to download files from many sites (in particular, sites requiring authentication) because the cookies received by the browser and those used by KIO are different. Qt WebEngine provide a class, `QWebEngineCookieStore` to allow synchronizing cookies between Qt WebEngine and other systems. Unfortunately, the API provided by this class is quite different from the API used by KCookieServer. I added a class, `WebEnginePartCookieJar` to manage the synchronization of cookies between Qt WebEngine and `KCookieServer`, then added a static variable of this class to `WebEnginePart`. This static variable is filled by `WebEnginePart`'s constructor the first time it's created. `WebEnginePartCookieJar` does the following: - disables persistent cookies in `QWebEngineProfile`. This way, cookies will only be stored on disk by `KCookieStore` - on creation, loads cookies from `KCookieServer` and adds them to `QWebEngineCookieStore` - in response to the `QWebEngineCookieStore::cookiesAdded` signal, it adds the cookie to `KCookieServer` according to the Cookies KCM settings - in response to the `QWebEngineCookieStore::cookiesRemoved` signal, it removes the cookie from `KCookieServer` - in response to the `QApplication::lastWindowClosed` signal, it calls `KCookieServer::deleteSessionCookies` for each window (having store each window's id earlier). Some functionality is missing, however, because of `KCookieServer`'s API: - there's no way to know when a cookie is added to `KCookieServer` or removed from it, so (aside from loading the coockies from `KCookieServer` when the `WebEnginePartCookieJar` is created) the synchronization is only one-way: from the `QWebEngineCookieStore` to `KCookieServer`. This should not be an issue most of the times, but it also means that, if the user deletes a cookie from the Cookies KCM while Konqueror is running, this change won't be propagated to `QWebEngineCookieStore` until Konqueror is restarted - when the cookie policy is set to "Ask", `KCookieServer` doesn't provide a way to find out what the user chose. As a workaround, `WebEnginePartCookieJar` checks whether the cookie exists in `KCookieStore` and removes it from the `QWebEngineCookieStore` if it doesn't. However, there's no way to distinguish between an "Accept" and "AcceptUntilSession" answer. Some tricks have been needed to make all this work. In particular: - `QWebEngineCookieStore` only provides the origin URL to the function set as cookie filter; however, `QWebEngineCookieStore::setCookieFilter` only exists since Qt 5.11, so on earlier Qt versions we can't determine whether a cookie is a cross origin cookie or not and honour the corresponding setting in the Cookie KCM - `KCookieServer::addCookies` requires an URL as parameter, but `QWebEngineCookieStore::cookiesAdded` doesn't provide one (I thought the URL passed to the cookie filter could be used, but there's no warranty that the order the requests are passed to the filter is the same in which cookies are added). Looking at the source code for `KCookieStore` and `KCookieJar`, however, it seems that they use this parameter mainly to determine the domain if it isn't specified in the cookie. Since the `QNetworkCookie` given by `KCookieServer::addCookies` seems to always have a non-empty domain, the URL is created using that domain as host - since `QWebEngineCookieStore` doesn't provide a way to find out which page made the request resulting in a cookie, there's no way to be sure of the window ID to pass to `KCookieServer::addCookies`. `WebEnginePartCookieJar` assumes that the window is the active one (this, of course, is only a problem when Konqueror has more than one window open) - there's an issue with expiration times. `KCookieJar` reads expiration times using `QDateTime::fromString` which, it seems, always interpret that time as local time even if expiration times in cookies is in GMT; this can lead to cookies to be considered expired when they should not. For example, if my local time is GMT +1 and I receive a cookie at 14:00 (local time) which expires in half an hour, it's expiration field will be something like "13:30:00 GMT"; however `KCookieJar` seems to interpret it as 13:30 local time and, since in local time, the time is 14:00, it considers the cookie expired. I worked around this issue by manually setting the time zone in the `QNetworkCookie` to GMT, but I can't understand why this happens (it also happens when calling `KCookieServer::addCookie` from the command line using `qdbus`, but it doesn't happen when using KHTMLPart). Test Plan: Open the "Cookies" page in SystemSettings, remove all cookies, use Konqueror to navigate web pages using cookies and note which cookies have appeared in the list; repeat the operation using KHTML and check that the cookies are the same. Reviewers: dfaure Reviewed By: dfaure Differential Revision: https://phabricator.kde.org/D14379
b10baef5