Merge lp:~abreu-alexandre/webbrowser-app/add-scheme-filter-handler into lp:webbrowser-app

Proposed by Alexandre Abreu
Status: Merged
Approved by: Alexandre Abreu
Approved revision: 1146
Merged at revision: 1184
Proposed branch: lp:~abreu-alexandre/webbrowser-app/add-scheme-filter-handler
Merge into: lp:webbrowser-app
Diff against target: 1139 lines (+440/-334)
12 files modified
src/app/webcontainer/CMakeLists.txt (+2/-1)
src/app/webcontainer/intent-parser.cpp (+86/-0)
src/app/webcontainer/intent-parser.h (+51/-0)
src/app/webcontainer/scheme-filter.cpp (+148/-169)
src/app/webcontainer/scheme-filter.h (+23/-70)
src/app/webcontainer/webapp-container.cpp (+24/-21)
src/app/webcontainer/webapp-container.h (+4/-4)
src/app/webcontainer/webapp-container.qml (+25/-26)
tests/autopilot/webapp_container/tests/__init__.py (+4/-4)
tests/autopilot/webapp_container/tests/test_scheme_filter.py (+59/-16)
tests/unittests/intent-filter/CMakeLists.txt (+2/-1)
tests/unittests/intent-filter/tst_IntentFilterTests.cpp (+12/-22)
To merge this branch: bzr merge lp:~abreu-alexandre/webbrowser-app/add-scheme-filter-handler
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Olivier Tilloy Approve
David Barth (community) Needs Fixing
Review via email: mp+265265@code.launchpad.net

Commit message

Add a general URI reformatting mechanism for webapp specific handled schemes.

Description of the change

Add a general URI reformatting mechanism for webapp specific handled schemes.

To post a comment you must log in.
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 :

Please revert the changes to webbrowser-app.pot.

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

done

Revision history for this message
David Barth (dbarth) wrote :

in webapp-container.qml around tests for matchHostname.length and matchScheme.length you should add a guard to check that matchHostname and matchScheme do exist first.

review: Needs Fixing
Revision history for this message
David Barth (dbarth) wrote :

Also, some debug log for when the filter file can't be loaded would be nice

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1114. By Launchpad Translations on behalf of phablet-team

Launchpad automatic translations update.

1115. By Launchpad Translations on behalf of phablet-team

Launchpad automatic translations update.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1116. By Launchpad Translations on behalf of phablet-team

Launchpad automatic translations update.

1117. By Launchpad Translations on behalf of phablet-team

Launchpad automatic translations update.

1118. By Steve Langasek

Add missing changelog entry due to direct upload.

1119. By Launchpad Translations on behalf of phablet-team

Launchpad automatic translations update.

1120. By Olivier Tilloy

Update all imports of:
 - Ubuntu.Components to 1.3
 - QtQuick to 2.4
 - QtQuick.Window to 2.2

This bumps the required versions of qtdeclarative5-ubuntu-ui-toolkit-plugin, qml-module-qtquick2 and qml-module-qtquick-window2 in debian/control. Fixes: #1483279

1121. By CI Train Bot Account

Releasing 0.23+15.10.20150810-0ubuntu1

1122. By Olivier Tilloy

Implement the "Find in Page" feature.
This bumps the runtime dependency on liboxideqt-qmlplugin to 1.8. Fixes: #1312260
Approved by: Riccardo Padovani

1123. By Olivier Tilloy

Drop old names for QML dependencies.
Original patch by Robert Ancell.

1124. By Olivier Tilloy

Highlight matching terms in one pass. Fixes: #1481206
Approved by: PS Jenkins bot, Ugo Riboni

1125. By CI Train Bot Account

Releasing 0.23+15.10.20150811-0ubuntu1

1126. By Olivier Tilloy

Update translation template.

1127. By Launchpad Translations on behalf of phablet-team

Launchpad automatic translations update.

1128. By Arthur Mello

Wide screen versions of the history view and new tab view, per design specification.
This adds a build dependency on qml-module-qt-labs-settings (for unit tests). Fixes: #1351157, #1481647

1129. By CI Train Bot Account

Releasing 0.23+15.10.20150812.1-0ubuntu1

1130. By Olivier Tilloy

Update translation template.

1131. By Launchpad Translations on behalf of phablet-team

Launchpad automatic translations update.

1132. By Olivier Tilloy

Remove strong typing of the contextualActions and selectionActions properties.
This would cause issues if an app imported Ubuntu.Web along with Ubuntu.Components < 1.3 and overrode one of these properties, because the webview expected an ActionList 1.3, and would get an earlier version. Fixes: #1484437

1133. By CI Train Bot Account

Releasing 0.23+15.10.20150813.1-0ubuntu1

1134. By CI Train Bot Account

Resync trunk.

1135. By Ugo Riboni

Delay the exit from fullscreen mode until focus remains lost for a certain amount of time. Fixes: #1477308
Approved by: Olivier Tilloy

1136. By Ugo Riboni

Disable find in page when the new tab view is active. Fixes: #1483847
Approved by: Olivier Tilloy

1137. By CI Train Bot Account

Releasing 0.23+15.10.20150814-0ubuntu1

1138. By Launchpad Translations on behalf of phablet-team

Launchpad automatic translations update.

1139. By Launchpad Translations on behalf of phablet-team

Launchpad automatic translations update.

1140. By Launchpad Translations on behalf of phablet-team

Launchpad automatic translations update.

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

Docstrings in scheme-filter.h are outdated, and to be honest not very useful as they don’t contain any actual documentation. Can they be either updated, or removed?

On a related note, some minimal documentation at the class-level to explain the general purpose of the class and how it is used in conjunction with other constructs by the webapp container would be very helpful, especially for our future selves.

intent-parser.h has some unused includes (QObject, QVariantMap). The include for QUrl could be made a forward declaration.

intent-parser.cpp has some unused includes (QJSEngine, QJSValue).

The copyright notice for the two new files should add 2015 (it’s not new code, but those are new files).

In webapp-container.cpp, won’t the renaming of the default filename for the scheme filter (LOCAL_SCHEME_FILTER_FILENAME) break existing filters for already published apps?

In test_default_scheme_filter, shouldn’t the test filter use encodeURIComponent() instead of r.path.replace(…) ?

1141. By Colin Watson

Fix versioned dependencies on qtdeclarative5-ubuntu-ui-toolkit-plugin to allow qtdeclarative5-ubuntu-ui-toolkit-plugin-gles.
Approved by: Olivier Tilloy

1142. By Arthur Mello

Wait for OptionSelector's collapsing transition to finish Fixes: #1484175
Approved by: Olivier Tilloy

1143. By Arthur Mello

Make sure to set the historyModel to the HistoryView component when browser wide property changes Fixes: #1484555
Approved by: Olivier Tilloy

1144. By CI Train Bot Account

Releasing 0.23+15.10.20150817-0ubuntu1

1145. By Alexandre Abreu

Add a general URI reformatting mechanism for webapp specific handled schemes.

1146. By Alexandre Abreu

Fix test

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

> Docstrings in scheme-filter.h are outdated, and to be honest not very useful
> as they don’t contain any actual documentation. Can they be either updated, or
> removed?
>
> On a related note, some minimal documentation at the class-level to explain
> the general purpose of the class and how it is used in conjunction with other
> constructs by the webapp container would be very helpful, especially for our
> future selves.
>
> intent-parser.h has some unused includes (QObject, QVariantMap). The include
> for QUrl could be made a forward declaration.
>
> intent-parser.cpp has some unused includes (QJSEngine, QJSValue).
>
> The copyright notice for the two new files should add 2015 (it’s not new code,
> but those are new files).

> In test_default_scheme_filter, shouldn’t the test filter use
> encodeURIComponent() instead of r.path.replace(…) ?

all updated,

> In webapp-container.cpp, won’t the renaming of the default filename for the
> scheme filter (LOCAL_SCHEME_FILTER_FILENAME) break existing filters for
> already published apps?

Last time I looked no app uses a default filter for intents, the default one
does the work already,

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 :

Once you’ve confirmed that not a single application in the store currently ships a "local-intent-filter.js" file, this is good to go. Thanks, and sorry for the delay in reviewing.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

I checked again and no webapp uses a local-intent-filter.js

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 :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/app/webcontainer/CMakeLists.txt'
2--- src/app/webcontainer/CMakeLists.txt 2015-07-03 16:13:49 +0000
3+++ src/app/webcontainer/CMakeLists.txt 2015-08-20 17:55:29 +0000
4@@ -21,7 +21,8 @@
5 webapp-container-helper.cpp
6 session-utils.cpp
7 url-pattern-utils.cpp
8- intent-filter.cpp
9+ scheme-filter.cpp
10+ intent-parser.cpp
11 )
12
13 add_executable(${WEBAPP_CONTAINER} ${WEBAPP_CONTAINER_SRC})
14
15=== added file 'src/app/webcontainer/intent-parser.cpp'
16--- src/app/webcontainer/intent-parser.cpp 1970-01-01 00:00:00 +0000
17+++ src/app/webcontainer/intent-parser.cpp 2015-08-20 17:55:29 +0000
18@@ -0,0 +1,86 @@
19+/*
20+ * Copyright 2014-2015 Canonical Ltd.
21+ *
22+ * This file is part of webbrowser-app.
23+ *
24+ * webbrowser-app is free software; you can redistribute it and/or modify
25+ * it under the terms of the GNU General Public License as published by
26+ * the Free Software Foundation; version 3.
27+ *
28+ * webbrowser-app is distributed in the hope that it will be useful,
29+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
30+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31+ * GNU General Public License for more details.
32+ *
33+ * You should have received a copy of the GNU General Public License
34+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
35+ */
36+
37+#include "intent-parser.h"
38+
39+#include <QtCore/QRegularExpression>
40+#include <QUrl>
41+
42+
43+namespace {
44+
45+const char INTENT_SCHEME_STRING[] = "intent";
46+const char INTENT_START_FRAGMENT_TAG[] = "Intent";
47+const char INTENT_URI_PACKAGE_PREFIX[] = "package=";
48+const char INTENT_URI_ACTION_PREFIX[] = "action=";
49+const char INTENT_URI_CATEGORY_PREFIX[] = "category=";
50+const char INTENT_URI_COMPONENT_PREFIX[] = "component=";
51+const char INTENT_URI_SCHEME_PREFIX[] = "scheme=";
52+const char INTENT_END_FRAGMENT_TAG[] = ";end";
53+
54+void trimUriSeparator(QString& uriComponent)
55+{
56+ uriComponent.remove(QRegExp("^/*")).remove(QRegExp("/*$"));
57+}
58+
59+}
60+
61+IntentUriDescription
62+parseIntentUri(const QUrl& intentUri)
63+{
64+ IntentUriDescription result;
65+ if (intentUri.scheme() != INTENT_SCHEME_STRING
66+ || !intentUri.fragment().startsWith(INTENT_START_FRAGMENT_TAG)
67+ || !intentUri.fragment().endsWith(INTENT_END_FRAGMENT_TAG)) {
68+ return result;
69+ }
70+
71+ QString host = intentUri.host();
72+ trimUriSeparator(host);
73+
74+ QString path = intentUri.path();
75+
76+ if (intentUri.hasQuery()) {
77+ path += "?" + intentUri.query();
78+ trimUriSeparator(path);
79+ }
80+
81+ result.host = host;
82+ result.uriPath = path;
83+
84+ QStringList infos = intentUri.fragment().split(";");
85+ Q_FOREACH(const QString& info, infos) {
86+ if (info.startsWith(INTENT_URI_PACKAGE_PREFIX)) {
87+ result.package = info.split(INTENT_URI_PACKAGE_PREFIX)[1];
88+ }
89+ else if (info.startsWith(INTENT_URI_ACTION_PREFIX)) {
90+ result.action = info.split(INTENT_URI_ACTION_PREFIX)[1];
91+ }
92+ else if (info.startsWith(INTENT_URI_CATEGORY_PREFIX)) {
93+ result.category = info.split(INTENT_URI_CATEGORY_PREFIX)[1];
94+ }
95+ else if (info.startsWith(INTENT_URI_COMPONENT_PREFIX)) {
96+ result.component = info.split(INTENT_URI_COMPONENT_PREFIX)[1];
97+ }
98+ else if (info.startsWith(INTENT_URI_SCHEME_PREFIX)) {
99+ result.scheme = info.split(INTENT_URI_SCHEME_PREFIX)[1];
100+ }
101+ }
102+
103+ return result;
104+}
105
106=== added file 'src/app/webcontainer/intent-parser.h'
107--- src/app/webcontainer/intent-parser.h 1970-01-01 00:00:00 +0000
108+++ src/app/webcontainer/intent-parser.h 2015-08-20 17:55:29 +0000
109@@ -0,0 +1,51 @@
110+/*
111+ * Copyright 2014-2015 Canonical Ltd.
112+ *
113+ * This file is part of webbrowser-app.
114+ *
115+ * webbrowser-app is free software; you can redistribute it and/or modify
116+ * it under the terms of the GNU General Public License as published by
117+ * the Free Software Foundation; version 3.
118+ *
119+ * webbrowser-app is distributed in the hope that it will be useful,
120+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
121+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
122+ * GNU General Public License for more details.
123+ *
124+ * You should have received a copy of the GNU General Public License
125+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
126+ */
127+
128+#ifndef _INTENT_PARSER_H_
129+#define _INTENT_PARSER_H_
130+
131+#include <QString>
132+
133+
134+class QUrl;
135+
136+struct IntentUriDescription
137+{
138+ QString uriPath;
139+
140+ // optional
141+ QString host;
142+
143+ QString package;
144+ QString action;
145+ QString category;
146+ QString component;
147+ QString scheme;
148+};
149+
150+/**
151+ * @brief Parse a URI that is supposed to be an intent as defined here
152+ *
153+ * https://developer.chrome.com/multidevice/android/intents
154+ *
155+ * @param intentUri
156+ * @return
157+ */
158+IntentUriDescription parseIntentUri(const QUrl& intentUri);
159+
160+#endif // _INTENT_PARSER_H_
161
162=== renamed file 'src/app/webcontainer/intent-filter.cpp' => 'src/app/webcontainer/scheme-filter.cpp'
163--- src/app/webcontainer/intent-filter.cpp 2015-01-30 16:19:51 +0000
164+++ src/app/webcontainer/scheme-filter.cpp 2015-08-20 17:55:29 +0000
165@@ -16,35 +16,24 @@
166 * along with this program. If not, see <http://www.gnu.org/licenses/>.
167 */
168
169-#include "intent-filter.h"
170+#include "scheme-filter.h"
171
172 #include <QtCore/QRegularExpression>
173 #include <QDebug>
174 #include <QFile>
175 #include <QJSEngine>
176 #include <QJSValue>
177+#include <QJsonArray>
178+#include <QJsonDocument>
179+#include <QJsonObject>
180 #include <QUrl>
181
182-
183-namespace {
184-
185-const char INTENT_SCHEME_STRING[] = "intent";
186-const char INTENT_START_FRAGMENT_TAG[] = "Intent";
187-const char INTENT_URI_PACKAGE_PREFIX[] = "package=";
188-const char INTENT_URI_ACTION_PREFIX[] = "action=";
189-const char INTENT_URI_CATEGORY_PREFIX[] = "category=";
190-const char INTENT_URI_COMPONENT_PREFIX[] = "component=";
191-const char INTENT_URI_SCHEME_PREFIX[] = "scheme=";
192-const char INTENT_END_FRAGMENT_TAG[] = ";end";
193-
194-void trimUriSeparator(QString& uriComponent)
195-{
196- uriComponent.remove(QRegExp("^/*")).remove(QRegExp("/*$"));
197-}
198-
199-}
200-
201-class IntentFilterPrivate
202+#include <QMap>
203+
204+#include "intent-parser.h"
205+
206+
207+class SchemeFilterPrivate
208 {
209 public:
210
211@@ -52,192 +41,182 @@
212
213 public:
214
215- IntentFilterPrivate(const QString& content);
216+ SchemeFilterPrivate(const QMap<QString, QString>& content);
217
218- QJSValue evaluate(const IntentUriDescription& intent);
219- QJSValue evaluate(const QString& customContent
220- , const IntentUriDescription& intent);
221+ QJSValue evaluate(const QString & filterFunction, const QUrl& uri);
222+ QJSValue evaluate(const QUrl& uri);
223+ QJSValue evaluate(QJSValue & function, const QUrl& uri);
224+ bool hasFilterFor(const QUrl& uri);
225
226 private:
227
228 QJSValue callFunction(
229 QJSValue & function
230- , const IntentUriDescription& intent);
231+ , const QString& scheme
232+ , const QString& uri
233+ , const QString& host);
234
235- QString _content;
236+ QMap<QString, QJSValue> _filterFunctionsPerScheme;
237 QJSEngine _engine;
238- QJSValue _function;
239-
240 };
241
242 // static
243-const QString IntentFilterPrivate::DEFAULT_PASS_THROUGH_FILTER =
244- "(function(intent) { return intent; })";
245+const QString SchemeFilterPrivate::DEFAULT_PASS_THROUGH_FILTER =
246+ "(function(uri) { return uri; })";
247
248-IntentFilterPrivate::IntentFilterPrivate(const QString& content)
249- : _content(content)
250+SchemeFilterPrivate::SchemeFilterPrivate(const QMap<QString, QString>& content)
251 {
252- if (_content.isEmpty())
253+ Q_FOREACH(QString scheme, content.keys())
254 {
255- _content = DEFAULT_PASS_THROUGH_FILTER;
256+ QJSValue v = _engine.evaluate(content[scheme]);
257+ if (v.isCallable())
258+ {
259+ _filterFunctionsPerScheme[scheme] = v;
260+ }
261 }
262- _function = _engine.evaluate(_content);
263-}
264-
265-QJSValue IntentFilterPrivate::callFunction(QJSValue & function
266- , const IntentUriDescription& intent)
267-{
268- if (!function.isCallable())
269- {
270+}
271+
272+bool SchemeFilterPrivate::hasFilterFor(const QUrl& uri)
273+{
274+ return _filterFunctionsPerScheme.contains(uri.scheme());
275+}
276+
277+QJSValue SchemeFilterPrivate::callFunction(QJSValue & function
278+ , const QString& scheme
279+ , const QString& path
280+ , const QString& host)
281+{
282+ if (!function.isCallable()) {
283 qCritical() << "Invalid intent filter function (not callable)";
284 return QJSValue();
285 }
286
287 QVariantMap o;
288- o.insert("scheme", intent.scheme);
289- o.insert("uri", intent.uriPath);
290- o.insert("host", intent.host);
291+ o.insert("scheme", scheme);
292+ o.insert("path", path);
293+ o.insert("host", host);
294
295 QJSValueList jsargs;
296 jsargs << _engine.toScriptValue(o);
297 return function.call(jsargs);
298 }
299
300-QJSValue IntentFilterPrivate::evaluate(const QString& customContent
301- , const IntentUriDescription& intent)
302-{
303- QJSValue f = _engine.evaluate(customContent);
304- return callFunction(f, intent);
305-}
306-
307-QJSValue IntentFilterPrivate::evaluate(const IntentUriDescription& intent)
308-{
309- return callFunction(_function, intent);
310+QJSValue SchemeFilterPrivate::evaluate(const QString & filterFunction,
311+ const QUrl& uri)
312+{
313+ QJSValue f = _engine.evaluate(filterFunction);
314+ return evaluate(f, uri);
315+}
316+
317+QJSValue SchemeFilterPrivate::evaluate(const QUrl& uri)
318+{
319+ return evaluate(_filterFunctionsPerScheme[uri.scheme()], uri);
320+}
321+
322+QJSValue SchemeFilterPrivate::evaluate(QJSValue & function, const QUrl& uri)
323+{
324+ QString scheme;
325+ QString path;
326+ QString host;
327+
328+ if (uri.scheme() == "intent") {
329+ IntentUriDescription intent = parseIntentUri(uri);
330+
331+ scheme = intent.scheme;
332+ path = intent.uriPath;
333+ host = intent.host;
334+ }
335+ else {
336+ scheme = uri.scheme();
337+ path = uri.path();
338+ host = uri.host();
339+ }
340+
341+ return callFunction(
342+ function,
343+ scheme,
344+ path,
345+ host);
346 }
347
348 // static
349-bool IntentFilter::isValidLocalIntentFilterFile(const QString& filename)
350+QMap<QString, QString>
351+SchemeFilter::parseValidLocalSchemeFilterFile(
352+ bool & isValid,
353+ const QString& filename)
354 {
355 QFile f(filename);
356- if (!f.exists() || !f.open(QIODevice::ReadOnly))
357- {
358- return false;
359- }
360-
361- // Perform basic validation
362- QJSEngine engine;
363- QJSValue result = engine.evaluate(QString(f.readAll()), filename);
364- return !result.isNull() && result.isCallable();
365-}
366-
367-// static
368-bool IntentFilter::isValidIntentFilterResult(const QVariantMap& result)
369-{
370- return result.contains("scheme")
371- && result.value("scheme").canConvert(QVariant::String)
372- && result.contains("uri")
373- && result.value("uri").canConvert(QVariant::String);
374-}
375-
376-// static
377-bool IntentFilter::isValidIntentDescription(const IntentUriDescription& intentDescription)
378-{
379- return !intentDescription.uriPath.isEmpty()
380- || !intentDescription.package.isEmpty();
381-}
382-
383-
384-IntentFilter::IntentFilter(const QString& content, QObject *parent) :
385+ if (!f.exists() || !f.open(QIODevice::ReadOnly)) {
386+ isValid = false;
387+ return QMap<QString, QString>();
388+ }
389+
390+ QString content = f.readAll();
391+
392+ QJsonDocument document(QJsonDocument::fromJson(content.toUtf8()));
393+ if (document.isNull() || document.isEmpty() || !document.isObject()) {
394+ isValid = false;
395+ return QMap<QString, QString>();
396+ }
397+
398+ QMap<QString, QString> parsedContent;
399+
400+ QJsonObject root = document.object();
401+ Q_FOREACH(const QString& k, root.keys()) {
402+ QJsonValue v = root.value(k);
403+
404+ if (v.isString()) {
405+ QJSEngine engine;
406+ QJSValue result = engine.evaluate(v.toString(), filename);
407+
408+ if (result.isNull() || !result.isCallable()) {
409+ isValid = false;
410+ return QMap<QString, QString>();
411+ }
412+ parsedContent[k] = v.toString();
413+ }
414+ }
415+
416+ isValid = true;
417+
418+ return parsedContent;
419+}
420+
421+SchemeFilter::SchemeFilter(const QMap<QString, QString>& content, QObject *parent) :
422 QObject(parent),
423- d_ptr(new IntentFilterPrivate(content))
424-{
425-}
426+ d_ptr(new SchemeFilterPrivate(content))
427+{}
428
429-IntentFilter::~IntentFilter()
430+SchemeFilter::~SchemeFilter()
431 {
432 delete d_ptr;
433 }
434
435-QVariantMap IntentFilter::applyFilter(const QString& intentUri)
436-{
437- Q_D(IntentFilter);
438+bool SchemeFilter::hasFilterFor(const QUrl& uri)
439+{
440+ Q_D(SchemeFilter);
441+ return d->hasFilterFor(uri);
442+}
443+
444+QVariantMap SchemeFilter::applyFilter(const QUrl& uri)
445+{
446+ Q_D(SchemeFilter);
447+
448+ if (! hasFilterFor(uri)) {
449+ return d->evaluate(
450+ SchemeFilterPrivate::DEFAULT_PASS_THROUGH_FILTER, uri)
451+ .toVariant().toMap();
452+ }
453+
454+ QJSValue value;
455+
456+ // Special case to parse schemes we know about & want to provide helpr w/
457+ value = d->evaluate(uri);
458
459 QVariantMap result;
460- IntentUriDescription intentDescription =
461- parseIntentUri(QUrl::fromUserInput(intentUri));
462- if (!isValidIntentDescription(intentDescription))
463- {
464- return result;
465- }
466- QJSValue value = d->evaluate(intentDescription);
467- if (value.isObject()
468- && value.toVariant().canConvert(QVariant::Map))
469- {
470- QVariantMap r = value.toVariant().toMap();
471- if (isValidIntentFilterResult(r))
472- {
473- result = r;
474- }
475- else
476- {
477- // Fallback to a noop
478- result = d->evaluate(
479- IntentFilterPrivate::DEFAULT_PASS_THROUGH_FILTER
480- , intentDescription).toVariant().toMap();
481- }
482- }
483- return result;
484-}
485-
486-bool IntentFilter::isValidIntentUri(const QString& intentUri) const
487-{
488- // a bit overkill but anyway ...
489- return isValidIntentDescription(parseIntentUri(QUrl::fromUserInput(intentUri)));
490-}
491-
492-IntentUriDescription
493-parseIntentUri(const QUrl& intentUri)
494-{
495- IntentUriDescription result;
496- if (intentUri.scheme() != INTENT_SCHEME_STRING
497- || !intentUri.fragment().startsWith(INTENT_START_FRAGMENT_TAG)
498- || !intentUri.fragment().endsWith(INTENT_END_FRAGMENT_TAG))
499- {
500- return result;
501- }
502- QString host = intentUri.host();
503- trimUriSeparator(host);
504- QString path = intentUri.path();
505- if (intentUri.hasQuery())
506- {
507- path += "?" + intentUri.query();
508- trimUriSeparator(path);
509- }
510- result.host = host;
511- result.uriPath = path;
512- QStringList infos = intentUri.fragment().split(";");
513- Q_FOREACH(const QString& info, infos)
514- {
515- if (info.startsWith(INTENT_URI_PACKAGE_PREFIX))
516- {
517- result.package = info.split(INTENT_URI_PACKAGE_PREFIX)[1];
518- }
519- else if (info.startsWith(INTENT_URI_ACTION_PREFIX))
520- {
521- result.action = info.split(INTENT_URI_ACTION_PREFIX)[1];
522- }
523- else if (info.startsWith(INTENT_URI_CATEGORY_PREFIX))
524- {
525- result.category = info.split(INTENT_URI_CATEGORY_PREFIX)[1];
526- }
527- else if (info.startsWith(INTENT_URI_COMPONENT_PREFIX))
528- {
529- result.component = info.split(INTENT_URI_COMPONENT_PREFIX)[1];
530- }
531- else if (info.startsWith(INTENT_URI_SCHEME_PREFIX))
532- {
533- result.scheme = info.split(INTENT_URI_SCHEME_PREFIX)[1];
534- }
535- }
536+ if (value.isObject() && value.toVariant().canConvert(QVariant::Map)) {
537+ result = value.toVariant().toMap();
538+ }
539+
540 return result;
541 }
542
543=== renamed file 'src/app/webcontainer/intent-filter.h' => 'src/app/webcontainer/scheme-filter.h'
544--- src/app/webcontainer/intent-filter.h 2015-01-30 16:19:51 +0000
545+++ src/app/webcontainer/scheme-filter.h 2015-08-20 17:55:29 +0000
546@@ -16,90 +16,43 @@
547 * along with this program. If not, see <http://www.gnu.org/licenses/>.
548 */
549
550-#ifndef _INTENT_FILTER_H_
551-#define _INTENT_FILTER_H_
552+#ifndef _SCHEME_FILTER_H_
553+#define _SCHEME_FILTER_H_
554
555 #include <QObject>
556+#include <QMap>
557 #include <QString>
558+#include <QUrl>
559 #include <QVariantMap>
560
561
562-class QUrl;
563-class IntentFilterPrivate;
564-struct IntentUriDescription;
565+class SchemeFilterPrivate;
566
567 /**
568- * @brief The IntentFilter class
569+ * @brief The SchemeFilter class
570 */
571-class IntentFilter : public QObject
572+class SchemeFilter : public QObject
573 {
574 Q_OBJECT
575
576 public:
577- IntentFilter(const QString& content,
578- QObject *parent = 0);
579- ~IntentFilter();
580-
581- /**
582- * @brief isValidLocalIntentFilterFile
583- * @return
584- */
585- static bool isValidLocalIntentFilterFile(const QString& filename);
586-
587- /**
588- * @brief isValidIntentDescription
589- * @return
590- */
591- static bool isValidIntentDescription(const IntentUriDescription& );
592-
593- /**
594- * @brief isValidIntentFilterResult
595- * @return
596- */
597- static bool isValidIntentFilterResult(const QVariantMap& );
598-
599- /**
600- * @brief apply
601- * @return
602- */
603- Q_INVOKABLE QVariantMap applyFilter(const QString& intentUri);
604-
605- /**
606- * @brief isValidIntentUri
607- * @return
608- */
609- Q_INVOKABLE bool isValidIntentUri(const QString& intentUri) const;
610+ SchemeFilter(const QMap<QString, QString>& content,
611+ QObject *parent = 0);
612+ ~SchemeFilter();
613+
614+ static QMap<QString, QString> parseValidLocalSchemeFilterFile(
615+ bool & isValid,
616+ const QString& filename);
617+
618+ Q_INVOKABLE QVariantMap applyFilter(const QUrl& uri);
619+
620+ Q_INVOKABLE bool hasFilterFor(const QUrl& uri);
621
622
623 private:
624
625- IntentFilterPrivate* d_ptr;
626- Q_DECLARE_PRIVATE(IntentFilter)
627-};
628-
629-
630-struct IntentUriDescription
631-{
632- QString uriPath;
633-
634- // optional
635- QString host;
636-
637- QString package;
638- QString action;
639- QString category;
640- QString component;
641- QString scheme;
642-};
643-
644-/**
645- * @brief Parse a URI that is supposed to be an intent as defined here
646- *
647- * https://developer.chrome.com/multidevice/android/intents
648- *
649- * @param intentUri
650- * @return
651- */
652-IntentUriDescription parseIntentUri(const QUrl& intentUri);
653-
654-#endif // _INTENT_FILTER_H_
655+ SchemeFilterPrivate* d_ptr;
656+ Q_DECLARE_PRIVATE(SchemeFilter)
657+};
658+
659+#endif // _SCHEME_FILTER_H_
660
661=== modified file 'src/app/webcontainer/webapp-container.cpp'
662--- src/app/webcontainer/webapp-container.cpp 2015-06-24 13:37:05 +0000
663+++ src/app/webcontainer/webapp-container.cpp 2015-08-20 17:55:29 +0000
664@@ -20,7 +20,7 @@
665 #include "webapp-container.h"
666
667 #include "chrome-cookie-store.h"
668-#include "intent-filter.h"
669+#include "scheme-filter.h"
670 #include "local-cookie-store.h"
671 #include "online-accounts-cookie-store.h"
672 #include "session-utils.h"
673@@ -78,7 +78,7 @@
674 }
675
676 const QString WebappContainer::URL_PATTERN_SEPARATOR = ",";
677-const QString WebappContainer::LOCAL_INTENT_FILTER_FILENAME = "local-intent-filter.js";
678+const QString WebappContainer::LOCAL_SCHEME_FILTER_FILENAME = "local-scheme-filter.js";
679
680
681 WebappContainer::WebappContainer(int& argc, char** argv):
682@@ -193,8 +193,8 @@
683 return false;
684 }
685
686- // Handle an optional intent filter. The default filter does nothing.
687- setupLocalIntentFilterIfAny(context);
688+ // Handle an optional scheme handler filter. The default *catch all* filter does nothing.
689+ setupLocalSchemeFilterIfAny(context, m_webappModelSearchPath);
690
691 m_component->completeCreate();
692
693@@ -204,28 +204,31 @@
694 }
695 }
696
697-void WebappContainer::setupLocalIntentFilterIfAny(QQmlContext* context)
698+void WebappContainer::setupLocalSchemeFilterIfAny(QQmlContext* context, const QString& webappSearchPath)
699 {
700- if(!context)
701- {
702+ if(!context) {
703 return;
704 }
705
706- QString localIntentFilterFileContent;
707- if (IntentFilter::isValidLocalIntentFilterFile(LOCAL_INTENT_FILTER_FILENAME))
708- {
709- QFile f(LOCAL_INTENT_FILTER_FILENAME);
710- if (f.open(QIODevice::ReadOnly))
711- {
712- localIntentFilterFileContent = QString(f.readAll());
713- }
714- f.close();
715-
716- qDebug() << "Using local intent filter file:"
717- << LOCAL_INTENT_FILTER_FILENAME;
718+ QDir searchPath(webappSearchPath.isEmpty()
719+ ? QDir::currentPath()
720+ : webappSearchPath);
721+
722+ bool hasValidLocalSchemeFilterFile = false;
723+
724+ QMap<QString, QString> content =
725+ SchemeFilter::parseValidLocalSchemeFilterFile(
726+ hasValidLocalSchemeFilterFile,
727+ searchPath.filePath(LOCAL_SCHEME_FILTER_FILENAME));
728+
729+ if (hasValidLocalSchemeFilterFile) {
730+ qDebug() << "Using local scheme filter file:"
731+ << LOCAL_SCHEME_FILTER_FILENAME;
732 }
733- m_intentFilter.reset(new IntentFilter(localIntentFilterFileContent, NULL));
734- context->setContextProperty("webappIntentFilter", m_intentFilter.data());
735+
736+ m_schemeFilter.reset(new SchemeFilter(content));
737+
738+ context->setContextProperty("webappSchemeFilter", m_schemeFilter.data());
739 }
740
741 bool WebappContainer::isValidLocalApplicationRunningContext() const
742
743=== modified file 'src/app/webcontainer/webapp-container.h'
744--- src/app/webcontainer/webapp-container.h 2015-06-24 13:37:05 +0000
745+++ src/app/webcontainer/webapp-container.h 2015-08-20 17:55:29 +0000
746@@ -28,7 +28,7 @@
747 #include <QStringList>
748 #include <QScopedPointer>
749
750-class IntentFilter;
751+class SchemeFilter;
752 class QQmlContext;
753
754 class WebappContainer : public BrowserApplication
755@@ -54,7 +54,7 @@
756 bool isValidLocalResource(const QString& resourceName) const;
757 bool shouldNotValidateCommandLineUrls() const;
758 bool isValidLocalIntentFilterFile(const QString& filename) const;
759- void setupLocalIntentFilterIfAny(QQmlContext* context);
760+ void setupLocalSchemeFilterIfAny(QQmlContext* context, const QString& webappSearchPath);
761
762 private:
763 QString m_webappName;
764@@ -71,10 +71,10 @@
765 QString m_localCookieStoreDbPath;
766 QString m_userAgentOverride;
767 QScopedPointer<WebappContainerHelper> m_webappContainerHelper;
768- QScopedPointer<IntentFilter> m_intentFilter;
769+ QScopedPointer<SchemeFilter> m_schemeFilter;
770
771 static const QString URL_PATTERN_SEPARATOR;
772- static const QString LOCAL_INTENT_FILTER_FILENAME;
773+ static const QString LOCAL_SCHEME_FILTER_FILENAME;
774 };
775
776 #endif // __WEBAPP_CONTAINER_H__
777
778=== modified file 'src/app/webcontainer/webapp-container.qml'
779--- src/app/webcontainer/webapp-container.qml 2015-08-10 15:22:00 +0000
780+++ src/app/webcontainer/webapp-container.qml 2015-08-20 17:55:29 +0000
781@@ -32,7 +32,6 @@
782
783 property string localCookieStoreDbPath: ""
784
785- property var intentFilterHandler
786 property string url: ""
787 property url webappIcon: ""
788 property string webappName: ""
789@@ -54,7 +53,7 @@
790 title: getWindowTitle()
791
792 // Used for testing
793- signal intentUriHandleResult(string uri)
794+ signal schemeUriHandleFilterResult(string uri)
795
796 function getWindowTitle() {
797 var webappViewTitle =
798@@ -229,13 +228,13 @@
799 showWebView()
800 }
801
802- function makeUrlFromIntentResult(intentFilterResult) {
803+ function makeUrlFromResult(result) {
804 var scheme = null
805 var hostname = null
806 var url = root.currentWebview.url || root.url
807- if (intentFilterResult.host
808- && intentFilterResult.host.length !== 0) {
809- hostname = intentFilterResult.host
810+ if (result.host
811+ && result.host.length !== 0) {
812+ hostname = result.host
813 }
814 else {
815 var matchHostname = url.toString().match(/.*:\/\/([^/]*)\/.*/)
816@@ -243,9 +242,10 @@
817 hostname = matchHostname[1]
818 }
819 }
820- if (intentFilterResult.scheme
821- && intentFilterResult.scheme.length !== 0) {
822- scheme = intentFilterResult.scheme
823+
824+ if (result.scheme
825+ && result.scheme.length !== 0) {
826+ scheme = result.scheme
827 }
828 else {
829 var matchScheme = url.toString().match(/(.*):\/\/[^/]*\/.*/)
830@@ -257,33 +257,32 @@
831 + '://'
832 + hostname
833 + "/"
834- + (intentFilterResult.uri
835- ? intentFilterResult.uri : "")
836+ + (result.path
837+ ? result.path : "")
838 }
839
840 /**
841- * Identity function for non-intent URIs.
842 *
843- * Otherwise if the URI is an intent, tries to apply a webapp
844- * local filter (or identity) and reconstruct the target URI based
845- * on its result.
846 */
847- function handleIntentUri(uri) {
848- var _uri = uri;
849- if (webappIntentFilter
850- && webappIntentFilter.isValidIntentUri(_uri)) {
851- var result = webappIntentFilter.applyFilter(_uri)
852- _uri = makeUrlFromIntentResult(result)
853-
854- console.log("Intent URI '" + uri + "' was mapped to '" + _uri + "'")
855+ function translateHandlerUri(uri) {
856+ //
857+ var scheme = uri.substr(0, uri.indexOf(":"))
858+ if (scheme.indexOf("http") === 0) {
859+ schemeUriHandleFilterResult(uri)
860+ return uri
861 }
862
863+ var result = webappSchemeFilter.applyFilter(uri)
864+ var mapped_uri = makeUrlFromResult(result)
865+
866+ uri = mapped_uri
867+
868 // Report the result of the intent uri filtering (if any)
869 // Done for testing purposed. It is not possible at this point
870 // to have AP call a slot and retrieve its result synchronously.
871- intentUriHandleResult(_uri)
872+ schemeUriHandleFilterResult(uri)
873
874- return _uri
875+ return uri
876 }
877
878 // Handle runtime requests to open urls as defined
879@@ -306,7 +305,7 @@
880 return;
881 }
882
883- requestedUrl = handleIntentUri(requestedUrl);
884+ requestedUrl = translateHandlerUri(requestedUrl);
885
886 // Add a small guard to prevent browsing to invalid urls
887 if (currentWebview
888
889=== modified file 'tests/autopilot/webapp_container/tests/__init__.py'
890--- tests/autopilot/webapp_container/tests/__init__.py 2015-04-29 22:18:55 +0000
891+++ tests/autopilot/webapp_container/tests/__init__.py 2015-08-20 17:55:29 +0000
892@@ -102,17 +102,17 @@
893 Eventually(Equals(100), timeout=20))
894 self.assertThat(webview.loading, Eventually(Equals(False)))
895
896- def get_intent_filtered_uri(self, uri):
897+ def get_scheme_filtered_uri(self, uri):
898 webviewContainer = self.get_webcontainer_window()
899 watcher = webviewContainer.watch_signal(
900- 'intentUriHandleResult(QString)')
901+ 'schemeUriHandleFilterResult(QString)')
902 previous = watcher.num_emissions
903- webviewContainer.slots.handleIntentUri(uri)
904+ webviewContainer.slots.translateHandlerUri(uri)
905 self.assertThat(
906 lambda: watcher.num_emissions,
907 Eventually(GreaterThan(previous)))
908 result = webviewContainer.get_signal_emissions(
909- 'intentUriHandleResult(QString)')[-1][0]
910+ 'schemeUriHandleFilterResult(QString)')[-1][0]
911 return result
912
913 def browse_to(self, url):
914
915=== renamed file 'tests/autopilot/webapp_container/tests/test_intent_uri_support.py' => 'tests/autopilot/webapp_container/tests/test_scheme_filter.py'
916--- tests/autopilot/webapp_container/tests/test_intent_uri_support.py 2015-01-29 16:53:45 +0000
917+++ tests/autopilot/webapp_container/tests/test_scheme_filter.py 2015-08-20 17:55:29 +0000
918@@ -25,7 +25,7 @@
919
920
921 @contextmanager
922-def generate_temp_webapp_with_intent(intent_filter_content=""):
923+def generate_webapp_with_scheme_filter(scheme_filter_content=""):
924 tmpdir = tempfile.mkdtemp()
925 manifest_content = """
926 {
927@@ -38,10 +38,10 @@
928 manifest_file = "{}/webapp-properties.json".format(tmpdir)
929 with open(manifest_file, "w+") as f:
930 f.write(manifest_content)
931- if len(intent_filter_content) != 0:
932- intent_filter_file = "{}/local-intent-filter.js".format(tmpdir)
933- with open(intent_filter_file, "w+") as f:
934- f.write(intent_filter_content)
935+ if len(scheme_filter_content) != 0:
936+ scheme_filter_file = "{}/local-scheme-filter.js".format(tmpdir)
937+ with open(scheme_filter_file, "w+") as f:
938+ f.write(scheme_filter_content)
939 old_cwd = os.getcwd()
940 try:
941 os.chdir(tmpdir)
942@@ -51,16 +51,16 @@
943 shutil.rmtree(tmpdir)
944
945
946-# Those tests rely on get_intent_filtered_uri() which
947+# Those tests rely on get_scheme_filtered_uri() which
948 # relies on implementation detail to trigger part of the intent handling
949 # code. This comes from the fact that the url-dispatcher is not easily
950 # instrumentable , so a full feature flow coverage is quite tricky to get.
951 # Those tests are not really functional in that sense.
952-class WebappContainerIntentUriSupportTestCase(
953+class WebappContainerSchemeFilterTestCase(
954 WebappContainerTestCaseWithLocalContentBase):
955 def test_basic_intent_parsing(self):
956 rule = 'MAP *.test.com:80 ' + self.get_base_url_hostname()
957- with generate_temp_webapp_with_intent() as webapp_install_path:
958+ with generate_webapp_with_scheme_filter() as webapp_install_path:
959 args = ['--webappModelSearchPath='+webapp_install_path]
960 self.launch_webcontainer_app(
961 args,
962@@ -73,12 +73,12 @@
963 #Intent;scheme=http;package=com.google.android.apps.maps;end'
964 self.assertThat(
965 'http://maps.google.es/maps?ie=utf-8&gl=es',
966- Equals(self.get_intent_filtered_uri(intent_uri)))
967+ Equals(self.get_scheme_filtered_uri(intent_uri)))
968
969 def test_webapp_with_invalid_default_local_intent(self):
970 rule = 'MAP *.test.com:80 ' + self.get_base_url_hostname()
971- filter = "1"
972- with generate_temp_webapp_with_intent(filter) as webapp_install_path:
973+ filter = "{ \"intent\": 1 }"
974+ with generate_webapp_with_scheme_filter(filter) as webapp_install_path:
975 args = ['--webappModelSearchPath='+webapp_install_path]
976 self.launch_webcontainer_app(
977 args,
978@@ -91,16 +91,16 @@
979 #Intent;scheme=http;package=com.google.android.apps.maps;end'
980 self.assertThat(
981 'http://www.test.com/maps?ie=utf-8&gl=es',
982- Equals(self.get_intent_filtered_uri(intent_uri)))
983+ Equals(self.get_scheme_filtered_uri(intent_uri)))
984
985 def test_with_valid_default_local_intent(self):
986 rule = 'MAP *.test.com:80 ' + self.get_base_url_hostname()
987- filter = "(function(r) { \
988+ filter = "{ \"intent\": \"(function(r) { \
989 return { \
990 'scheme': 'https', \
991 'host': 'maps.test.com', \
992- 'uri': r.uri }; })"
993- with generate_temp_webapp_with_intent(filter) as webapp_install_path:
994+ 'path': r.path }; })\" }"
995+ with generate_webapp_with_scheme_filter(filter) as webapp_install_path:
996 args = ['--webappModelSearchPath='+webapp_install_path]
997 self.launch_webcontainer_app(
998 args,
999@@ -113,4 +113,47 @@
1000 #Intent;scheme=http;package=com.google.android.apps.maps;end'
1001 self.assertThat(
1002 'https://maps.test.com/maps?ie=utf-8&gl=es',
1003- Equals(self.get_intent_filtered_uri(intent_uri)))
1004+ Equals(self.get_scheme_filtered_uri(intent_uri)))
1005+
1006+ def test_no_filter_for_http(self):
1007+ rule = 'MAP *.test.com:80 ' + self.get_base_url_hostname()
1008+ filter = "{ \"http\": \"(function(r) { \
1009+ return { \
1010+ 'scheme': 'https', \
1011+ 'host': 'maps.test.com', \
1012+ 'path': r.path }; })\" }"
1013+ with generate_webapp_with_scheme_filter(filter) as webapp_install_path:
1014+ args = ['--webappModelSearchPath='+webapp_install_path]
1015+ self.launch_webcontainer_app(
1016+ args,
1017+ {'UBUNTU_WEBVIEW_HOST_MAPPING_RULES': rule})
1018+
1019+ webview = self.get_oxide_webview()
1020+ webapp_url = 'http://www.test.com/'
1021+ self.assertThat(webview.url, Eventually(Equals(webapp_url)))
1022+
1023+ new_uri = 'http://www.test.com/maps?ie=utf-8&gl=es'
1024+ self.assertThat(
1025+ 'http://www.test.com/maps?ie=utf-8&gl=es',
1026+ Equals(self.get_scheme_filtered_uri(new_uri)))
1027+
1028+ def test_default_scheme_filter(self):
1029+ rule = 'MAP *.test.com:80 ' + self.get_base_url_hostname()
1030+ filter = "{ \"mailto\": \"(function(r) { \
1031+ return { \
1032+ 'scheme': 'https', \
1033+ 'host': 'mail.google.com', \
1034+ 'path': '?to='+encodeURIComponent(r.path) }; })\" }"
1035+ with generate_webapp_with_scheme_filter(filter) as webapp_install_path:
1036+ args = ['--webappModelSearchPath='+webapp_install_path]
1037+ self.launch_webcontainer_app(
1038+ args,
1039+ {'UBUNTU_WEBVIEW_HOST_MAPPING_RULES': rule})
1040+ webview = self.get_oxide_webview()
1041+ webapp_url = 'http://www.test.com/'
1042+ self.assertThat(webview.url, Eventually(Equals(webapp_url)))
1043+
1044+ scheme_uri = 'mailto:blabla@ubuntu.com'
1045+ self.assertThat(
1046+ 'https://mail.google.com/?to=blabla%40ubuntu.com',
1047+ Equals(self.get_scheme_filtered_uri(scheme_uri)))
1048
1049=== modified file 'tests/unittests/intent-filter/CMakeLists.txt'
1050--- tests/unittests/intent-filter/CMakeLists.txt 2015-06-22 10:29:20 +0000
1051+++ tests/unittests/intent-filter/CMakeLists.txt 2015-08-20 17:55:29 +0000
1052@@ -3,7 +3,8 @@
1053 find_package(Qt5Test REQUIRED)
1054 set(TEST tst_IntentFilterTests)
1055 set(SOURCES
1056- ${webapp-container_SOURCE_DIR}/intent-filter.cpp
1057+ ${webapp-container_SOURCE_DIR}/intent-parser.cpp
1058+ ${webapp-container_SOURCE_DIR}/scheme-filter.cpp
1059 tst_IntentFilterTests.cpp
1060 )
1061 include_directories(${webapp-container_SOURCE_DIR})
1062
1063=== modified file 'tests/unittests/intent-filter/tst_IntentFilterTests.cpp'
1064--- tests/unittests/intent-filter/tst_IntentFilterTests.cpp 2015-01-30 16:31:15 +0000
1065+++ tests/unittests/intent-filter/tst_IntentFilterTests.cpp 2015-08-20 17:55:29 +0000
1066@@ -21,7 +21,8 @@
1067 #include <QtTest/QtTest>
1068
1069 // local
1070-#include "intent-filter.h"
1071+#include "scheme-filter.h"
1072+#include "intent-parser.h"
1073
1074 class IntentFilterTests : public QObject
1075 {
1076@@ -144,12 +145,6 @@
1077 QCOMPARE(d.action, action);
1078 QCOMPARE(d.component, component);
1079 QCOMPARE(d.category, category);
1080-
1081- QVERIFY(IntentFilter::isValidIntentDescription(d) == isValid);
1082-
1083- QString emptyContent;
1084- IntentFilter pf(emptyContent);
1085- QVERIFY(pf.isValidIntentUri(intentUris) == isValid);
1086 }
1087
1088 void applyFilters_data()
1089@@ -171,24 +166,17 @@
1090
1091 QTest::newRow("Valid intent - default filter function")
1092 << "intent://scan/#Intent;component=com;scheme=zxing;category=BROWSABLE;action=com;package=com.google.zxing.client.android;end"
1093- << "(function(result) {return {'scheme': result.scheme+'custom', 'uri': result.uri+'custom', 'host': result.host+'custom'}; })"
1094+ << "(function(result) {return {'scheme': result.scheme+'custom', 'path': result.path+'custom', 'host': result.host+'custom'}; })"
1095 << "zxingcustom"
1096 << "/custom"
1097 << "scancustom";
1098
1099 QTest::newRow("Valid intent - no (optional) host in filter result")
1100 << "intent://host/my/long/path?a=1/#Intent;component=com;scheme=zxing;category=BROWSABLE;action=com;package=com.google.zxing.client.android;end"
1101- << "(function(result) {return {'scheme': result.scheme+'custom', 'uri': result.uri+'custom' }; })"
1102+ << "(function(result) {return {'scheme': result.scheme+'custom', 'path': result.path+'custom' }; })"
1103 << "zxingcustom"
1104 << "my/long/path?a=1custom"
1105 << "";
1106-
1107- QTest::newRow("Valid intent - invalid filter fallback to default")
1108- << "intent://host/my/long/path?a=1/#Intent;component=com;scheme=zxing;category=BROWSABLE;action=com;package=com.google.zxing.client.android;end"
1109- << "(function(result) {return { 'uri': result.uri+'custom' }; })"
1110- << "zxing"
1111- << "my/long/path?a=1"
1112- << "host";
1113 }
1114
1115 void applyFilters()
1116@@ -201,16 +189,18 @@
1117 QFETCH(QString, uri);
1118 QFETCH(QString, host);
1119
1120- IntentFilter pf(filterFunctionSource);
1121- QVERIFY(pf.isValidIntentUri(intentUris));
1122-
1123- QVariantMap r = pf.applyFilter(intentUris);
1124+ QMap<QString, QString> filters;
1125+ filters["intent"] = filterFunctionSource;
1126+
1127+ SchemeFilter sf(filters);
1128+
1129+ QVariantMap r = sf.applyFilter(intentUris);
1130 QVERIFY(r.contains("scheme"));
1131- QVERIFY(r.contains("uri"));
1132+ QVERIFY(r.contains("path"));
1133
1134 QCOMPARE(r.value("scheme").toString(), scheme);
1135 QCOMPARE(r.value("host").toString(), host);
1136- QCOMPARE(r.value("uri").toString(), uri);
1137+ QCOMPARE(r.value("path").toString(), uri);
1138 }
1139 };
1140

Subscribers

People subscribed via source and target branches

to status/vote changes: