Merge lp:~mardy/webbrowser-app/add-onlineaccount-support-for-container2 into lp:webbrowser-app

Proposed by Alberto Mardegan
Status: Merged
Merged at revision: 556
Proposed branch: lp:~mardy/webbrowser-app/add-onlineaccount-support-for-container2
Merge into: lp:webbrowser-app
Diff against target: 1573 lines (+935/-256)
21 files modified
debian/control (+4/-1)
src/app/browserapplication.cpp (+6/-0)
src/app/browserapplication.h (+2/-0)
src/app/webcontainer/AccountsPage.qml (+73/-0)
src/app/webcontainer/CMakeLists.txt (+5/-1)
src/app/webcontainer/chrome-cookie-store.cpp (+218/-0)
src/app/webcontainer/chrome-cookie-store.h (+53/-0)
src/app/webcontainer/cookie-store.cpp (+30/-24)
src/app/webcontainer/cookie-store.h (+16/-28)
src/app/webcontainer/online-accounts-cookie-store.cpp (+8/-12)
src/app/webcontainer/online-accounts-cookie-store.h (+6/-6)
src/app/webcontainer/sqlitecookiestore.cpp (+0/-99)
src/app/webcontainer/sqlitecookiestore.h (+0/-58)
src/app/webcontainer/webapp-container.cpp (+24/-1)
src/app/webcontainer/webapp-container.h (+4/-0)
src/app/webcontainer/webapp-container.qml (+114/-26)
src/app/webcontainer/webkit-cookie-store.cpp (+120/-0)
src/app/webcontainer/webkit-cookie-store.h (+51/-0)
tests/unittests/CMakeLists.txt (+1/-0)
tests/unittests/cookie-store/CMakeLists.txt (+11/-0)
tests/unittests/cookie-store/tst_CookieStore.cpp (+189/-0)
To merge this branch: bzr merge lp:~mardy/webbrowser-app/add-onlineaccount-support-for-container2
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Olivier Tilloy Approve
David Barth (community) Approve
Review via email: mp+211701@code.launchpad.net

Commit message

Add online account support in the webapp container.

A new "accountProvider" command line parameter has been added to allow one to specify an account provider for the specific webapp launch. When used, one can specify a given provider, e.g. "facebook", to pull existing accounts (if any) from the specified provider
from Online Accounts.

When the provider does not have any existing account, an option to delegate the creation of such an account to OA is provided. It is also possible to skip the step and go straight to the target url.

Description of the change

Add online account support in the webapp container.

A new "accountProvider" command line parameter has been added to allow one to specify an account provider for the specific webapp launch. When used, one can specify a given provider, e.g. "facebook", to pull existing accounts (if any) from the specified provider
from Online Accounts.

When the provider does not have any existing account, an option to delegate the creation of such an account to OA is provided. It is also possible to skip the step and go straight to the target url.

In order to use it, one can use a command line such as:

APP_ID=cookie-test ./webapp-container --webapp --accountProvider=facebook https://www.facebook.com

(provided a proper .application file has been installed with the proper name in /usr/share/accounts/applications).

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:470
http://jenkins.qa.ubuntu.com/job/webbrowser-app-ci/648/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty/4061/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty-touch/3646
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-trusty-amd64-ci/150
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-trusty-armhf-ci/150
        deb: http://jenkins.qa.ubuntu.com/job/webbrowser-app-trusty-armhf-ci/150/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-trusty-i386-ci/150
    FAILURE: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-trusty/3545/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/4113
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/4113/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/3648
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/3648/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-runner-mako/5971
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/4970

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/webbrowser-app-ci/648/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
David Barth (dbarth) :
review: Approve
Revision history for this message
Olivier Tilloy (osomon) wrote :

60 +// system
61 +#include <string.h>
62 +#include <unistd.h>

Those changes seem useless, can they be reverted?

Revision history for this message
Olivier Tilloy (osomon) wrote :

287 + bool registerCookieQmlTypes(QQmlEngine * engine);

What’s the point of this method returning a boolean value (the return value seems unused)?

Revision history for this message
Olivier Tilloy (osomon) wrote :

223 + qmlRegisterType<CookieStore>("Ubuntu.WebContainer.Components", 0, 1, "CookieStore");
224 + qmlRegisterType<SqliteCookieStore>("Ubuntu.WebContainer.Components", 0, 1, "SqliteCookieStore");
225 + qmlRegisterType<OnlineAccountsCookieStore>("Ubuntu.WebContainer.Components", 0, 1, "OnlineAccountsCookieStore");

For consistency with what’s already done in webbrowser-app.cpp (see line 90), and to make it fully explicit that those are not public API exposed through a plugin, could you change the import to "private.webcontainer" (and while at it define a variable with it before the calls to qmlRegisterType)?

Revision history for this message
Olivier Tilloy (osomon) wrote :

235 - out << "Usage: " << command << " [-h|--help] [--fullscreen] [--maximized] [--inspector] [--app-id=APP_ID] [--homepage=URL] [--webapp[=name]] [--webappModelSearchPath=PATH] [--webappUrlPatterns=URL_PATTERNS] [--enable-back-forward] [--enable-addressbar] [URL]" << endl;

This was split in several lines for readability (thanks for this!), but it’s missing the new [--accountProvider=PROVIDER_NAME] token.

Revision history for this message
Olivier Tilloy (osomon) wrote :

358 + return i18n.tr("Ubuntu Web Application")

Since some strings were updated, the translation template needs to be re-generated. To do that, run:

   cmake . && make webbrowser-app.pot

and then commit the changes to the branch.

Revision history for this message
Olivier Tilloy (osomon) wrote :

(apparently, when the initial version of this branch was reverted in trunk, the new C++ files were not removed)

421 + dbPath: ".local/share/" + applicationName + "/.QtWebKit/cookies.db"

Apparently this dbPath property is relative to the user’s home directory. This is not how local files to the applications should be accessed. Instead, use the "dataLocation" global context property being exported by the Ubuntu.Components.Extra.Browser plugin.

Revision history for this message
Olivier Tilloy (osomon) wrote :

206 + m_window->setProperty("applicationName", QCoreApplication::applicationName());

In Qt 5.2, the Qt.application global QML object has a 'name' property, which will make this additional property superfluous.

Revision history for this message
Olivier Tilloy (osomon) wrote :
Revision history for this message
Olivier Tilloy (osomon) wrote :

=== modified file 'tests/autopilot/webbrowser_app/tests/http_server.py'

Changes to this file are unrelated, please revert.

Revision history for this message
Olivier Tilloy (osomon) wrote :

456 +
457 +

Can those two superfluous blank lines be removed?

Revision history for this message
Olivier Tilloy (osomon) wrote :

Looks good overall, but I made a bunch of comments for minor changes, so marking needs fixing to ensure they get addressed before landing. Thanks!

review: Needs Fixing
471. By Alberto Mardegan

Address review comments

472. By Alberto Mardegan

remove added empty line

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

The inclusion of <QStandardPaths> in src/app/webcontainer/sqlitecookiestore.cpp is now unused, and should be removed.

473. By Alberto Mardegan

Removed unused header inclusion

Revision history for this message
Olivier Tilloy (osomon) wrote :

LGTM.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
474. By Alberto Mardegan

Don't load the webview as soon as a webapp starts

The code in webapp-container.qml initially checks the value of its
"accountProvider" property and loads the webview if that's empty.
If this property is set after the component has been built, this will cause the
webview to be (accidentally) loaded for a fraction of a second, which in turn
will cause the WebProcess to be spawned. The WebProcess will read the
cookies.db file, and the same WebProcess instance will likely be reused for the
webapp, once we really want to use it. This has the unfortunate side-effect
that it will not re-read the cookies which we might have copied over from
Online Accounts in the meantime.

So, with this change we make sure that all properties (including
"accountProvider") will be set on the Window before the component is completed.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
475. By Alberto Mardegan

Fix build

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

I understand the logic in revision 474 (and the need for it), but I’m not very fond of the way it’s implemented. Do we really need an optional CreationMode parameter? Can’t we just make BeginCreation the (non overridable) default?
I.e., what do we gain from keeping webbrowser-app being initialized in CompleteCreation mode?

Revision history for this message
Alberto Mardegan (mardy) wrote :

I agree with you Olivier, I simply wanted to avoid changing webbrowser-app at all. If you don't mind me adding a completeCreate() call in WebbrowserApp::initialize(), we can indeed get rid of that enum.

Revision history for this message
Olivier Tilloy (osomon) wrote :

> I agree with you Olivier, I simply wanted to avoid changing webbrowser-app at
> all. If you don't mind me adding a completeCreate() call in
> WebbrowserApp::initialize(), we can indeed get rid of that enum.

Yes, please do. Thanks!

476. By Alberto Mardegan

Always use 2-step creation of the component

Revision history for this message
Olivier Tilloy (osomon) wrote :

I haven’t tested again, but the changes look good to me. Please ensure the changes are thoroughly tested before landing.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
477. By Alberto Mardegan

Merge from trunk, partial fixes

[ Ubuntu daily release ]
* New rebuild forced
[ Alexandre Abreu ]
* Fix the network dialog reload (LP: #1309138)
* Oxide (and Chromium) does not inform of non user driven navigations
  (or more specifically redirects that would be part of an
  popup/webview load (after its been granted). Quite a few sites (e.g.
  Youtube), create popups when clicking on links (or following a
  window.open()) with proper youtube.com address but w/ redirection
  params, e.g.:
  http://www.youtube.com/redirect?q=http%3A%2F%2Fgodzillamovie.com%2F&
  redir_token=b8WPI1pq9FHXeHm2bN3KVLAJSfp8MTM5NzI2NDg3NEAxMzk3MTc4NDc0
  In this instance the popup & navigation is granted, but then a
  redirect happens inside the popup to the real target url (here
  http://godzillamovie.com) which is not trapped by a navigation
  requested and therefore not filtered. The only way to do it atm is
  to listen to url changes in popups & also filter there. (LP:
  #1294279)
[ CI bot ]
* Resync trunk
[ Olivier Tilloy ]
* Handle new view requests in the browser. (LP: #1307735)
[ Olivier Tilloy ]
* Force the page title to be reset to an empty string when the
  activity view is being hidden. (LP: #1307420)
[ Michael Sheldon ]
* Add support for file upload via content-hub
[ Ugo Riboni ]
* Add support for file upload via content-hub
[ Alexandre Abreu ]
* Make sure that we dont load unecessary libs (oxide or qtwebkit)
  correspnding to the webengine that we dont use. (LP: #1306037)
* Add a basic set of integration tests for the webapp container
[ Ubuntu daily release ]
* New rebuild forced
[ Olivier Tilloy ]
* Enable UA overrides for all form factors, each in a separate file.
  Add an override for google calendar on desktop. Clean up the
  construction of the default UA string for easier reading and
  maintenance.
[ Bill Filler ]
* Add support for file upload via content-hub
[ David Barth ]
* To prevent https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-
  toolkit/+bug/1305834 caused by a recent UI toolkit change, we are
  returning an empty title for now. (LP: #1305834)
[ Alexandre Abreu ]
* Add support for Oxide's onNavigationRequested in the container (LP:
  #1302769)
* Webapps: maintain the session cookies for the user session Instruct
  Oxide to store/load the session cookies on disk in a per-webapp
  directory under XDG_RUNTIME_DIR. The first time in a user session
  that the webapp is launched, the session cookies (leftover from
  previous sessions) are not loaded, but only stored (this is the
  chrome's "persistent" sessionCookieMode). The next times, session
  cookies are both loaded and stored (chrome's "restored"
  sessionCookieMode).
[ Alberto Mardegan ]
* Webapps: maintain the session cookies for the user session Instruct
  Oxide to store/load the session cookies on disk in a per-webapp
  directory under XDG_RUNTIME_DIR. The first time in a user session
  that the webapp is launched, the session cookies (leftover from
  previous sessions) are not loaded, but only stored (this is the
  chrome's "persistent" sessionCookieMode). The next times, session
  cookies are both loaded and stored (chrome's "restored"
  sessionCookieMode).
[ Ubuntu daily release ]
* New rebuild forced
[ Olivier Tilloy ]
* Update to oxide 1.0.
[ Olivier Tilloy ]
* Re-enable javascript dialogs, now that they are available in oxide.
[ CI bot ]
* Resync trunk
[ Alexandre Abreu ]
* Small update to the --webapp flag documentation
[ Olivier Tilloy ]
* Null-check to fix a segmentation fault when --help is passed to the
  executable.
[ Olivier Tilloy ]
* Land the master Oxide support branch. See individual revisions for
  details. (LP: #1271756)
[ Alexandre Abreu ]
* There are 2 ways for the webapp-container to receive a list of
  patterns to filter url browsing in a webapp container: through the
  manifest.json file that comes with a given (named) webapp, or
  through the command line. At the moment, the 2 mechanisms are
  exclusive in the sense that from the webapp-container's perspective
  it only considers one or another when filtering navigation (the
  webapp manifest one being preferred) but they are NOT semantically
  equivalent. The list of url patterns in the manifest.json file is
  use as a mean to filter the urls that are being browsed to, but ALSO
  in the chromium & FF browsers to know if a webapp is to be
  installed/enabled when browsing in a given url. For example, for
  Gmail, the hostname mail.google.com is used as a trigger to ask the
  user for an installation/enablement of a webapp in the browser. It
  is also implicitely used as a filter for browser once in the
  container. The issue is that for applications like google services,
  the authentication mechanism is common. So when launched in the
  container, the user will be redirected to e.g.
  https://accounts.google.com or https://accounts.google.ca, etc. So,
  the manifest.json cannot be modified to account for those, since we
  dont want to install a webapp from those URLs but we need a way to
  add extra navigation url patterns to allow google service webapps to
  be redirected to e.g. https://accounts.google.* etc. We provide here
  2 things: an way for the url patterns passed down from the command
  line to be also considered in the navigation filtering,. a way to
  simplify url patterns for google apps (LP: #1288982)
[ Olivier Tilloy ]
* Use the renderer only once when rendering a thumbnail. This seems to
  fix the crash that was happening at destruction time. (LP: #1294219)

478. By Alberto Mardegan

WIP

479. By Alberto Mardegan

From trunk

[ Olivier Tilloy ]
* Fix FTBFS with Qt 5.3. (LP: #1321440)
[ Ubuntu daily release ]
* New rebuild forced
[ Olivier Tilloy ]
* Remove an extraneous whitespace in the default UA on mobile.
[ Michael Sheldon ]
* Add support for downloading images via download manager and content-
  hub on non-desktop platforms.
[ Tim Peeters ]
* Push the initial Page on the PageStack.
[ Ubuntu daily release ]
* New rebuild forced
[ Alexandre Abreu ]
* Add --local-webapp-manifest webapp container cli option to simplify
  the command line in the case of a local manifest.json file
  definition. This is to become a bit more important now that the
  manifest support thing like ua overrides that would be beneficial to
  webapp on touch.
[ Ubuntu daily release ]
* New rebuild forced
[ Alexandre Abreu ]
* Add capability for single webapps to have specific UA overrides for
  the website that they serve (LP: #1245465)
[ Olivier Tilloy ]
* Enable cross compilation for an ARM target on an X86 host.
* Port autopilot tests to Python 3.
[ Michael Sheldon ]
* Resolve image URLs beginning with a double slash correctly for
  context menu items (LP: #1311626)
[ Adnane Belmadiaf ]
* Enabled passwordEchoEnabled (LP: #1314251)
[ Alberto Mardegan ]
* Split UbuntuWebContext into two different components:
  UbuntuWebContext, which is a WebContext derivative with the UA
  overrides for Ubuntu. UbuntuSharedWebContext, which is a singleton
  for UbuntuWebContext .
[ Olivier Tilloy ]
* Build the models in a separate static lib, and link the unit tests
  against it. This speeds up build time by avoiding having to
  recompile the models’ source for each unit test.
* Handle javascript console messages.
* Escape literal dots in UA override matching regular expressions.
* Enable localStorage by default in the browser. (LP: #1309673)
* Ensure that the URL actually changes so that the address bar is
  updated in case the user has entered a new address that redirects to
  where she previously was. (LP: #1306615)
* Update bzr ignore rules.
[ Olivier Tilloy ]
* Work around a recent regression by forcing the OSK to show up when
  the address bar is being focused. (LP: #1316057)
[ CI bot ]
* Resync trunk
[ Alberto Mardegan ]
* Webapps: let SAML requests through SAML requests are used for
  instance by Google Apps for your domain; they are implemented as a
  HTTP redirect to a URL containing the query parameter called
  "SAMLRequest". Besides letting the request through, we must also add
  the SAML domain to the list of the allowed hosts. (LP: #1302780)
[ Ubuntu daily release ]
* New rebuild forced

480. By Alberto Mardegan

Fix cookies stores, add tests

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

614 + bool setCookies(Cookies);

Shouldn’t the argument be a "const Cookies&" ? (this applies to other methods that take a Cookies as argument)

Revision history for this message
Olivier Tilloy (osomon) wrote :

In CookieStore::doSetCookies(…), you could use the Q_UNIMPLEMENTED() macro to make it explicit that this method is meant to be re-implemented by subclasses.

Revision history for this message
Olivier Tilloy (osomon) wrote :

440 + QString dbPath() const;
1310 + QString dbPath() const;

Can those return a "const QString&" ?

Revision history for this message
Olivier Tilloy (osomon) wrote :

1108 + WebkitCookieStore {
1109 + id: webkitCookieStore
1110 + dbPath: dataLocation + "/.QtWebKit/cookies.db"
1111 + }
1112 +
1113 + ChromeCookieStore {
1114 + id: chromeCookieStore
1115 + dbPath: dataLocation + "/cookies.sqlite"
1116 + }

The two implementations of CookieStore are instantiated at all times, even though only one (or possibly none) of them is used. Can only one of them be instantiated dynamically in loadLoginView() instead?

Revision history for this message
Olivier Tilloy (osomon) wrote :

1344 +set(TEST tst_CookieStore)

Can this be renamed to "tst_CookieStoreTests", so that the bzr ignore rules will match the generated binary and xml output?

Revision history for this message
Olivier Tilloy (osomon) wrote :

1436 + makeCleanDir("/tmp/non-existing");
1437 + makeCleanDir("/tmp/non-existing2");

Please use QTemporaryDir instead to create truly unique and temporary directories.

Revision history for this message
Olivier Tilloy (osomon) wrote :

1442 + QCOMPARE(dbPathChanged.count(), 0);
1462 + QCOMPARE(dbPathChanged.count(), 0);

Those tests are useless, as you just instantiated the signal spy, so you are guaranteed that the count is 0.

481. By Alberto Mardegan

Fix the webapp container

482. By Alberto Mardegan

Merge from trunk

[ Ubuntu daily release ]
* New rebuild forced
[ Olivier Tilloy ]
* Ensure the main page that contains the webviews fills the main view.
  (LP: #1321462)
[ Olivier Tilloy ]
* Ensure the current webview is hidden while the activity view is
  visible, and work around a bug in oxide that prevented new empty
  tabs from rendering.
[ Ubuntu daily release ]
* New rebuild forced
[ Olivier Tilloy ]
* Various optimizations to the activity view. (LP: #1260980)
* Do not override the default height of the TextField that serves as
  the address bar. (LP: #1317866)

483. By Alberto Mardegan

Revert changes to pot file

484. By Alberto Mardegan

Address review comments

Revision history for this message
Alberto Mardegan (mardy) wrote :

On 05/29/2014 11:27 AM, Olivier Tilloy wrote:
> 614 + bool setCookies(Cookies);
>
> Shouldn’t the argument be a "const Cookies&" ? (this applies to other methods that take a Cookies as argument)

Fixed.

> In CookieStore::doSetCookies(…), you could use the Q_UNIMPLEMENTED() macro to make it explicit that this method is meant to be re-implemented by subclasses.

Done.

> 440 + QString dbPath() const;
> 1310 + QString dbPath() const;
>
> Can those return a "const QString&" ?

They could indeed, but I prefer not to return a reference, because that
exposes an implementation detail (the fact that we store the path as a
member variable in the class). I generally never return by reference,
unless I have a very good reason to; but if you feel strongly about
this, I can change it.

> The two implementations of CookieStore are instantiated at all times, even though only one (or possibly none) of them is used. Can only one of them be instantiated dynamically in loadLoginView() instead?

Done.

> 1344 +set(TEST tst_CookieStore)
>
> Can this be renamed to "tst_CookieStoreTests", so that the bzr ignore rules will match the generated binary and xml output?

Done.

> 1436 + makeCleanDir("/tmp/non-existing");
> 1437 + makeCleanDir("/tmp/non-existing2");
>
> Please use QTemporaryDir instead to create truly unique and temporary directories.

Done.

> 1442 + QCOMPARE(dbPathChanged.count(), 0);
> 1462 + QCOMPARE(dbPathChanged.count(), 0);
>
> Those tests are useless, as you just instantiated the signal spy, so you are guaranteed that the count is 0.

No idea what I was thinking :-) I've now removed them.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

> 1344 +set(TEST tst_CookieStore)
>
> Can this be renamed to "tst_CookieStoreTests", so that the bzr ignore rules
> will match the generated binary and xml output?

Almost there :)
You renamed it to "tst_CookieStoreTest", so it’s still missing the final "s" to match the other test cases’ naming convention.

Revision history for this message
Olivier Tilloy (osomon) :
485. By Alberto Mardegan

Rename test executable

Revision history for this message
Alberto Mardegan (mardy) wrote :

I changed the test name, and replied to your comment about the SQL connection name.

486. By Alberto Mardegan

Remove support for relative file paths

Revision history for this message
Olivier Tilloy (osomon) wrote :

Looks good to me now.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:486
http://jenkins.qa.ubuntu.com/job/webbrowser-app-ci/844/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/554/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic-touch/139/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-amd64-ci/43
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/43
        deb: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/43/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-i386-ci/43
    FAILURE: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/495/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/693
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/693/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/1160
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/1160/artifact/work/output/*zip*/output.zip
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-runner-mako/6775/console
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/7978

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/webbrowser-app-ci/844/rebuild

review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2014-05-02 05:45:21 +0000
3+++ debian/control 2014-06-02 11:59:43 +0000
4@@ -51,9 +51,12 @@
5 Multi-Arch: foreign
6 Depends: ${misc:Depends},
7 ${shlibs:Depends},
8+ libqt5webkit5-qmlwebkitplugin,
9+ qtdeclarative5-accounts-plugin,
10+ qtdeclarative5-qtquick2-plugin (>= 5.2),
11 unity-webapps-qml,
12- libqt5webkit5-qmlwebkitplugin,
13 webbrowser-app (= ${binary:Version}),
14+Suggests: qtdeclarative5-online-accounts-client0.1 (>= 0.3),
15 Description: Ubuntu web applications container
16 A lightweight webapps container tailored for Ubuntu, based on the Webkit
17 rendering engine and using the Ubuntu UI components.
18
19=== modified file 'src/app/browserapplication.cpp'
20--- src/app/browserapplication.cpp 2014-05-21 08:01:42 +0000
21+++ src/app/browserapplication.cpp 2014-06-02 11:59:43 +0000
22@@ -122,6 +122,9 @@
23 if (!isRunningInstalled()) {
24 m_engine->addImportPath(UbuntuBrowserImportsDirectory());
25 }
26+
27+ qmlEngineCreated(m_engine);
28+
29 QQmlContext* context = m_engine->rootContext();
30 m_component = new QQmlComponent(m_engine);
31 m_component->loadUrl(QUrl::fromLocalFile(UbuntuBrowserDirectory() + "/" + qmlFileSubPath));
32@@ -141,6 +144,9 @@
33 return true;
34 }
35
36+void BrowserApplication::qmlEngineCreated(QQmlEngine*)
37+{}
38+
39 int BrowserApplication::run()
40 {
41 Q_ASSERT(m_window != 0);
42
43=== modified file 'src/app/browserapplication.h'
44--- src/app/browserapplication.h 2014-04-10 14:47:53 +0000
45+++ src/app/browserapplication.h 2014-06-02 11:59:43 +0000
46@@ -49,6 +49,8 @@
47 virtual void printUsage() const = 0;
48 QList<QUrl> urls() const;
49
50+ virtual void qmlEngineCreated(QQmlEngine*);
51+
52 QStringList m_arguments;
53 QQmlEngine* m_engine;
54 QQuickWindow* m_window;
55
56=== added file 'src/app/webcontainer/AccountsPage.qml'
57--- src/app/webcontainer/AccountsPage.qml 1970-01-01 00:00:00 +0000
58+++ src/app/webcontainer/AccountsPage.qml 2014-06-02 11:59:43 +0000
59@@ -0,0 +1,73 @@
60+/*
61+ * Copyright 2013-2014 Canonical Ltd.
62+ *
63+ * This file is part of webbrowser-app.
64+ *
65+ * webbrowser-app is free software; you can redistribute it and/or modify
66+ * it under the terms of the GNU General Public License as published by
67+ * the Free Software Foundation; version 3.
68+ *
69+ * webbrowser-app is distributed in the hope that it will be useful,
70+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
71+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
72+ * GNU General Public License for more details.
73+ *
74+ * You should have received a copy of the GNU General Public License
75+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
76+ */
77+
78+import QtQuick 2.0
79+import Ubuntu.Components 0.1
80+import webcontainer.private 0.1
81+
82+Page {
83+ id: accountsPage
84+
85+ property alias accountProvider: accountsLogin.accountProvider
86+ property alias applicationName: accountsLogin.applicationName
87+ property var webappCookieStore: null
88+
89+ signal done()
90+
91+ visible: false
92+ anchors.fill: parent
93+
94+ AccountsLoginPage {
95+ id: accountsLogin
96+
97+ anchors.fill: parent
98+
99+ QtObject {
100+ id: internal
101+ function onMoved(result) {
102+ webappCookieStore.moved.disconnect(internal.onMoved)
103+ if (!result) {
104+ console.error("Unable to move cookies")
105+ }
106+ accountsPage.done()
107+ }
108+ }
109+
110+ onDone: {
111+ if (!accountsPage.visible)
112+ return
113+ if (!credentialsId) {
114+ accountsPage.done()
115+ return
116+ }
117+
118+ if (webappCookieStore) {
119+ var instance = onlineAccountStoreComponent.createObject(accountsLogin, {accountId: credentialsId})
120+ webappCookieStore.moved.connect(internal.onMoved)
121+ webappCookieStore.moveFrom(instance)
122+ } else {
123+ accountsPage.done()
124+ }
125+ }
126+ }
127+
128+ Component {
129+ id: onlineAccountStoreComponent
130+ OnlineAccountsCookieStore { }
131+ }
132+}
133
134=== modified file 'src/app/webcontainer/CMakeLists.txt'
135--- src/app/webcontainer/CMakeLists.txt 2014-04-03 12:01:59 +0000
136+++ src/app/webcontainer/CMakeLists.txt 2014-06-02 11:59:43 +0000
137@@ -9,7 +9,11 @@
138 set(WEBAPP_CONTAINER webapp-container)
139
140 set(WEBAPP_CONTAINER_SRC
141+ chrome-cookie-store.cpp
142+ cookie-store.cpp
143+ online-accounts-cookie-store.cpp
144 webapp-container.cpp
145+ webkit-cookie-store.cpp
146 session-utils.cpp
147 url-pattern-utils.cpp
148 )
149@@ -18,7 +22,7 @@
150
151 target_link_libraries(${WEBAPP_CONTAINER} ${COMMONLIB})
152
153-qt5_use_modules(${WEBAPP_CONTAINER} Core Widgets Quick)
154+qt5_use_modules(${WEBAPP_CONTAINER} Core Widgets Quick Sql DBus)
155
156 install(TARGETS ${WEBAPP_CONTAINER}
157 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
158
159=== added file 'src/app/webcontainer/chrome-cookie-store.cpp'
160--- src/app/webcontainer/chrome-cookie-store.cpp 1970-01-01 00:00:00 +0000
161+++ src/app/webcontainer/chrome-cookie-store.cpp 2014-06-02 11:59:43 +0000
162@@ -0,0 +1,218 @@
163+/*
164+ * Copyright 2014 Canonical Ltd.
165+ *
166+ * This file is part of webbrowser-app.
167+ *
168+ * webbrowser-app is free software; you can redistribute it and/or modify
169+ * it under the terms of the GNU General Public License as published by
170+ * the Free Software Foundation; version 3.
171+ *
172+ * webbrowser-app is distributed in the hope that it will be useful,
173+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
174+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
175+ * GNU General Public License for more details.
176+ *
177+ * You should have received a copy of the GNU General Public License
178+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
179+ */
180+
181+#include "chrome-cookie-store.h"
182+
183+#include <QDebug>
184+#include <QFileInfo>
185+#include <QNetworkCookie>
186+#include <QSqlError>
187+#include <QSqlQuery>
188+#include <QStandardPaths>
189+
190+static int connectionCounter = 0;
191+
192+static qint64 dateTimeToChrome(const QDateTime &time)
193+{
194+ /* Chrome uses Mon Jan 01 00:00:00 UTC 1601 as the epoch, hence the
195+ * magic number */
196+ return (time.toMSecsSinceEpoch() + 11644473600000) * 1000;
197+}
198+
199+static QDateTime dateTimeFromChrome(qint64 chromeTimeStamp)
200+{
201+ qint64 msecsSinceEpoch = chromeTimeStamp / 1000 - 11644473600000;
202+ return QDateTime::fromMSecsSinceEpoch(msecsSinceEpoch);
203+}
204+
205+ChromeCookieStore::ChromeCookieStore(QObject* parent):
206+ CookieStore(parent)
207+{
208+ QString connectionName =
209+ QString("chromeCookieStore-%1").arg(connectionCounter++);
210+ m_db = QSqlDatabase::addDatabase("QSQLITE", connectionName);
211+}
212+
213+Cookies ChromeCookieStore::doGetCookies()
214+{
215+ Cookies cookies;
216+ m_db.setDatabaseName(m_dbPath);
217+
218+ if (Q_UNLIKELY(!m_db.open())) {
219+ qCritical() << "Could not open cookie database:" << m_dbPath
220+ << m_db.lastError();
221+ return cookies;
222+ }
223+
224+ QSqlQuery q(m_db);
225+ q.exec("SELECT host_key, name, value, path, expires_utc, secure, httponly, has_expires FROM cookies;");
226+
227+ while (q.next()) {
228+ /* Build the cookie string from its parts */
229+ QNetworkCookie cookie(q.value(1).toString().toUtf8(),
230+ q.value(2).toString().toUtf8());
231+ cookie.setSecure(q.value(5).toBool());
232+ cookie.setHttpOnly(q.value(6).toBool());
233+ if (q.value(7).toBool()) {
234+ QDateTime expires = dateTimeFromChrome(q.value(4).toULongLong());
235+ cookie.setExpirationDate(expires);
236+ }
237+ cookie.setDomain(q.value(0).toString());
238+ cookie.setPath(q.value(3).toString());
239+ cookies.append(cookie.toRawForm());
240+ }
241+
242+ m_db.close();
243+ return cookies;
244+}
245+
246+QDateTime ChromeCookieStore::lastUpdateTimeStamp() const
247+{
248+ QFileInfo dbFileInfo(m_dbPath);
249+ return dbFileInfo.lastModified();
250+}
251+
252+bool ChromeCookieStore::createDb()
253+{
254+ if (Q_UNLIKELY(!m_db.transaction())) return false;
255+
256+ QSqlQuery q(m_db);
257+ bool ok;
258+ ok = q.exec("CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
259+ "value LONGVARCHAR)");
260+ if (Q_UNLIKELY(!ok)) {
261+ m_db.rollback();
262+ return false;
263+ }
264+
265+ ok = q.exec("CREATE TABLE cookies (creation_utc INTEGER NOT NULL UNIQUE PRIMARY KEY,"
266+ "host_key TEXT NOT NULL,"
267+ "name TEXT NOT NULL,"
268+ "value TEXT NOT NULL,"
269+ "path TEXT NOT NULL,"
270+ "expires_utc INTEGER NOT NULL,"
271+ "secure INTEGER NOT NULL,"
272+ "httponly INTEGER NOT NULL,"
273+ "last_access_utc INTEGER NOT NULL,"
274+ "has_expires INTEGER NOT NULL DEFAULT 1,"
275+ "persistent INTEGER NOT NULL DEFAULT 1,"
276+ "priority INTEGER NOT NULL DEFAULT 1,"
277+ "encrypted_value BLOB DEFAULT '')");
278+ if (Q_UNLIKELY(!ok)) {
279+ m_db.rollback();
280+ return false;
281+ }
282+
283+ ok = q.exec("CREATE INDEX domain ON cookies(host_key)");
284+ if (Q_UNLIKELY(!ok)) {
285+ m_db.rollback();
286+ return false;
287+ }
288+
289+ ok = q.exec("INSERT INTO meta (key, value) VALUES ('version', '7')");
290+ if (Q_UNLIKELY(!ok)) {
291+ m_db.rollback();
292+ return false;
293+ }
294+
295+ ok = q.exec("INSERT INTO meta (key, value) VALUES ('last_compatible_version', '5')");
296+ if (Q_UNLIKELY(!ok)) {
297+ m_db.rollback();
298+ return false;
299+ }
300+
301+ return m_db.commit();
302+}
303+
304+bool ChromeCookieStore::doSetCookies(const Cookies& cookies)
305+{
306+ m_db.setDatabaseName(m_dbPath);
307+
308+ if (!m_db.open()) {
309+ qCritical() << "Could not open cookie database:" <<
310+ m_dbPath << m_db.lastError().text();
311+ return false;
312+ }
313+
314+ QSqlQuery q(m_db);
315+ // Check whether the table already exists
316+ q.exec("SELECT name FROM sqlite_master WHERE type='table' AND name='cookies'");
317+ if (!q.next() && !createDb()) {
318+ qCritical() << "Could not create cookie database:" <<
319+ m_dbPath << m_db.lastError().text();
320+ return false;
321+ }
322+
323+ QList<QNetworkCookie> parsedCookies;
324+
325+ Q_FOREACH(const QByteArray &cookie, cookies) {
326+ parsedCookies.append(QNetworkCookie::parseCookies(cookie));
327+ }
328+
329+ q.prepare("INSERT INTO cookies (creation_utc,"
330+ "host_key, name, value, path,"
331+ "expires_utc, secure, httponly, last_access_utc,"
332+ "has_expires, persistent, priority, encrypted_value) "
333+ "VALUES (:creation_utc,"
334+ ":host_key, :name, :value, :path,"
335+ ":expires_utc, :secure, :httponly, :last_access_utc,"
336+ ":has_expires, :persistent, :priority, :encrypted_value)");
337+ Q_FOREACH(const QNetworkCookie &cookie, parsedCookies) {
338+ q.bindValue(":creation_utc",
339+ dateTimeToChrome(QDateTime::currentDateTimeUtc()));
340+ q.bindValue(":host_key", cookie.domain());
341+ q.bindValue(":name", cookie.name());
342+ q.bindValue(":value", cookie.value());
343+ q.bindValue(":path", cookie.path());
344+ q.bindValue(":expires_utc",
345+ dateTimeToChrome(cookie.expirationDate().toUTC()));
346+ q.bindValue(":secure", cookie.isSecure());
347+ q.bindValue(":httponly", cookie.isHttpOnly());
348+ q.bindValue(":last_access_utc",
349+ dateTimeToChrome(QDateTime::currentDateTimeUtc()));
350+ q.bindValue(":has_expires", cookie.expirationDate().isValid());
351+ q.bindValue(":persistent", true);
352+ q.bindValue(":priority", 1);
353+ q.bindValue(":encrypted_value", 1);
354+ q.exec();
355+ }
356+
357+ m_db.close();
358+
359+ return true;
360+}
361+
362+void ChromeCookieStore::setDbPath(const QString &path)
363+{
364+ // If path is a URL, strip the initial "file://"
365+ QString normalizedPath = path.startsWith("file://") ? path.mid(7) : path;
366+
367+ if (normalizedPath != m_dbPath) {
368+ if (Q_UNLIKELY(!normalizedPath.startsWith('/'))) {
369+ qWarning() << "Invalid database path (must be absolute):" << path;
370+ return;
371+ }
372+ m_dbPath = normalizedPath;
373+ Q_EMIT dbPathChanged();
374+ }
375+}
376+
377+QString ChromeCookieStore::dbPath () const
378+{
379+ return m_dbPath;
380+}
381
382=== added file 'src/app/webcontainer/chrome-cookie-store.h'
383--- src/app/webcontainer/chrome-cookie-store.h 1970-01-01 00:00:00 +0000
384+++ src/app/webcontainer/chrome-cookie-store.h 2014-06-02 11:59:43 +0000
385@@ -0,0 +1,53 @@
386+/*
387+ * Copyright 2014 Canonical Ltd.
388+ *
389+ * This file is part of webbrowser-app.
390+ *
391+ * webbrowser-app is free software; you can redistribute it and/or modify
392+ * it under the terms of the GNU General Public License as published by
393+ * the Free Software Foundation; version 3.
394+ *
395+ * webbrowser-app is distributed in the hope that it will be useful,
396+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
397+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
398+ * GNU General Public License for more details.
399+ *
400+ * You should have received a copy of the GNU General Public License
401+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
402+ */
403+
404+#ifndef CHROME_COOKIE_STORE_H
405+#define CHROME_COOKIE_STORE_H
406+
407+#include "cookie-store.h"
408+
409+#include <QSqlDatabase>
410+
411+class ChromeCookieStore : public CookieStore
412+{
413+ Q_OBJECT
414+ Q_PROPERTY(QString dbPath READ dbPath WRITE setDbPath NOTIFY dbPathChanged)
415+
416+public:
417+ ChromeCookieStore(QObject* parent = 0);
418+
419+ void setDbPath(const QString& path);
420+ QString dbPath() const;
421+
422+ QDateTime lastUpdateTimeStamp() const Q_DECL_OVERRIDE;
423+
424+Q_SIGNALS:
425+ void dbPathChanged();
426+
427+private:
428+ virtual Cookies doGetCookies() Q_DECL_OVERRIDE;
429+ virtual bool doSetCookies(const Cookies& cookies) Q_DECL_OVERRIDE;
430+
431+ bool createDb();
432+
433+private:
434+ QString m_dbPath;
435+ QSqlDatabase m_db;
436+};
437+
438+#endif // CHROME_COOKIE_STORE_H
439
440=== renamed file 'src/app/webcontainer/cookiestore.cpp' => 'src/app/webcontainer/cookie-store.cpp'
441--- src/app/webcontainer/cookiestore.cpp 2014-01-27 22:58:55 +0000
442+++ src/app/webcontainer/cookie-store.cpp 2014-06-02 11:59:43 +0000
443@@ -1,5 +1,5 @@
444 /*
445- * Copyright 2013 Canonical Ltd.
446+ * Copyright 2014 Canonical Ltd.
447 *
448 * This file is part of webbrowser-app.
449 *
450@@ -18,10 +18,10 @@
451
452 #include <QDebug>
453
454-#include "cookiestore.h"
455+#include "cookie-store.h"
456
457-CookieStore::CookieStore(QObject *parent)
458- : QObject(parent)
459+CookieStore::CookieStore(QObject* parent):
460+ QObject(parent)
461 {
462 qRegisterMetaType<Cookies>("Cookies");
463 }
464@@ -31,19 +31,26 @@
465 return doGetCookies();
466 }
467
468-void CookieStore::setCookies(Cookies cookies)
469+bool CookieStore::setCookies(const Cookies& cookies)
470 {
471- doSetCookies(cookies);
472+ if (doSetCookies(cookies)) {
473+ Q_EMIT cookiesChanged();
474+ return true;
475+ } else {
476+ return false;
477+ }
478 }
479
480 Cookies CookieStore::doGetCookies()
481 {
482+ Q_UNIMPLEMENTED();
483 return Cookies();
484 }
485
486-void CookieStore::doSetCookies(Cookies cookies)
487+bool CookieStore::doSetCookies(const Cookies& cookies)
488 {
489 Q_UNUSED(cookies);
490+ Q_UNIMPLEMENTED();
491 }
492
493 QDateTime CookieStore::lastUpdateTimeStamp() const
494@@ -51,33 +58,32 @@
495 return _lastUpdateTimeStamp;
496 }
497
498-void CookieStore::updateLastUpdateTimestamp(const QDateTime & timestamp)
499+void CookieStore::updateLastUpdateTimestamp(const QDateTime& timestamp)
500 {
501 _lastUpdateTimeStamp = timestamp;
502 }
503
504-void CookieStore::moveFrom(CookieStore *store)
505+void CookieStore::moveFrom(CookieStore* store)
506 {
507- if (! store)
508+ if (Q_UNLIKELY(!store))
509 return;
510
511- Cookies cookies =
512- store->cookies();
513-
514- QDateTime lastRemoteCookieUpdate =
515- store->lastUpdateTimeStamp();
516-
517- QDateTime lastLocalCookieUpdate =
518- lastUpdateTimeStamp();
519-
520- if (lastRemoteCookieUpdate.isValid()
521- && lastLocalCookieUpdate.isValid()
522- && (lastRemoteCookieUpdate < lastLocalCookieUpdate))
523+ Cookies cookies = store->cookies();
524+
525+ QDateTime lastRemoteCookieUpdate = store->lastUpdateTimeStamp();
526+ QDateTime lastLocalCookieUpdate = lastUpdateTimeStamp();
527+
528+ if (lastRemoteCookieUpdate.isValid() &&
529+ lastLocalCookieUpdate.isValid() &&
530+ (lastRemoteCookieUpdate < lastLocalCookieUpdate))
531 {
532 Q_EMIT moved(false);
533 return;
534 }
535
536- setCookies(cookies);
537+ if (setCookies(cookies)) {
538+ Q_EMIT moved(true);
539+ } else {
540+ Q_EMIT moved(false);
541+ }
542 }
543-
544
545=== renamed file 'src/app/webcontainer/cookiestore.h' => 'src/app/webcontainer/cookie-store.h'
546--- src/app/webcontainer/cookiestore.h 2014-01-27 22:58:55 +0000
547+++ src/app/webcontainer/cookie-store.h 2014-06-02 11:59:43 +0000
548@@ -1,5 +1,5 @@
549 /*
550- * Copyright 2013 Canonical Ltd.
551+ * Copyright 2014 Canonical Ltd.
552 *
553 * This file is part of webbrowser-app.
554 *
555@@ -16,62 +16,50 @@
556 * along with this program. If not, see <http://www.gnu.org/licenses/>.
557 */
558
559-#ifndef __COOKIESTORE_H__
560-#define __COOKIESTORE_H__
561+#ifndef __COOKIE_STORE_H__
562+#define __COOKIE_STORE_H__
563
564+#include <QByteArray>
565+#include <QDateTime>
566+#include <QList>
567 #include <QObject>
568-#include <QtCore/QList>
569-#include <QtCore/QString>
570-#include <QDateTime>
571-#include <QString>
572-#include <QMap>
573
574-typedef QMap<QString, QString> Cookies;
575+typedef QList<QByteArray> Cookies;
576 Q_DECLARE_METATYPE(Cookies);
577
578
579 class CookieStore : public QObject
580 {
581 Q_OBJECT
582- Q_PROPERTY(Cookies cookies READ \
583- cookies WRITE setCookies \
584+ Q_PROPERTY(Cookies cookies READ cookies WRITE setCookies \
585 NOTIFY cookiesChanged)
586- Q_PROPERTY(QDateTime lastUpdateTimeStamp \
587- READ lastUpdateTimeStamp \
588+ Q_PROPERTY(QDateTime lastUpdateTimeStamp READ lastUpdateTimeStamp \
589 NOTIFY lastUpdateTimeStampChanged)
590
591 public:
592-
593- CookieStore(QObject *parent = 0);
594-
595+ CookieStore(QObject* parent = 0);
596+
597+ bool setCookies(const Cookies& cookies);
598 Cookies cookies();
599- void setCookies(Cookies);
600
601 virtual QDateTime lastUpdateTimeStamp() const;
602
603- Q_INVOKABLE void moveFrom (CookieStore * store);
604+ Q_INVOKABLE void moveFrom(CookieStore* store);
605
606 Q_SIGNALS:
607-
608 void moved(bool);
609 void cookiesChanged();
610 void lastUpdateTimeStampChanged();
611
612 protected:
613-
614- void updateLastUpdateTimestamp(const QDateTime & timestamp);
615-
616+ void updateLastUpdateTimestamp(const QDateTime& timestamp);
617
618 private:
619-
620 virtual Cookies doGetCookies();
621- virtual void doSetCookies(Cookies);
622+ virtual bool doSetCookies(const Cookies& Cookies);
623
624 private:
625-
626 QDateTime _lastUpdateTimeStamp;
627 };
628
629-
630-#endif // __COOKIESTORE_H__
631-
632+#endif // __COOKIE_STORE_H__
633
634=== renamed file 'src/app/webcontainer/onlineaccountscookiestore.cpp' => 'src/app/webcontainer/online-accounts-cookie-store.cpp'
635--- src/app/webcontainer/onlineaccountscookiestore.cpp 2014-01-27 22:58:55 +0000
636+++ src/app/webcontainer/online-accounts-cookie-store.cpp 2014-06-02 11:59:43 +0000
637@@ -1,5 +1,5 @@
638 /*
639- * Copyright 2013 Canonical Ltd.
640+ * Copyright 2013-2014 Canonical Ltd.
641 *
642 * This file is part of webbrowser-app.
643 *
644@@ -16,7 +16,7 @@
645 * along with this program. If not, see <http://www.gnu.org/licenses/>.
646 */
647
648-#include "onlineaccountscookiestore.h"
649+#include "online-accounts-cookie-store.h"
650
651 #include <QList>
652 #include <QVariant>
653@@ -44,15 +44,12 @@
654 # define ONLINE_ACCOUNTS_COOKIE_STORE_METHOD "cookiesForIdentity"
655 #endif
656
657-class OnlineAccountsCookieStorePrivate : public QObject
658+class OnlineAccountsCookieStorePrivate
659 {
660- Q_OBJECT
661-
662 public:
663- OnlineAccountsCookieStorePrivate (QObject * parent = 0)
664- : QObject(parent),
665- _id (0),
666- m_connection (QDBusConnection::sessionBus())
667+ OnlineAccountsCookieStorePrivate():
668+ _id(0),
669+ m_connection(QDBusConnection::sessionBus())
670 {}
671
672 quint32 _id;
673@@ -135,9 +132,8 @@
674 return qdbus_cast<Cookies>(arguments.front());
675 }
676
677-void OnlineAccountsCookieStore::doSetCookies(Cookies cookies)
678+bool OnlineAccountsCookieStore::doSetCookies(const Cookies& cookies)
679 {
680 Q_UNUSED(cookies);
681+ return false;
682 }
683-
684-#include "onlineaccountscookiestore.moc"
685
686=== renamed file 'src/app/webcontainer/onlineaccountscookiestore.h' => 'src/app/webcontainer/online-accounts-cookie-store.h'
687--- src/app/webcontainer/onlineaccountscookiestore.h 2014-01-27 22:58:55 +0000
688+++ src/app/webcontainer/online-accounts-cookie-store.h 2014-06-02 11:59:43 +0000
689@@ -1,5 +1,5 @@
690 /*
691- * Copyright 2013 Canonical Ltd.
692+ * Copyright 2013-2014 Canonical Ltd.
693 *
694 * This file is part of webbrowser-app.
695 *
696@@ -16,10 +16,10 @@
697 * along with this program. If not, see <http://www.gnu.org/licenses/>.
698 */
699
700-#ifndef ONLINEACCOUNTSCOOKIESTORE_H
701-#define ONLINEACCOUNTSCOOKIESTORE_H
702+#ifndef ONLINE_ACCOUNTS_COOKIE_STORE_H
703+#define ONLINE_ACCOUNTS_COOKIE_STORE_H
704
705-#include "cookiestore.h"
706+#include "cookie-store.h"
707
708 class OnlineAccountsCookieStorePrivate;
709
710@@ -45,7 +45,7 @@
711 private:
712
713 virtual Cookies doGetCookies() Q_DECL_OVERRIDE;
714- virtual void doSetCookies(Cookies) Q_DECL_OVERRIDE;
715+ virtual bool doSetCookies(const Cookies& cookies) Q_DECL_OVERRIDE;
716
717
718 private:
719@@ -54,4 +54,4 @@
720 Q_DECLARE_PRIVATE(OnlineAccountsCookieStore)
721 };
722
723-#endif // ONLINEACCOUNTSCOOKIESTORE_H
724+#endif // ONLINE_ACCOUNTS_COOKIE_STORE_H
725
726=== removed file 'src/app/webcontainer/sqlitecookiestore.cpp'
727--- src/app/webcontainer/sqlitecookiestore.cpp 2014-02-07 16:44:50 +0000
728+++ src/app/webcontainer/sqlitecookiestore.cpp 1970-01-01 00:00:00 +0000
729@@ -1,99 +0,0 @@
730-/*
731- * Copyright 2013 Canonical Ltd.
732- *
733- * This file is part of webbrowser-app.
734- *
735- * webbrowser-app is free software; you can redistribute it and/or modify
736- * it under the terms of the GNU General Public License as published by
737- * the Free Software Foundation; version 3.
738- *
739- * webbrowser-app is distributed in the hope that it will be useful,
740- * but WITHOUT ANY WARRANTY; without even the implied warranty of
741- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
742- * GNU General Public License for more details.
743- *
744- * You should have received a copy of the GNU General Public License
745- * along with this program. If not, see <http://www.gnu.org/licenses/>.
746- */
747-
748-#include "sqlitecookiestore.h"
749-
750-#include <QSqlDatabase>
751-#include <QSqlError>
752-#include <QSqlQuery>
753-#include <QFileInfo>
754-#include <QStandardPaths>
755-#include <QDebug>
756-
757-
758-SqliteCookieStore::SqliteCookieStore(QObject *parent)
759- : CookieStore(parent)
760-{}
761-
762-Cookies SqliteCookieStore::doGetCookies()
763-{
764- return Cookies();
765-}
766-
767-QDateTime SqliteCookieStore::lastUpdateTimeStamp() const
768-{
769- QFileInfo dbFileInfo(getFullDbPathName ());
770- return dbFileInfo.lastModified();
771-}
772-
773-void SqliteCookieStore::doSetCookies(Cookies cookies)
774-{
775- QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
776- db.setDatabaseName (getFullDbPathName ());
777-
778- if ( ! db.open())
779- {
780- qCritical() << "Could not open cookie database: " << getFullDbPathName() << db.lastError();
781- Q_EMIT moved(false);
782- return;
783- }
784-
785- QSqlQuery q(db);
786- q.exec("CREATE TABLE IF NOT EXISTS cookies "
787- "(cookieId VARCHAR PRIMARY KEY, cookie BLOB)");
788- q.exec ("DELETE FROM cookies;");
789-
790- q.prepare("INSERT INTO cookies (cookieId, cookie) "
791- "VALUES (:cookieId, :cookie)");
792-
793- for (Cookies::const_iterator it = cookies.constBegin();
794- it != cookies.constEnd();
795- ++it)
796- {
797- q.bindValue(":cookieId", it.key());
798- q.bindValue(":cookie", it.value());
799-
800- if ( ! q.exec())
801- {
802- qWarning() << "Couldn't insert cookie into DB"
803- << it.key();
804- }
805- }
806-
807- Q_EMIT moved(true);
808-}
809-
810-QString SqliteCookieStore::getFullDbPathName() const
811-{
812- return QStandardPaths::standardLocations(QStandardPaths::HomeLocation)[0] + "/" + dbPath();
813-}
814-
815-void SqliteCookieStore::setDbPath(const QString &path)
816-{
817- if (path != m_dbPath)
818- {
819- m_dbPath = path;
820- Q_EMIT dbPathChanged();
821- }
822-}
823-
824-QString SqliteCookieStore::dbPath () const
825-{
826- return m_dbPath;
827-}
828-
829
830=== removed file 'src/app/webcontainer/sqlitecookiestore.h'
831--- src/app/webcontainer/sqlitecookiestore.h 2014-01-27 22:58:55 +0000
832+++ src/app/webcontainer/sqlitecookiestore.h 1970-01-01 00:00:00 +0000
833@@ -1,58 +0,0 @@
834-/*
835- * Copyright 2013 Canonical Ltd.
836- *
837- * This file is part of webbrowser-app.
838- *
839- * webbrowser-app is free software; you can redistribute it and/or modify
840- * it under the terms of the GNU General Public License as published by
841- * the Free Software Foundation; version 3.
842- *
843- * webbrowser-app is distributed in the hope that it will be useful,
844- * but WITHOUT ANY WARRANTY; without even the implied warranty of
845- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
846- * GNU General Public License for more details.
847- *
848- * You should have received a copy of the GNU General Public License
849- * along with this program. If not, see <http://www.gnu.org/licenses/>.
850- */
851-
852-#ifndef SQLITECOOKIESTORE_H
853-#define SQLITECOOKIESTORE_H
854-
855-#include "cookiestore.h"
856-#include <QString>
857-
858-
859-class SqliteCookieStore : public CookieStore
860-{
861- Q_OBJECT
862- Q_PROPERTY(QString dbPath READ dbPath WRITE setDbPath NOTIFY dbPathChanged)
863-
864-
865-public:
866- SqliteCookieStore(QObject *parent = 0);
867-
868- void setDbPath (const QString & path);
869- QString dbPath () const;
870-
871- QDateTime lastUpdateTimeStamp() const Q_DECL_OVERRIDE;
872-
873-
874-Q_SIGNALS:
875-
876- void dbPathChanged();
877-
878-
879-private:
880-
881- virtual Cookies doGetCookies() Q_DECL_OVERRIDE;
882- virtual void doSetCookies(Cookies) Q_DECL_OVERRIDE;
883-
884- QString getFullDbPathName() const;
885-
886-
887-private:
888- QString m_dbPath;
889-};
890-
891-#endif // SQLITECOOKIESTORE_H
892
893=== modified file 'src/app/webcontainer/webapp-container.cpp'
894--- src/app/webcontainer/webapp-container.cpp 2014-05-08 16:51:08 +0000
895+++ src/app/webcontainer/webapp-container.cpp 2014-06-02 11:59:43 +0000
896@@ -19,8 +19,11 @@
897 #include "config.h"
898 #include "webapp-container.h"
899
900+#include "chrome-cookie-store.h"
901+#include "online-accounts-cookie-store.h"
902 #include "session-utils.h"
903 #include "url-pattern-utils.h"
904+#include "webkit-cookie-store.h"
905
906 // Qt
907 #include <QtCore/QCoreApplication>
908@@ -30,14 +33,17 @@
909 #include <QtCore/QtGlobal>
910 #include <QtCore/QRegularExpression>
911 #include <QtCore/QTextStream>
912-#include <QtQuick/QQuickWindow>
913 #include <QtQml/QQmlComponent>
914 #include <QtQml/QQmlContext>
915 #include <QtQml/QQmlEngine>
916+#include <QtQml>
917+#include <QtQuick/QQuickWindow>
918
919 #include <QStandardPaths>
920 #include <QSettings>
921
922+static const char privateModuleUri[] = "webcontainer.private";
923+
924 namespace
925 {
926
927@@ -103,6 +109,7 @@
928 m_window->setProperty("webappName", m_webappName);
929 m_window->setProperty("backForwardButtonsVisible", m_backForwardButtonsVisible);
930 m_window->setProperty("addressBarVisible", m_addressBarVisible);
931+ m_window->setProperty("accountProvider", m_accountProvider);
932
933 qDebug() << "Using" << (m_withOxide ? "Oxide" : "QtWebkit") << "as the web engine backend";
934 m_window->setProperty("oxide", m_withOxide);
935@@ -134,6 +141,18 @@
936 }
937 }
938
939+void WebappContainer::qmlEngineCreated(QQmlEngine* engine)
940+{
941+ if (engine) {
942+ qmlRegisterType<ChromeCookieStore>(privateModuleUri, 0, 1,
943+ "ChromeCookieStore");
944+ qmlRegisterType<WebkitCookieStore>(privateModuleUri, 0, 1,
945+ "WebkitCookieStore");
946+ qmlRegisterType<OnlineAccountsCookieStore>(privateModuleUri, 0, 1,
947+ "OnlineAccountsCookieStore");
948+ }
949+}
950+
951 void WebappContainer::printUsage() const
952 {
953 QTextStream out(stdout);
954@@ -147,6 +166,7 @@
955 " [--webapp=name]"
956 " [--webappModelSearchPath=PATH]"
957 " [--webappUrlPatterns=URL_PATTERNS]"
958+ " [--accountProvider=PROVIDER_NAME]"
959 " [--enable-back-forward]"
960 " [--enable-addressbar]"
961 " [--store-session-cookies]"
962@@ -162,6 +182,7 @@
963 out << " --webapp=name try to match the webapp by name with an installed integration script" << endl;
964 out << " --webappModelSearchPath=PATH alter the search path for installed webapps and set it to PATH. PATH can be an absolute or path relative to CWD" << endl;
965 out << " --webappUrlPatterns=URL_PATTERNS list of comma-separated url patterns (wildcard based) that the webapp is allowed to navigate to" << endl;
966+ out << " --accountProvider=PROVIDER_NAME Online account provider for the application if the application is to reuse a local account." << endl;
967 out << " --store-session-cookies store session cookies on disk" << endl;
968 out << "Chrome options (if none specified, no chrome is shown by default):" << endl;
969 out << " --enable-back-forward enable the display of the back and forward buttons" << endl;
970@@ -190,6 +211,8 @@
971 QStringList includePatterns = tail.split(URL_PATTERN_SEPARATOR);
972 m_webappUrlPatterns = UrlPatternUtils::filterAndTransformUrlPatterns(includePatterns);
973 }
974+ } else if (argument.startsWith("--accountProvider=")) {
975+ m_accountProvider = argument.split("--accountProvider=")[1];
976 } else if (argument == "--store-session-cookies") {
977 m_storeSessionCookies = true;
978 } else if (argument == "--enable-back-forward") {
979
980=== modified file 'src/app/webcontainer/webapp-container.h'
981--- src/app/webcontainer/webapp-container.h 2014-05-08 16:51:08 +0000
982+++ src/app/webcontainer/webapp-container.h 2014-06-02 11:59:43 +0000
983@@ -34,6 +34,9 @@
984
985 bool initialize();
986
987+protected:
988+ void qmlEngineCreated(QQmlEngine *);
989+
990 private:
991 virtual void printUsage() const;
992 void parseCommandLine();
993@@ -44,6 +47,7 @@
994 QString m_webappName;
995 QString m_webappModelSearchPath;
996 QStringList m_webappUrlPatterns;
997+ QString m_accountProvider;
998 bool m_withOxide;
999 bool m_storeSessionCookies;
1000 bool m_backForwardButtonsVisible;
1001
1002=== modified file 'src/app/webcontainer/webapp-container.qml'
1003--- src/app/webcontainer/webapp-container.qml 2014-04-22 15:35:16 +0000
1004+++ src/app/webcontainer/webapp-container.qml 2014-06-02 11:59:43 +0000
1005@@ -1,5 +1,5 @@
1006 /*
1007- * Copyright 2013 Canonical Ltd.
1008+ * Copyright 2013-2014 Canonical Ltd.
1009 *
1010 * This file is part of webbrowser-app.
1011 *
1012@@ -19,22 +19,27 @@
1013 import QtQuick 2.0
1014 import QtQuick.Window 2.0
1015 import Ubuntu.Components 0.1
1016+import Ubuntu.Components.Extras.Browser 0.2
1017+import webcontainer.private 0.1
1018
1019 Window {
1020+ id: root
1021 objectName: "webappContainer"
1022
1023- property alias developerExtrasEnabled: browser.developerExtrasEnabled
1024-
1025- property alias backForwardButtonsVisible: browser.backForwardButtonsVisible
1026- property alias addressBarVisible: browser.addressBarVisible
1027-
1028- property alias url: browser.url
1029- property alias webappName: browser.webappName
1030- property alias webappModelSearchPath: browser.webappModelSearchPath
1031- property alias webappUrlPatterns: browser.webappUrlPatterns
1032- property alias oxide: browser.oxide
1033-
1034- contentOrientation: browser.screenOrientation
1035+ property bool developerExtrasEnabled: false
1036+
1037+ property bool backForwardButtonsVisible: true
1038+ property bool addressBarVisible: true
1039+
1040+ property string url: ""
1041+ property string webappName: ""
1042+ property string webappModelSearchPath: ""
1043+ property var webappUrlPatterns
1044+ property bool oxide: false
1045+ property string accountProvider: ""
1046+ property var __webappCookieStore: null
1047+
1048+ contentOrientation: Screen.orientation
1049
1050 width: 800
1051 height: 600
1052@@ -42,24 +47,107 @@
1053 title: {
1054 if (typeof(webappName) === 'string' && webappName.length !== 0) {
1055 return webappName
1056- } else if (browser.title) {
1057+ } else if (webappPageComponentLoader.item &&
1058+ webappPageComponentLoader.item.title) {
1059 // TRANSLATORS: %1 refers to the current page’s title
1060- return i18n.tr("%1 - Ubuntu Web Browser").arg(browser.title)
1061+ return i18n.tr("%1 - Ubuntu Web Browser").arg(webappPageComponentLoader.item.title)
1062 } else {
1063 return i18n.tr("Ubuntu Web Browser")
1064 }
1065 }
1066
1067- WebApp {
1068- id: browser
1069-
1070- property int screenOrientation: Screen.orientation
1071-
1072- chromeless: !backForwardButtonsVisible && !addressBarVisible
1073- webbrowserWindow: webbrowserWindowProxy
1074-
1075- anchors.fill: parent
1076-
1077- Component.onCompleted: i18n.domain = "webbrowser-app"
1078+ Loader {
1079+ id: webappPageComponentLoader
1080+ anchors.fill: parent
1081+ }
1082+
1083+ Component {
1084+ id: webappPageComponent
1085+
1086+ WebApp {
1087+ id: browser
1088+ addressBarVisible: root.addressBarVisible
1089+ backForwardButtonsVisible: root.backForwardButtonsVisible
1090+ developerExtrasEnabled: root.developerExtrasEnabled
1091+ oxide: root.oxide
1092+ url: root.url
1093+ webappModelSearchPath: root.webappModelSearchPath
1094+ webappName: root.webappName
1095+ webappUrlPatterns: root.webappUrlPatterns
1096+
1097+ anchors.fill: parent
1098+
1099+ chromeless: !backForwardButtonsVisible && !addressBarVisible
1100+ webbrowserWindow: webbrowserWindowProxy
1101+
1102+ Component.onCompleted: i18n.domain = "webbrowser-app"
1103+ }
1104+ }
1105+
1106+ Loader {
1107+ id: accountsPageComponentLoader
1108+ anchors.fill: parent
1109+ onStatusChanged: {
1110+ if (status == Loader.Error) {
1111+ // Happens on the desktop, if Ubuntu.OnlineAccounts.Client
1112+ // can't be imported
1113+ loadWebAppView()
1114+ } else if (status == Loader.Ready) {
1115+ item.visible = true
1116+ }
1117+ }
1118+ }
1119+
1120+ Connections {
1121+ target: accountsPageComponentLoader.item
1122+ onDone: loadWebAppView()
1123+ }
1124+
1125+ Component {
1126+ id: webkitCookieStoreComponent
1127+ WebkitCookieStore {
1128+ dbPath: dataLocation + "/.QtWebKit/cookies.db"
1129+ }
1130+ }
1131+
1132+ Component {
1133+ id: chromeCookieStoreComponent
1134+ ChromeCookieStore {
1135+ dbPath: dataLocation + "/cookies.sqlite"
1136+ }
1137+ }
1138+
1139+ Component.onCompleted: updateCurrentView()
1140+
1141+ onAccountProviderChanged: updateCurrentView();
1142+
1143+ function updateCurrentView() {
1144+ // check if we are to display the login view
1145+ // or directly switch to the webapp view
1146+ if (accountProvider.length !== 0) {
1147+ loadLoginView();
1148+ } else {
1149+ loadWebAppView();
1150+ }
1151+ }
1152+
1153+ function loadLoginView() {
1154+ if (!__webappCookieStore) {
1155+ var cookieStoreComponent =
1156+ oxide ? chromeCookieStoreComponent : webkitCookieStoreComponent
1157+ __webappCookieStore = cookieStoreComponent.createObject(this)
1158+ }
1159+ accountsPageComponentLoader.setSource("AccountsPage.qml", {
1160+ "accountProvider": accountProvider,
1161+ "applicationName": Qt.application.name,
1162+ "webappCookieStore": __webappCookieStore
1163+ })
1164+ }
1165+
1166+ function loadWebAppView() {
1167+ webappPageComponentLoader.sourceComponent = webappPageComponent;
1168+ if (accountsPageComponentLoader.item)
1169+ accountsPageComponentLoader.item.visible = false;
1170+ webappPageComponentLoader.item.visible = true;
1171 }
1172 }
1173
1174=== added file 'src/app/webcontainer/webkit-cookie-store.cpp'
1175--- src/app/webcontainer/webkit-cookie-store.cpp 1970-01-01 00:00:00 +0000
1176+++ src/app/webcontainer/webkit-cookie-store.cpp 2014-06-02 11:59:43 +0000
1177@@ -0,0 +1,120 @@
1178+/*
1179+ * Copyright 2014 Canonical Ltd.
1180+ *
1181+ * This file is part of webbrowser-app.
1182+ *
1183+ * webbrowser-app is free software; you can redistribute it and/or modify
1184+ * it under the terms of the GNU General Public License as published by
1185+ * the Free Software Foundation; version 3.
1186+ *
1187+ * webbrowser-app is distributed in the hope that it will be useful,
1188+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1189+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1190+ * GNU General Public License for more details.
1191+ *
1192+ * You should have received a copy of the GNU General Public License
1193+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1194+ */
1195+
1196+#include "webkit-cookie-store.h"
1197+
1198+#include <QDebug>
1199+#include <QFileInfo>
1200+#include <QNetworkCookie>
1201+#include <QSqlError>
1202+#include <QSqlQuery>
1203+#include <QStandardPaths>
1204+
1205+static int connectionCounter = 0;
1206+
1207+WebkitCookieStore::WebkitCookieStore(QObject* parent):
1208+ CookieStore(parent)
1209+{
1210+ QString connectionName =
1211+ QString("webkitCookieStore-%1").arg(connectionCounter++);
1212+ m_db = QSqlDatabase::addDatabase("QSQLITE", connectionName);
1213+}
1214+
1215+Cookies WebkitCookieStore::doGetCookies()
1216+{
1217+ Cookies cookies;
1218+ m_db.setDatabaseName(m_dbPath);
1219+
1220+ if (!m_db.open()) {
1221+ qCritical() << "Could not open cookie database:" << m_dbPath << m_db.lastError();
1222+ return cookies;
1223+ }
1224+
1225+ QSqlQuery q(m_db);
1226+ q.exec("SELECT cookie FROM cookies;");
1227+
1228+ while (q.next()) {
1229+ cookies.append(q.value(0).toString().toUtf8());
1230+ }
1231+
1232+ m_db.close();
1233+ return cookies;
1234+}
1235+
1236+QDateTime WebkitCookieStore::lastUpdateTimeStamp() const
1237+{
1238+ QFileInfo dbFileInfo(m_dbPath);
1239+ return dbFileInfo.lastModified();
1240+}
1241+
1242+bool WebkitCookieStore::doSetCookies(const Cookies& cookies)
1243+{
1244+ m_db.setDatabaseName(m_dbPath);
1245+
1246+ if (!m_db.open()) {
1247+ qCritical() << "Could not open cookie database:" << m_dbPath << m_db.lastError();
1248+ return false;
1249+ }
1250+
1251+ QSqlQuery q(m_db);
1252+ q.exec("CREATE TABLE IF NOT EXISTS cookies "
1253+ "(cookieId VARCHAR PRIMARY KEY, cookie BLOB)");
1254+ q.exec ("DELETE FROM cookies;");
1255+
1256+ q.prepare("INSERT INTO cookies (cookieId, cookie) "
1257+ "VALUES (:cookieId, :cookie)");
1258+
1259+ Q_FOREACH(const QByteArray& cookie, cookies) {
1260+ /* The unique key is the hostname + the cookie name */
1261+ QList<QNetworkCookie> parsed = QNetworkCookie::parseCookies(cookie);
1262+ if (parsed.isEmpty()) continue;
1263+
1264+ const QNetworkCookie& c = parsed.first();
1265+ q.bindValue(":cookieId", c.domain() + c.name());
1266+ q.bindValue(":cookie", cookie);
1267+
1268+ if (!q.exec()) {
1269+ qWarning() << "Couldn't insert cookie into DB" << cookie;
1270+ }
1271+ }
1272+
1273+ m_db.close();
1274+
1275+ return true;
1276+}
1277+
1278+void WebkitCookieStore::setDbPath(const QString& path)
1279+{
1280+ // If path is a URL, strip the initial "file://"
1281+ QString normalizedPath = path.startsWith("file://") ? path.mid(7) : path;
1282+
1283+ if (path != m_dbPath) {
1284+ if (Q_UNLIKELY(!normalizedPath.startsWith('/'))) {
1285+ qWarning() << "Invalid database path (must be absolute):" << path;
1286+ return;
1287+ }
1288+ m_dbPath = path;
1289+ Q_EMIT dbPathChanged();
1290+ }
1291+}
1292+
1293+QString WebkitCookieStore::dbPath() const
1294+{
1295+ return m_dbPath;
1296+}
1297+
1298
1299=== added file 'src/app/webcontainer/webkit-cookie-store.h'
1300--- src/app/webcontainer/webkit-cookie-store.h 1970-01-01 00:00:00 +0000
1301+++ src/app/webcontainer/webkit-cookie-store.h 2014-06-02 11:59:43 +0000
1302@@ -0,0 +1,51 @@
1303+/*
1304+ * Copyright 2014 Canonical Ltd.
1305+ *
1306+ * This file is part of webbrowser-app.
1307+ *
1308+ * webbrowser-app is free software; you can redistribute it and/or modify
1309+ * it under the terms of the GNU General Public License as published by
1310+ * the Free Software Foundation; version 3.
1311+ *
1312+ * webbrowser-app is distributed in the hope that it will be useful,
1313+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1314+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1315+ * GNU General Public License for more details.
1316+ *
1317+ * You should have received a copy of the GNU General Public License
1318+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1319+ */
1320+
1321+#ifndef WEBKIT_COOKIE_STORE_H
1322+#define WEBKIT_COOKIE_STORE_H
1323+
1324+#include "cookie-store.h"
1325+
1326+#include <QSqlDatabase>
1327+
1328+class WebkitCookieStore : public CookieStore
1329+{
1330+ Q_OBJECT
1331+ Q_PROPERTY(QString dbPath READ dbPath WRITE setDbPath NOTIFY dbPathChanged)
1332+
1333+public:
1334+ WebkitCookieStore(QObject* parent = 0);
1335+
1336+ void setDbPath(const QString& path);
1337+ QString dbPath() const;
1338+
1339+ QDateTime lastUpdateTimeStamp() const Q_DECL_OVERRIDE;
1340+
1341+Q_SIGNALS:
1342+ void dbPathChanged();
1343+
1344+private:
1345+ virtual Cookies doGetCookies() Q_DECL_OVERRIDE;
1346+ virtual bool doSetCookies(const Cookies& cookies) Q_DECL_OVERRIDE;
1347+
1348+private:
1349+ QString m_dbPath;
1350+ QSqlDatabase m_db;
1351+};
1352+
1353+#endif // WEBKIT_COOKIE_STORE_H
1354
1355=== modified file 'tests/unittests/CMakeLists.txt'
1356--- tests/unittests/CMakeLists.txt 2014-04-03 12:54:12 +0000
1357+++ tests/unittests/CMakeLists.txt 2014-06-02 11:59:43 +0000
1358@@ -10,3 +10,4 @@
1359 add_subdirectory(tabs-model)
1360 add_subdirectory(bookmarks-model)
1361 add_subdirectory(container-url-patterns)
1362+add_subdirectory(cookie-store)
1363
1364=== added directory 'tests/unittests/cookie-store'
1365=== added file 'tests/unittests/cookie-store/CMakeLists.txt'
1366--- tests/unittests/cookie-store/CMakeLists.txt 1970-01-01 00:00:00 +0000
1367+++ tests/unittests/cookie-store/CMakeLists.txt 2014-06-02 11:59:43 +0000
1368@@ -0,0 +1,11 @@
1369+set(TEST tst_CookieStoreTests)
1370+set(SOURCES
1371+ ${webapp-container_SOURCE_DIR}/chrome-cookie-store.cpp
1372+ ${webapp-container_SOURCE_DIR}/cookie-store.cpp
1373+ ${webapp-container_SOURCE_DIR}/webkit-cookie-store.cpp
1374+ tst_CookieStore.cpp
1375+)
1376+add_executable(${TEST} ${SOURCES})
1377+include_directories(${webapp-container_SOURCE_DIR})
1378+qt5_use_modules(${TEST} Core Network Sql Test)
1379+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
1380
1381=== added file 'tests/unittests/cookie-store/tst_CookieStore.cpp'
1382--- tests/unittests/cookie-store/tst_CookieStore.cpp 1970-01-01 00:00:00 +0000
1383+++ tests/unittests/cookie-store/tst_CookieStore.cpp 2014-06-02 11:59:43 +0000
1384@@ -0,0 +1,189 @@
1385+/*
1386+ * Copyright 2014 Canonical Ltd.
1387+ *
1388+ * This file is part of webbrowser-app.
1389+ *
1390+ * webbrowser-app is free software; you can redistribute it and/or modify
1391+ * it under the terms of the GNU General Public License as published by
1392+ * the Free Software Foundation; version 3.
1393+ *
1394+ * webbrowser-app is distributed in the hope that it will be useful,
1395+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1396+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1397+ * GNU General Public License for more details.
1398+ *
1399+ * You should have received a copy of the GNU General Public License
1400+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1401+ */
1402+
1403+// Qt
1404+#include <QtCore/QDir>
1405+#include <QtCore/QSet>
1406+#include <QtCore/QTemporaryDir>
1407+#include <QtNetwork/QNetworkCookie>
1408+#include <QtTest/QSignalSpy>
1409+#include <QtTest/QtTest>
1410+
1411+// local
1412+#include "chrome-cookie-store.h"
1413+#include "webkit-cookie-store.h"
1414+
1415+uint qHash(const QNetworkCookie &cookie, uint seed)
1416+{
1417+ return qHash(cookie.toRawForm(), seed);
1418+}
1419+
1420+class CookieStoreTest : public QObject
1421+{
1422+ Q_OBJECT
1423+
1424+private Q_SLOTS:
1425+ void testChromeProperties();
1426+ void testWebkitProperties();
1427+
1428+ void testChromeReadWrite_data() { setupCookieData(); }
1429+ void testWebkitReadWrite_data() { setupCookieData(); }
1430+ void testChromeReadWrite();
1431+ void testWebkitReadWrite();
1432+
1433+ void testMoving_data() { setupCookieData(); }
1434+ void testMoving();
1435+
1436+private:
1437+ void setupCookieData();
1438+ QSet<QNetworkCookie> parseCookies(const Cookies &rawCookies);
1439+};
1440+
1441+QSet<QNetworkCookie>
1442+CookieStoreTest::parseCookies(const Cookies &rawCookies)
1443+{
1444+ QList<QNetworkCookie> cookies;
1445+ Q_FOREACH(const QByteArray &rawCookie, rawCookies) {
1446+ cookies.append(QNetworkCookie::parseCookies(rawCookie));
1447+ }
1448+ return cookies.toSet();
1449+}
1450+
1451+void CookieStoreTest::testChromeProperties()
1452+{
1453+ QTemporaryDir tmpDir;
1454+ QVERIFY(tmpDir.isValid());
1455+ QTemporaryDir tmpDir2;
1456+ QVERIFY(tmpDir2.isValid());
1457+
1458+ ChromeCookieStore store;
1459+ QSignalSpy dbPathChanged(&store, SIGNAL(dbPathChanged()));
1460+
1461+ store.setProperty("dbPath", tmpDir.path());
1462+ QCOMPARE(dbPathChanged.count(), 1);
1463+ QCOMPARE(store.property("dbPath").toString(), tmpDir.path());
1464+ dbPathChanged.clear();
1465+
1466+ store.setProperty("dbPath", "file://" + tmpDir2.path());
1467+ QCOMPARE(dbPathChanged.count(), 1);
1468+ QCOMPARE(store.property("dbPath").toString(), tmpDir2.path());
1469+
1470+ QVERIFY(store.property("cookies").value<Cookies>().isEmpty());
1471+}
1472+
1473+void CookieStoreTest::testWebkitProperties()
1474+{
1475+ QTemporaryDir tmpDir;
1476+ QVERIFY(tmpDir.isValid());
1477+
1478+ WebkitCookieStore store;
1479+ QSignalSpy dbPathChanged(&store, SIGNAL(dbPathChanged()));
1480+
1481+ store.setProperty("dbPath", tmpDir.path());
1482+ QCOMPARE(dbPathChanged.count(), 1);
1483+ QCOMPARE(store.property("dbPath").toString(), tmpDir.path());
1484+
1485+ QVERIFY(store.property("cookies").value<Cookies>().isEmpty());
1486+}
1487+
1488+void CookieStoreTest::setupCookieData()
1489+{
1490+ QTest::addColumn<Cookies>("cookies");
1491+
1492+ Cookies cookies;
1493+
1494+ cookies << "LSID=DQAAAKEaem_vYg; Domain=docs.foo.com; Path=/accounts; "
1495+ "Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly";
1496+ QTest::newRow("Single cookie") << cookies;
1497+
1498+ cookies.clear();
1499+ cookies << "LSID=DQAAAKEaem_vYg; Domain=docs.foo.com; Path=/accounts; "
1500+ "Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly";
1501+ cookies << "HSID=AYQEVnDKrdst; Domain=.foo.com; Path=/; "
1502+ "Expires=Wed, 13 Jan 2021 22:23:01 GMT; HttpOnly";
1503+ cookies << "SSID=Ap4PGTEq; Domain=foo.com; Path=/; "
1504+ "Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure";
1505+ cookies << "made_write_conn=1295214458; Path=/; Domain=.example.com";
1506+ QTest::newRow("Few cookies") << cookies;
1507+}
1508+
1509+void CookieStoreTest::testChromeReadWrite()
1510+{
1511+ QFETCH(Cookies, cookies);
1512+
1513+ QTemporaryDir tmpDir;
1514+ QVERIFY(tmpDir.isValid());
1515+ QDir testDir(tmpDir.path());
1516+
1517+ ChromeCookieStore store;
1518+ QSignalSpy cookiesChanged(&store, SIGNAL(cookiesChanged()));
1519+ store.setDbPath(testDir.filePath("cookies.db"));
1520+
1521+ QCOMPARE(cookiesChanged.count(), 0);
1522+ store.setProperty("cookies", QVariant::fromValue(cookies));
1523+ QCOMPARE(cookiesChanged.count(), 1);
1524+ Cookies readCookies = store.property("cookies").value<Cookies>();
1525+ QCOMPARE(parseCookies(readCookies), parseCookies(cookies));
1526+}
1527+
1528+void CookieStoreTest::testWebkitReadWrite()
1529+{
1530+ QFETCH(Cookies, cookies);
1531+
1532+ QTemporaryDir tmpDir;
1533+ QVERIFY(tmpDir.isValid());
1534+ QDir testDir(tmpDir.path());
1535+
1536+ WebkitCookieStore store;
1537+ QSignalSpy cookiesChanged(&store, SIGNAL(cookiesChanged()));
1538+ store.setDbPath(testDir.filePath("cookies.db"));
1539+
1540+ QCOMPARE(cookiesChanged.count(), 0);
1541+ store.setProperty("cookies", QVariant::fromValue(cookies));
1542+ QCOMPARE(cookiesChanged.count(), 1);
1543+ Cookies readCookies = store.property("cookies").value<Cookies>();
1544+ QCOMPARE(parseCookies(readCookies), parseCookies(cookies));
1545+}
1546+
1547+void CookieStoreTest::testMoving()
1548+{
1549+ QFETCH(Cookies, cookies);
1550+
1551+ QTemporaryDir tmpDir;
1552+ QVERIFY(tmpDir.isValid());
1553+ QDir testDir(tmpDir.path());
1554+
1555+ WebkitCookieStore webkitStore;
1556+ webkitStore.setDbPath(testDir.filePath("webkit.db"));
1557+ webkitStore.setProperty("cookies", QVariant::fromValue(cookies));
1558+
1559+ ChromeCookieStore chromeStore;
1560+ chromeStore.setDbPath(testDir.filePath("chrome.db"));
1561+
1562+ QSignalSpy moved(&chromeStore, SIGNAL(moved(bool)));
1563+ chromeStore.moveFrom(&webkitStore);
1564+
1565+ QCOMPARE(moved.count(), 1);
1566+ QCOMPARE(moved.at(0).at(0).toBool(), true);
1567+
1568+ Cookies movedCookies = chromeStore.property("cookies").value<Cookies>();
1569+ QCOMPARE(parseCookies(movedCookies), parseCookies(cookies));
1570+}
1571+
1572+QTEST_MAIN(CookieStoreTest)
1573+#include "tst_CookieStore.moc"

Subscribers

People subscribed via source and target branches

to status/vote changes: