Merge lp:~abreu-alexandre/webbrowser-app/webapp-homepage into lp:webbrowser-app

Proposed by Alexandre Abreu on 2014-10-07
Status: Superseded
Proposed branch: lp:~abreu-alexandre/webbrowser-app/webapp-homepage
Merge into: lp:webbrowser-app
Diff against target: 872 lines (+288/-103)
16 files modified
po/webbrowser-app.pot (+14/-14)
src/app/webcontainer/Chrome.qml (+1/-1)
src/app/webcontainer/WebApp.qml (+4/-12)
src/app/webcontainer/WebViewImplOxide.qml (+34/-20)
src/app/webcontainer/WebViewImplWebkit.qml (+4/-1)
src/app/webcontainer/WebappContainerWebview.qml (+5/-2)
src/app/webcontainer/url-pattern-utils.cpp (+28/-7)
src/app/webcontainer/url-pattern-utils.h (+2/-1)
src/app/webcontainer/webapp-container.cpp (+24/-13)
src/app/webcontainer/webapp-container.h (+1/-1)
src/app/webcontainer/webapp-container.qml (+24/-9)
tests/autopilot/webapp_container/tests/__init__.py (+43/-5)
tests/autopilot/webapp_container/tests/fake_servers.py (+28/-8)
tests/autopilot/webapp_container/tests/test_app_launch.py (+1/-1)
tests/autopilot/webapp_container/tests/test_redirection_pattern.py (+59/-0)
tests/unittests/container-url-patterns/tst_ContainerUrlPatternsTests.cpp (+16/-8)
To merge this branch: bzr merge lp:~abreu-alexandre/webbrowser-app/webapp-homepage
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing on 2014-10-11
Olivier Tilloy Approve on 2014-10-10
David Barth (community) 2014-10-07 Approve on 2014-10-09
Review via email: mp+237456@code.launchpad.net

Commit message

Webapp homepage only considered if no command line override is provided. Add support for StateSaver url tracking.

Description of the change

Webapp homepage only considered if no command line override is provided. Add support for StateSaver url tracking.

To post a comment you must log in.
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
760. By Launchpad Translations on behalf of phablet-team on 2014-10-09

Launchpad automatic translations update.

David Barth (dbarth) :
review: Approve
Olivier Tilloy (osomon) wrote :

This changeset does much more than what it says on the tin. Please update the commit message to make it clear that this introduces StateSaver support for the webapp container. Also, wasn’t there a bug report to track the introduction of StateSaver? If so, please link it to the MR, and if not please file one and link it.

review: Needs Fixing
Olivier Tilloy (osomon) wrote :

Given that updateBrowserUrl() is called only in one place, I don’t think factoring it out in its own function is useful. But it doesn’t harm either, I guess.

Code changes look good, not functionally tested.

review: Approve
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:753
http://jenkins.qa.ubuntu.com/job/webbrowser-app-ci/1177/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/5811/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/4037
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-amd64-ci/376
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/376
        deb: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/376/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-i386-ci/376
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/5466/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/7063
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/7063/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/14503
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/3404
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/4366
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/4366/artifact/work/output/*zip*/output.zip

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

review: Needs Fixing (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:753
http://jenkins.qa.ubuntu.com/job/webbrowser-app-ci/1179/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/5825/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/4042
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-amd64-ci/378
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/378
        deb: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/378/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-i386-ci/378
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/5479/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/7077
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/7077/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/14521
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/3409
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/4371
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/4371/artifact/work/output/*zip*/output.zip

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

review: Needs Fixing (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
761. By Launchpad Translations on behalf of phablet-team on 2014-10-14

Launchpad automatic translations update.

762. By Launchpad Translations on behalf of phablet-team on 2014-10-15

Launchpad automatic translations update.

763. By Michael Sheldon on 2014-10-15

Detect 7 digital album downloads and request that they get unzipped by download manager. Fixes: 1365993
Approved by: PS Jenkins bot, Olivier Tilloy

764. By PS Jenkins bot on 2014-10-15

Releasing 0.23+14.10.20141015.1-0ubuntu1

765. By PS Jenkins bot on 2014-10-17

Resync trunk

766. By Launchpad Translations on behalf of phablet-team on 2014-10-18

Launchpad automatic translations update.

767. By Launchpad Translations on behalf of phablet-team on 2014-10-19

Launchpad automatic translations update.

768. By Olivier Tilloy on 2014-10-28

Fix the override mechanism for navigator.userAgent,
and add UA override rules for HSBC’s Brazilian mobile site and ESPN’s mobile site. Fixes: 1316259, 1380657
Approved by: Bill Filler, PS Jenkins bot

769. By PS Jenkins bot on 2014-10-28

Releasing 0.23+14.10.20141028~rtm-0ubuntu1

770. By PS Jenkins bot on 2014-10-29

Resync trunk

771. By Riccardo Padovani on 2014-10-29

Fixed #1378975 - Fast double click on menu button opens menu twice Fixes: 1378975
Approved by: Olivier Tilloy

772. By Riccardo Padovani on 2014-10-29

Updated the README
Approved by: Olivier Tilloy

773. By Jean-Francois Moy on 2014-10-29

Twitter User Script - Hide the prompt to download the Android application. Fixes: 1352789, 1377268, 1378008
Approved by: Alexandre Abreu, Olivier Tilloy

774. By PS Jenkins bot on 2014-10-29

Fix the override mechanism for navigator.userAgent,
and add UA override rules for HSBC’s Brazilian mobile site and ESPN’s mobile site. Fixes: 1316259, 1380657
Approved by: Bill Filler, PS Jenkins bot

775. By Olivier Tilloy on 2014-10-29

Prevent the browser from trying to download embedded flash applications. Fixes: 1379806
Approved by: Alexandre Abreu

776. By Olivier Tilloy on 2014-10-29

Fix a harmless compilation warning found by clang (non-literal-null-conversion).

777. By Olivier Tilloy on 2014-10-29

Update UITK autopilot test imports. Fixes: 1386276
Approved by: Zsombor Egri, PS Jenkins bot

778. By PS Jenkins bot on 2014-10-29

Releasing 0.23+15.04.20141029.1-0ubuntu1

779. By Alexandre Abreu on 2014-10-29

Webapp homepage only considered if no command line override is provided. Add support for StateSaver url tracking.

Unmerged revisions

779. By Alexandre Abreu on 2014-10-29

Webapp homepage only considered if no command line override is provided. Add support for StateSaver url tracking.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'po/webbrowser-app.pot'
2--- po/webbrowser-app.pot 2014-10-03 14:41:14 +0000
3+++ po/webbrowser-app.pot 2014-10-20 22:12:22 +0000
4@@ -8,7 +8,7 @@
5 msgstr ""
6 "Project-Id-Version: webbrowser-app\n"
7 "Report-Msgid-Bugs-To: \n"
8-"POT-Creation-Date: 2014-09-22 14:59+0100\n"
9+"POT-Creation-Date: 2014-10-20 17:24-0400\n"
10 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
11 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12 "Language-Team: LANGUAGE <LL@li.org>\n"
13@@ -117,7 +117,7 @@
14 msgstr ""
15
16 #: src/app/GeolocationPermissionRequest.qml:29
17-#: src/app/webcontainer/WebViewImplWebkit.qml:65
18+#: src/app/webcontainer/WebViewImplWebkit.qml:68
19 msgid "This page wants to know your device’s location."
20 msgstr ""
21
22@@ -406,19 +406,19 @@
23 msgid "search or enter an address"
24 msgstr ""
25
26-#: src/app/webbrowser/Browser.qml:179
27+#: src/app/webbrowser/Browser.qml:190
28 msgid "Share"
29 msgstr ""
30
31-#: src/app/webbrowser/Browser.qml:193
32+#: src/app/webbrowser/Browser.qml:204
33 msgid "History"
34 msgstr ""
35
36-#: src/app/webbrowser/Browser.qml:200
37+#: src/app/webbrowser/Browser.qml:211
38 msgid "Open tabs"
39 msgstr ""
40
41-#: src/app/webbrowser/Browser.qml:206 src/app/webbrowser/TabsView.qml:57
42+#: src/app/webbrowser/Browser.qml:217 src/app/webbrowser/TabsView.qml:57
43 msgid "New tab"
44 msgstr ""
45
46@@ -445,19 +445,19 @@
47 msgid "Done"
48 msgstr ""
49
50-#: src/app/webbrowser/HistoryView.qml:113
51+#: src/app/webbrowser/HistoryView.qml:112
52 msgid "Clear"
53 msgstr ""
54
55-#: src/app/webbrowser/HistoryView.qml:127
56+#: src/app/webbrowser/HistoryView.qml:126
57 msgid "Delete all history?"
58 msgstr ""
59
60-#: src/app/webbrowser/HistoryView.qml:130
61+#: src/app/webbrowser/HistoryView.qml:129
62 msgid "Yes"
63 msgstr ""
64
65-#: src/app/webbrowser/HistoryView.qml:139
66+#: src/app/webbrowser/HistoryView.qml:138
67 msgid "No"
68 msgstr ""
69
70@@ -481,7 +481,7 @@
71 msgid "Tap to view"
72 msgstr ""
73
74-#: src/app/webbrowser/TabsView.qml:115
75+#: src/app/webbrowser/TabsView.qml:114
76 msgid "Add"
77 msgstr ""
78
79@@ -497,15 +497,15 @@
80 msgid "Ubuntu Web Browser"
81 msgstr ""
82
83-#: src/app/webcontainer/AccountsLoginPage.qml:87
84+#: src/app/webcontainer/AccountsLoginPage.qml:91
85 msgid "No local account found for "
86 msgstr ""
87
88-#: src/app/webcontainer/AccountsLoginPage.qml:92
89+#: src/app/webcontainer/AccountsLoginPage.qml:96
90 msgid "Skip account creation step"
91 msgstr ""
92
93-#: src/app/webcontainer/AccountsLoginPage.qml:141
94+#: src/app/webcontainer/AccountsLoginPage.qml:145
95 msgid "Add account"
96 msgstr ""
97
98
99=== modified file 'src/app/webcontainer/Chrome.qml'
100--- src/app/webcontainer/Chrome.qml 2014-07-29 21:51:07 +0000
101+++ src/app/webcontainer/Chrome.qml 2014-10-20 22:12:22 +0000
102@@ -82,7 +82,7 @@
103
104 Favicon {
105 anchors.centerIn: parent
106- source: chrome.webview.icon
107+ source: chrome.webview ? chrome.webview.icon : null
108 }
109 }
110
111
112=== modified file 'src/app/webcontainer/WebApp.qml'
113--- src/app/webcontainer/WebApp.qml 2014-10-03 14:41:14 +0000
114+++ src/app/webcontainer/WebApp.qml 2014-10-20 22:12:22 +0000
115@@ -36,9 +36,10 @@
116 property alias oxide: webview.withOxide
117 property alias webappName: webview.webappName
118 property alias webappUrlPatterns: webview.webappUrlPatterns
119- property alias popupRedirectionUrlPrefix: webview.popupRedirectionUrlPrefix
120+ property alias popupRedirectionUrlPrefixPattern: webview.popupRedirectionUrlPrefixPattern
121 property alias webviewOverrideFile: webview.webviewOverrideFile
122 property string localUserAgentOverride: ""
123+ property alias blockOpenExternalUrls: webview.blockOpenExternalUrls
124
125 property bool backForwardButtonsVisible: false
126 property bool chromeVisible: false
127@@ -69,10 +70,12 @@
128 }
129
130 Item {
131+ id: webviewContainer
132 anchors.fill: parent
133
134 WebappContainerWebview {
135 id: webview
136+ objectName: "webview"
137
138 anchors {
139 left: parent.left
140@@ -179,15 +182,4 @@
141 actionsContext: actionManager.globalContext
142 model: UnityWebApps.UnityWebappsAppModel { searchPath: webappModelSearchPath }
143 }
144-
145- function isValidContainedUrl(url) {
146- if (!url || url.length === 0 || url === 'about:blank') {
147- return false
148- }
149- if (popupRedirectionUrlPrefix.length !== 0
150- && url.indexOf(popupRedirectionUrlPrefix) === 0) {
151- return false
152- }
153- return true
154- }
155 }
156
157=== modified file 'src/app/webcontainer/WebViewImplOxide.qml'
158--- src/app/webcontainer/WebViewImplOxide.qml 2014-08-19 08:42:30 +0000
159+++ src/app/webcontainer/WebViewImplOxide.qml 2014-10-20 22:12:22 +0000
160@@ -33,7 +33,16 @@
161 property string webappName: ""
162 property string localUserAgentOverride: ""
163 property var webappUrlPatterns: null
164- property string popupRedirectionUrlPrefix: ""
165+ property string popupRedirectionUrlPrefixPattern: ""
166+
167+ // Mostly used for testing & avoid external urls to
168+ // "leak" in the default browser
169+ property bool blockOpenExternalUrls: false
170+
171+ // Those signals are used for testing purposes to externally
172+ // track down the various internal logic & steps of a popup lifecycle.
173+ signal openExternalUrlTriggered(string url)
174+ signal gotRedirectionUrl(string url)
175
176 currentWebview: webview
177
178@@ -48,6 +57,9 @@
179 }
180 }
181
182+ StateSaver.properties: "url"
183+ StateSaver.enabled: true
184+
185 function shouldOpenPopupsInDefaultBrowser() {
186 return formFactor !== "desktop";
187 }
188@@ -70,6 +82,13 @@
189 disposition === Oxide.NavigationRequest.DispositionNewForegroundTab;
190 }
191
192+ function openUrlExternally(url) {
193+ webview.openExternalUrlTriggered(url)
194+ if (! webview.blockOpenExternalUrls) {
195+ Qt.openUrlExternally(url)
196+ }
197+ }
198+
199 function shouldAllowNavigationTo(url) {
200 // The list of url patterns defined by the webapp takes precedence over command line
201 if (isRunningAsANamedWebapp()) {
202@@ -113,36 +132,31 @@
203 return
204 }
205
206+ var redirectionPatternMatch = url.match(popupRedirectionUrlPrefixPattern);
207 var isRedirectionUrl =
208- popupRedirectionUrlPrefix.length !== 0
209- && url.indexOf(popupRedirectionUrlPrefix) === 0;
210-
211+ popupRedirectionUrlPrefixPattern
212+ && redirectionPatternMatch
213+ && redirectionPatternMatch.length >= 2;
214 var targetUrl = url;
215 if (isRedirectionUrl) {
216- // Extract the target URL.
217- targetUrl = url.slice(popupRedirectionUrlPrefix.length);
218- // Quick fix for http://pad.lv/1358622 (trim trailing parameters).
219- // A proper solution would probably involve regexps instead of a
220- // simple redirection prefix.
221- var extraParams = targetUrl.indexOf("&");
222- if (extraParams !== -1) {
223- targetUrl = targetUrl.slice(0, extraParams);
224- }
225- // Decode it.
226- targetUrl = decodeURIComponent(targetUrl);
227+ // Assume that the first group is the matching one
228+ targetUrl = redirectionPatternMatch[1];
229+ console.debug("Got a redirection URL with target URL: " + targetUrl)
230+ targetUrl = decodeURIComponent(targetUrl)
231+ gotRedirectionUrl(targetUrl)
232 }
233
234 if (webview.shouldAllowNavigationTo(targetUrl)) {
235 console.debug('Redirecting popup browsing ' + targetUrl + ' in the current container window.')
236 request.action = Oxide.NavigationRequest.ActionReject
237- webappContainerHelper.browseToUrlRequested(webview, url.slice(url.indexOf(popupRedirectionUrlPrefix)))
238+ webappContainerHelper.browseToUrlRequested(webview, targetUrl)
239 return
240 }
241
242 if (shouldOpenPopupsInDefaultBrowser()) {
243 console.debug('Opening popup window ' + targetUrl + ' in the browser window.')
244 request.action = Oxide.NavigationRequest.ActionReject
245- Qt.openUrlExternally(targetUrl)
246+ openUrlExternally(targetUrl)
247 return;
248 }
249 return
250@@ -179,7 +193,7 @@
251
252 if (request.action === Oxide.NavigationRequest.ActionReject) {
253 console.debug('Opening: ' + url + ' in the browser window.')
254- Qt.openUrlExternally(url)
255+ openUrlExternally(url)
256 }
257 }
258
259@@ -203,7 +217,7 @@
260 if ( ! isNewForegroundWebViewDisposition(request.disposition) &&
261 ! webview.shouldAllowNavigationTo(url)) {
262 request.action = Oxide.NavigationRequest.ActionReject
263- Qt.openUrlExternally(url);
264+ openUrlExternally(url);
265 popup.close()
266 return;
267 }
268@@ -233,7 +247,7 @@
269 return;
270
271 if (_url != 'about:blank' && ! webview.shouldAllowNavigationTo(_url)) {
272- Qt.openUrlExternally(_url);
273+ openUrlExternally(_url);
274 popup.close()
275 }
276 }
277
278=== modified file 'src/app/webcontainer/WebViewImplWebkit.qml'
279--- src/app/webcontainer/WebViewImplWebkit.qml 2014-07-29 21:51:07 +0000
280+++ src/app/webcontainer/WebViewImplWebkit.qml 2014-10-20 22:12:22 +0000
281@@ -34,7 +34,7 @@
282 property string webappName: ""
283 property var webappUrlPatterns: null
284 property string localUserAgentOverride: ""
285- property string popupRedirectionUrlPrefix: ""
286+ property string popupRedirectionUrlPrefixPattern: ""
287
288 function getUAString() {
289 return webview.localUserAgentOverride.length === 0 ? undefined : webview.localUserAgentOverride
290@@ -53,6 +53,9 @@
291 }
292 }
293
294+ StateSaver.properties: "url"
295+ StateSaver.enabled: true
296+
297 property bool lastLoadFailed: false
298 onLoadingChanged: {
299 lastLoadFailed = (loadRequest.status === WebView.LoadFailedStatus)
300
301=== modified file 'src/app/webcontainer/WebappContainerWebview.qml'
302--- src/app/webcontainer/WebappContainerWebview.qml 2014-09-02 06:29:12 +0000
303+++ src/app/webcontainer/WebappContainerWebview.qml 2014-10-20 22:12:22 +0000
304@@ -33,11 +33,13 @@
305 property var currentWebview: webappContainerWebViewLoader.item
306 property var webappUrlPatterns
307 property string localUserAgentOverride: ""
308- property string popupRedirectionUrlPrefix: ""
309+ property string popupRedirectionUrlPrefixPattern: ""
310 property url webviewOverrideFile: ""
311+ property bool blockOpenExternalUrls: false
312
313 Loader {
314 id: webappContainerWebViewLoader
315+ objectName: "containerWebviewLoader"
316 anchors.fill: parent
317 asynchronous: true
318 }
319@@ -62,7 +64,8 @@
320 , webappName: containerWebview.webappName
321 , webappUrlPatterns: containerWebview.webappUrlPatterns
322 , developerExtrasEnabled: containerWebview.developerExtrasEnabled
323- , popupRedirectionUrlPrefix: containerWebview.popupRedirectionUrlPrefix})
324+ , popupRedirectionUrlPrefixPattern: containerWebview.popupRedirectionUrlPrefixPattern
325+ , blockOpenExternalUrls: containerWebview.blockOpenExternalUrls})
326 }
327 }
328
329
330=== modified file 'src/app/webcontainer/url-pattern-utils.cpp'
331--- src/app/webcontainer/url-pattern-utils.cpp 2014-09-05 20:14:53 +0000
332+++ src/app/webcontainer/url-pattern-utils.cpp 2014-10-20 22:12:22 +0000
333@@ -21,6 +21,8 @@
334 #include <QtCore/QRegularExpression>
335 #include <QDebug>
336
337+namespace
338+{
339
340 /**
341 * Tests for the validity of a given webapp url pattern. It follows
342@@ -35,7 +37,7 @@
343 * @param pattern pattern that is to be tested for validity
344 * @return true if the url is valid, false otherwise
345 */
346-static bool isValidWebappUrlPattern(const QString& pattern)
347+bool isValidWebappUrlPattern(const QString& pattern)
348 {
349 static QRegularExpression grammar("^http(s|s\\?)?://[^\\.]+\\.[^\\.\\*\\?]+\\.[^\\.\\*\\?]+(\\.[^\\.\\*\\?/]+)*/.*$");
350 return grammar.match(pattern).hasMatch();
351@@ -71,7 +73,7 @@
352 * @param pattern pattern that is to be tested for validity
353 * @return true if the url is valid, false otherwise
354 */
355-static bool isValidGoogleUrlPattern(const QString& pattern)
356+bool isValidGoogleUrlPattern(const QString& pattern)
357 {
358 static QRegularExpression grammar("^http(s|s\\?)?://[^\\.\\?\\*]+\\.google\\.[^\\.\\?]+/.*$");
359 return grammar.match(pattern).hasMatch();
360@@ -83,14 +85,31 @@
361 * @param pattern pattern that is to be tested for validity
362 * @return true if the url is valid, false otherwise
363 */
364-static bool isValidStrictUrlPattern(const QString& pattern)
365+bool isValidStrictUrlPattern(const QString& pattern)
366 {
367 static QRegularExpression grammar("^http(s|s\\?)?://[^\\.\\*\\?]+\\.[^\\.\\*\\?]+(\\.[^\\.\\*\\?/]+)*/.*$");
368 return grammar.match(pattern).hasMatch();
369 }
370
371
372-QString UrlPatternUtils::transformWebappSearchPatternToSafePattern(const QString& pattern)
373+QString toSafeHostnamePartPattern(const QString& hostnamePart)
374+{
375+ QString localHostnamePart = hostnamePart;
376+ return localHostnamePart.replace("*", "[^\\./]*");
377+}
378+
379+QString toSafeUrlPathPartPattern(const QString& urlPathPart)
380+{
381+ QString localUrlPathPart = urlPathPart;
382+ return localUrlPathPart.replace("*", "[^\\s]*");
383+}
384+
385+} // namespace {
386+
387+
388+QString UrlPatternUtils::transformWebappSearchPatternToSafePattern(
389+ const QString& pattern,
390+ bool doTransformUrlPath)
391 {
392 QString transformedPattern;
393
394@@ -112,8 +131,10 @@
395 // matches
396 // https?://*.ebay.com/*
397 QString scheme = match.captured(1);
398- QString hostname = match.captured(2).replace("*", "[^\\./]*");
399- QString tail = match.captured(3).replace("*", "[^\\s]*");
400+ QString hostname = toSafeHostnamePartPattern(match.captured(2));
401+ QString tail = doTransformUrlPath ?
402+ toSafeUrlPathPartPattern(match.captured(3))
403+ : match.captured(3);
404
405 // reconstruct
406 transformedPattern = QString("%1%2%3").arg(scheme).arg(hostname).arg(tail);
407@@ -128,7 +149,7 @@
408 QString scheme = match.captured(1);
409 QString hostname = match.captured(2);
410 QString tld = match.captured(3).replace("*", "[^\\./]*");
411- QString tail = match.captured(4).replace("*", "[^\\s]*");
412+ QString tail = toSafeUrlPathPartPattern(match.captured(4));
413
414 // reconstruct
415 transformedPattern = QString("%1%2%3%4")
416
417=== modified file 'src/app/webcontainer/url-pattern-utils.h'
418--- src/app/webcontainer/url-pattern-utils.h 2014-04-01 18:45:08 +0000
419+++ src/app/webcontainer/url-pattern-utils.h 2014-10-20 22:12:22 +0000
420@@ -25,7 +25,8 @@
421
422 namespace UrlPatternUtils {
423
424-QString transformWebappSearchPatternToSafePattern(const QString&);
425+QString transformWebappSearchPatternToSafePattern(const QString&
426+ , bool doTransformUrlPath = true);
427
428 QStringList filterAndTransformUrlPatterns(const QStringList & includePatterns);
429
430
431=== modified file 'src/app/webcontainer/webapp-container.cpp'
432--- src/app/webcontainer/webapp-container.cpp 2014-10-03 14:41:14 +0000
433+++ src/app/webcontainer/webapp-container.cpp 2014-10-20 22:12:22 +0000
434@@ -158,8 +158,15 @@
435
436 context->setContextProperty("webappContainerHelper", m_webappContainerHelper.data());
437
438- if ( ! m_popupRedirectionUrlPrefix.isEmpty()) {
439- m_window->setProperty("popupRedirectionUrlPrefix", m_popupRedirectionUrlPrefix);
440+ if ( ! m_popupRedirectionUrlPrefixPattern.isEmpty()) {
441+ const QString WEBAPP_CONTAINER_DO_NOT_FILTER_PATTERN_URL_ENV_VAR =
442+ qgetenv("WEBAPP_CONTAINER_DO_NOT_FILTER_PATTERN_URL");
443+ m_window->setProperty(
444+ "popupRedirectionUrlPrefixPattern",
445+ WEBAPP_CONTAINER_DO_NOT_FILTER_PATTERN_URL_ENV_VAR == "1"
446+ ? m_popupRedirectionUrlPrefixPattern
447+ : UrlPatternUtils::transformWebappSearchPatternToSafePattern(
448+ m_popupRedirectionUrlPrefixPattern, false));
449 }
450
451 if (!m_userAgentOverride.isEmpty()) {
452@@ -172,16 +179,20 @@
453 m_window->setProperty("webviewOverrideFile", QUrl::fromLocalFile(overrideFile.absoluteFilePath()));
454 }
455
456- // When a webapp is being launched by name, the URL is pulled from its 'homepage'.
457- if (m_webappName.isEmpty()) {
458- QList<QUrl> urls = this->urls();
459- if (!urls.isEmpty()) {
460- m_window->setProperty("url", urls.last());
461- } else if (m_webappModelSearchPath.isEmpty()) {
462- return false;
463- }
464- // Otherwise, assume that the homepage will come from a locally defined
465- // webapp-properties.json file pulled from the webapp model element.
466+ const QString WEBAPP_CONTAINER_BLOCK_OPEN_URL_EXTERNALLY_ENV_VAR =
467+ qgetenv("WEBAPP_CONTAINER_BLOCK_OPEN_URL_EXTERNALLY");
468+ if (WEBAPP_CONTAINER_BLOCK_OPEN_URL_EXTERNALLY_ENV_VAR == "1") {
469+ m_window->setProperty("blockOpenExternalUrls", true);
470+ }
471+
472+ QList<QUrl> urls = this->urls();
473+ if (!urls.isEmpty()) {
474+ m_window->setProperty("url", urls.last());
475+ } else if (m_webappModelSearchPath.isEmpty()) {
476+ // Either we have a command line argument for the start URL or we have
477+ // local search path for a webapp definition (that would include in its
478+ // meta data a homepage). Any other case is faulty.
479+ return false;
480 }
481
482 m_component->completeCreate();
483@@ -278,7 +289,7 @@
484 } else if (argument == "--local-webapp-manifest") {
485 m_localWebappManifest = true;
486 } else if (argument.startsWith("--popup-redirection-url-prefix=")) {
487- m_popupRedirectionUrlPrefix = argument.split("--popup-redirection-url-prefix=")[1];
488+ m_popupRedirectionUrlPrefixPattern = argument.split("--popup-redirection-url-prefix=")[1];
489 } else if (argument.startsWith("--local-cookie-db-path=")) {
490 m_localCookieStoreDbPath = argument.split("--local-cookie-db-path=")[1];
491 } else if (argument.startsWith("--user-agent-string=")) {
492
493=== modified file 'src/app/webcontainer/webapp-container.h'
494--- src/app/webcontainer/webapp-container.h 2014-09-25 20:36:59 +0000
495+++ src/app/webcontainer/webapp-container.h 2014-10-20 22:12:22 +0000
496@@ -56,7 +56,7 @@
497 bool m_backForwardButtonsVisible;
498 bool m_addressBarVisible;
499 bool m_localWebappManifest;
500- QString m_popupRedirectionUrlPrefix;
501+ QString m_popupRedirectionUrlPrefixPattern;
502 QString m_localCookieStoreDbPath;
503 QString m_userAgentOverride;
504 QScopedPointer<WebappContainerHelper> m_webappContainerHelper;
505
506=== modified file 'src/app/webcontainer/webapp-container.qml'
507--- src/app/webcontainer/webapp-container.qml 2014-10-08 09:23:14 +0000
508+++ src/app/webcontainer/webapp-container.qml 2014-10-20 22:12:22 +0000
509@@ -39,10 +39,11 @@
510 property var webappUrlPatterns
511 property bool oxide: false
512 property string accountProvider: ""
513- property string popupRedirectionUrlPrefix: ""
514+ property string popupRedirectionUrlPrefixPattern: ""
515 property url webviewOverrideFile: ""
516 property var __webappCookieStore: null
517 property string localUserAgentOverride: ""
518+ property bool blockOpenExternalUrls: false
519
520 contentOrientation: Screen.orientation
521
522@@ -77,10 +78,10 @@
523 oxide: root.oxide
524 webappModelSearchPath: root.webappModelSearchPath
525 webappUrlPatterns: root.webappUrlPatterns
526+ blockOpenExternalUrls: root.blockOpenExternalUrls
527
528 localUserAgentOverride: root.localUserAgentOverride
529-
530- popupRedirectionUrlPrefix: root.popupRedirectionUrlPrefix
531+ popupRedirectionUrlPrefixPattern: root.popupRedirectionUrlPrefixPattern
532 webviewOverrideFile: root.webviewOverrideFile
533
534 anchors.fill: parent
535@@ -107,7 +108,7 @@
536 searchPath: root.webappModelSearchPath
537
538 onModelContentChanged: {
539- if (root.webappName) {
540+ if (root.webappName && root.url.length === 0) {
541 var idx = webappModel.getWebappIndex(root.webappName)
542 root.url = webappModel.data(idx, UnityWebApps.UnityWebappsAppModel.Homepage)
543 }
544@@ -185,8 +186,22 @@
545 browser.visible = true;
546 if (browser.currentWebview) {
547 browser.currentWebview.visible = true;
548- browser.currentWebview.url = root.url
549- browser.webappName = root.webappName
550+ browser.webappName = root.webappName;
551+
552+ // As we use StateSaver to restore the URL, we need to check first if
553+ // it has not been set previously before setting the URL to the default property
554+ // homepage.
555+ var current_url = browser.currentWebview.url.toString();
556+ if (!current_url || current_url.length === 0) {
557+ browser.currentWebview.url = root.url;
558+ }
559+ }
560+ }
561+
562+ function updateBrowserUrl(url) {
563+ root.url = url;
564+ if (browser.currentWebview) {
565+ browser.currentWebview.url = url;
566 }
567 }
568
569@@ -205,11 +220,11 @@
570 }
571 var requestedUrl = uris[0].toString();
572
573- if (popupRedirectionUrlPrefix.length !== 0
574- && requestedUrl.indexOf(popupRedirectionUrlPrefix) === 0) {
575+ if (popupRedirectionUrlPrefixPattern.length !== 0
576+ && requestedUrl.match(popupRedirectionUrlPrefixPattern)) {
577 return;
578 }
579- browser.currentWebview.url = requestedUrl;
580+ updateBrowserUrl(requestedUrl);
581 }
582 }
583 }
584
585=== modified file 'tests/autopilot/webapp_container/tests/__init__.py'
586--- tests/autopilot/webapp_container/tests/__init__.py 2014-07-17 11:08:58 +0000
587+++ tests/autopilot/webapp_container/tests/__init__.py 2014-10-20 22:12:22 +0000
588@@ -20,6 +20,8 @@
589
590 from autopilot.testcase import AutopilotTestCase
591 from autopilot.platform import model
592+from testtools.matchers import Equals
593+from autopilot.matchers import Eventually
594
595 from ubuntuuitoolkit import emulators as toolkit_emulators
596 from webapp_container.tests import fake_servers
597@@ -38,16 +40,24 @@
598
599
600 class WebappContainerTestCaseBase(AutopilotTestCase):
601+ def setUp(self):
602+ self.pointing_device = toolkit_emulators.get_pointing_device()
603+ super(WebappContainerTestCaseBase, self).setUp()
604+
605 def get_webcontainer_app_path(self):
606 if os.path.exists(LOCAL_BROWSER_CONTAINER_PATH_NAME):
607 return LOCAL_BROWSER_CONTAINER_PATH_NAME
608 return INSTALLED_BROWSER_CONTAINER_PATH_NAME
609
610- def launch_webcontainer_app(self, args):
611+ def launch_webcontainer_app(self, args, envvars={}):
612 if model() != 'Desktop':
613 args.append(
614 '--desktop_file_hint=/usr/share/applications/'
615 'webbrowser-app.desktop')
616+ if envvars:
617+ for envvar_key in envvars:
618+ self.patch_environment(envvar_key, envvars[envvar_key])
619+
620 try:
621 self.app = self.launch_test_application(
622 self.get_webcontainer_app_path(),
623@@ -68,15 +78,43 @@
624 def get_webcontainer_chrome(self):
625 return self.app.select_single("Chrome")
626
627+ def get_webview(self):
628+ return self.app.select_single(objectName="webview")
629+
630+ def get_oxide_webview(self):
631+ container = self.get_webview().select_single(
632+ objectName='containerWebviewLoader')
633+ return container.select_single('WebViewImplOxide')
634+
635+ def assert_page_eventually_loaded(self, url):
636+ webview = self.get_oxide_webview()
637+ self.assertThat(webview.url, Eventually(Equals(url)))
638+ # loadProgress == 100 ensures that a page has actually loaded
639+ self.assertThat(webview.loadProgress,
640+ Eventually(Equals(100), timeout=20))
641+ self.assertThat(webview.loading, Eventually(Equals(False)))
642+
643+ def browse_to(self, url):
644+ webview = self.get_oxide_webview()
645+ webview.url = url
646+ self.assert_page_eventually_loaded(url)
647+
648
649 class WebappContainerTestCaseWithLocalContentBase(WebappContainerTestCaseBase):
650+ BASE_URL_SCHEME = 'http://'
651+
652 def setUp(self):
653 super(WebappContainerTestCaseWithLocalContentBase, self).setUp()
654 self.http_server = fake_servers.WebappContainerContentHttpServer()
655 self.addCleanup(self.http_server.shutdown)
656- self.base_url = "http://localhost:{}".format(self.http_server.port)
657-
658- def launch_webcontainer_app_with_local_http_server(self, args, path='/'):
659+ self.base_url = "{}localhost:{}".format(
660+ self.BASE_URL_SCHEME, self.http_server.port)
661+
662+ def get_base_url_hostname(self):
663+ return self.base_url[len(self.BASE_URL_SCHEME):]
664+
665+ def launch_webcontainer_app_with_local_http_server(
666+ self, args, path='/', envvars={}):
667 self.url = self.base_url + path
668 args.append(self.url)
669- self.launch_webcontainer_app(args)
670+ self.launch_webcontainer_app(args, envvars)
671
672=== modified file 'tests/autopilot/webapp_container/tests/fake_servers.py'
673--- tests/autopilot/webapp_container/tests/fake_servers.py 2014-04-24 10:50:42 +0000
674+++ tests/autopilot/webapp_container/tests/fake_servers.py 2014-10-20 22:12:22 +0000
675@@ -26,14 +26,28 @@
676 self.end_headers()
677 self.wfile.write(content.encode())
678
679- def basic_html_content(self):
680- return """
681-<html>
682-<head>
683-<title>Some content</title>
684-</head>
685-<body>
686-This is some content
687+ def basic_html_content(self, content="basic"):
688+ return """
689+<html>
690+<head>
691+<title>Some content</title>
692+</head>
693+<body>
694+This is some {} content
695+</body>
696+</html>
697+ """.format(content)
698+
699+ def redirect_html_content(self):
700+ return """
701+<html>
702+<head>
703+<title>Some content</title>
704+</head>
705+<body>
706+<div><a href='/redirect?url=myredirect&s=1&r=2' target='_blank'>
707+<div style="height: 100%; width: 100%"></div>
708+</a></div>
709 </body>
710 </html>
711 """
712@@ -42,6 +56,12 @@
713 if self.path == '/':
714 self.send_response(200)
715 self.serve_content(self.basic_html_content())
716+ elif self.path == '/other':
717+ self.send_response(200)
718+ self.serve_content(self.basic_html_content("other"))
719+ elif self.path == '/get-redirect':
720+ self.send_response(200)
721+ self.serve_content(self.redirect_html_content())
722 else:
723 self.send_error(404)
724
725
726=== modified file 'tests/autopilot/webapp_container/tests/test_app_launch.py'
727--- tests/autopilot/webapp_container/tests/test_app_launch.py 2014-07-17 11:08:58 +0000
728+++ tests/autopilot/webapp_container/tests/test_app_launch.py 2014-10-20 22:12:22 +0000
729@@ -23,7 +23,7 @@
730 WebappContainerTestCaseWithLocalContentBase):
731
732 def test_container_does_not_load_with_no_webapp_name_and_url(self):
733- args = ['--webapp']
734+ args = []
735 self.launch_webcontainer_app(args)
736 self.assertIsNone(self.get_webcontainer_proxy())
737
738
739=== added file 'tests/autopilot/webapp_container/tests/test_redirection_pattern.py'
740--- tests/autopilot/webapp_container/tests/test_redirection_pattern.py 1970-01-01 00:00:00 +0000
741+++ tests/autopilot/webapp_container/tests/test_redirection_pattern.py 2014-10-20 22:12:22 +0000
742@@ -0,0 +1,59 @@
743+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
744+# Copyright 2014 Canonical
745+#
746+# This program is free software: you can redistribute it and/or modify it
747+# under the terms of the GNU General Public License version 3, as published
748+# by the Free Software Foundation.
749+#
750+# This program is distributed in the hope that it will be useful,
751+# but WITHOUT ANY WARRANTY; without even the implied warranty of
752+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
753+# GNU General Public License for more details.
754+#
755+# You should have received a copy of the GNU General Public License
756+# along with this program. If not, see <http://www.gnu.org/licenses/>.
757+
758+from testtools.matchers import Equals
759+from autopilot.matchers import Eventually
760+
761+from webapp_container.tests import WebappContainerTestCaseWithLocalContentBase
762+
763+
764+class WebappContainerRedirectionPatternTestCase(
765+ WebappContainerTestCaseWithLocalContentBase):
766+
767+ def test_browse_to_redirection_pattern_url(self):
768+ REDIRECTION_HOSTNAME = self.get_base_url_hostname()
769+ args = ["--popup-redirection-url-prefix={}{}{}".format(
770+ 'http://', REDIRECTION_HOSTNAME.replace('.', '\.'),
771+ '/redirect\\?url=([^&]*).*')]
772+ self.launch_webcontainer_app_with_local_http_server(
773+ args,
774+ '/get-redirect',
775+ {'WEBAPP_CONTAINER_BLOCK_OPEN_URL_EXTERNALLY': '1',
776+ 'WEBAPP_CONTAINER_DO_NOT_FILTER_PATTERN_URL': '1'})
777+ self.get_webcontainer_window().visible.wait_for(True)
778+
779+ webview = self.get_oxide_webview()
780+ external_open_watcher = webview.watch_signal(
781+ 'openExternalUrlTriggered(QString)')
782+ got_redirection_url_watcher = webview.watch_signal(
783+ 'gotRedirectionUrl(QString)')
784+
785+ self.assertThat(external_open_watcher.was_emitted, Equals(False))
786+ self.assertThat(got_redirection_url_watcher.was_emitted, Equals(False))
787+ self.browse_to(
788+ "http://{}/get-redirect".format(REDIRECTION_HOSTNAME))
789+
790+ self.pointing_device.click_object(webview)
791+
792+ self.assertThat(
793+ lambda: got_redirection_url_watcher.was_emitted,
794+ Eventually(Equals(True)))
795+ self.assertThat(
796+ webview.get_signal_emissions(
797+ 'gotRedirectionUrl(QString)')[0][0],
798+ Equals('myredirect'))
799+ self.assertThat(
800+ lambda: external_open_watcher.was_emitted,
801+ Eventually(Equals(True)))
802
803=== modified file 'tests/unittests/container-url-patterns/tst_ContainerUrlPatternsTests.cpp'
804--- tests/unittests/container-url-patterns/tst_ContainerUrlPatternsTests.cpp 2014-09-05 20:14:53 +0000
805+++ tests/unittests/container-url-patterns/tst_ContainerUrlPatternsTests.cpp 2014-10-20 22:12:22 +0000
806@@ -33,25 +33,32 @@
807 {
808 QTest::addColumn<QString>("pattern");
809 QTest::addColumn<QString>("transformedPattern");
810+ QTest::addColumn<bool>("doTransformUrlPath");
811
812 // regular patterns
813
814 QTest::newRow("Valid pattern")
815 << "https?://*.mydomain.com/*"
816- << "https?://[^\\./]*.mydomain.com/[^\\s]*";
817+ << "https?://[^\\./]*.mydomain.com/[^\\s]*"
818+ << true;
819+
820+ QTest::newRow("Valid pattern with no tail replacement")
821+ << "https?://*.mydomain.com/l.php\\?\\w+=([^&]+).*"
822+ << "https?://[^\\./]*.mydomain.com/l.php\\?\\w+=([^&]+).*"
823+ << false;
824
825 QTest::newRow("Valid pattern - short url")
826 << "https?://mydomain.com/*"
827- << "https?://mydomain.com/[^\\s]*";
828+ << "https?://mydomain.com/[^\\s]*" << true;
829
830 QTest::newRow("Valid pattern - strict url")
831 << "https?://www.mydomain.com/*"
832- << "https?://www.mydomain.com/[^\\s]*";
833+ << "https?://www.mydomain.com/[^\\s]*" << true;
834
835 #define WEBAPP_INVALID_URL_PATTERN_TEST(id,invalid_url_pattern) \
836 QTest::newRow("Invalid pattern " #id) \
837 << invalid_url_pattern \
838- << QString()
839+ << QString() << true
840
841 WEBAPP_INVALID_URL_PATTERN_TEST(1, "http");
842 WEBAPP_INVALID_URL_PATTERN_TEST(2, "://");
843@@ -74,16 +81,16 @@
844
845 QTest::newRow("Valid Google pattern")
846 << "https?://mail.google.*/*"
847- << "https?://mail.google.[^\\./]*/[^\\s]*";
848+ << "https?://mail.google.[^\\./]*/[^\\s]*" << true;
849
850 QTest::newRow("Valid non Google pattern")
851 << "https://*.google.com/*"
852- << "https://[^\\./]*.google.com/[^\\s]*";
853+ << "https://[^\\./]*.google.com/[^\\s]*" << true;
854
855 #define WEBAPP_INVALID_GOOGLE_URL_PATTERN_TEST(id,invalid_google_url_pattern) \
856 QTest::newRow("Invalid Google App pattern " #id) \
857 << invalid_google_url_pattern \
858- << QString()
859+ << QString() << true
860
861 WEBAPP_INVALID_GOOGLE_URL_PATTERN_TEST(1, "https://*.google.*/*");
862 WEBAPP_INVALID_GOOGLE_URL_PATTERN_TEST(2, "https://service.gooo*gle.com/*");
863@@ -99,7 +106,8 @@
864 {
865 QFETCH(QString, pattern);
866 QFETCH(QString, transformedPattern);
867- QCOMPARE(UrlPatternUtils::transformWebappSearchPatternToSafePattern(pattern), transformedPattern);
868+ QFETCH(bool, doTransformUrlPath);
869+ QCOMPARE(UrlPatternUtils::transformWebappSearchPatternToSafePattern(pattern, doTransformUrlPath), transformedPattern);
870 }
871
872 void filteredUrlPatterns_data()

Subscribers

People subscribed via source and target branches

to status/vote changes: