Bug 1119670 - Implement processing of scope member of web manifest. r=ehsan
authorMarcos Caceres <mcaceres@mozilla.com>
Thu, 15 Jan 2015 19:46:00 -0500
changeset 253050 b0066a6e586534ea5a460eec8369671c9322f1e4
parent 253049 a0f3db72a62ceeb62472f982590decc6dc2587e8
child 253051 d172fffe7074288db17141d23f0bc2afe45f92c5
push id721
push userjlund@mozilla.com
push dateTue, 21 Apr 2015 23:03:33 +0000
treeherdermozilla-release@d27c9211ebb3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1119670
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1119670 - Implement processing of scope member of web manifest. r=ehsan
dom/manifest/ManifestProcessor.jsm
dom/manifest/test/mochitest.ini
dom/manifest/test/test_ManifestProcessor_scope.html
--- a/dom/manifest/ManifestProcessor.jsm
+++ b/dom/manifest/ManifestProcessor.jsm
@@ -130,16 +130,49 @@ this.ManifestProcessor.prototype.process
       expectedType: 'string'
     };
 
     let value = extractValue(obj);
     value = (value) ? value.trim() : value;
     return (displayModes.has(value)) ? value : defaultDisplayMode;
   }
 
+  function processScopeMember(manifest, manifestURL, docURL, startURL) {
+    const spec = {
+        objectName: 'manifest',
+        object: manifest,
+        property: 'scope',
+        expectedType: 'string',
+        dontTrim: true
+      },
+      value = extractValue(spec);
+    let scopeURL;
+    try {
+      scopeURL = new URL(value, manifestURL);
+    } catch (e) {
+      let msg = 'The URL of scope is invalid.';
+      issueDeveloperWarning(msg);
+      return undefined;
+    }
+
+    if (scopeURL.origin !== docURL.origin) {
+      let msg = 'Scope needs to be same-origin as Document.';
+      issueDeveloperWarning(msg);
+      return undefined;
+    }
+
+    //If start URL is not within scope of scope URL:
+    if (startURL && startURL.origin !== scopeURL.origin || !startURL.pathname.startsWith(scopeURL.pathname)) {
+      let msg = 'The start URL is outside the scope, so scope is invalid.';
+      issueDeveloperWarning(msg);
+      return undefined;
+    }
+    return scopeURL;
+  }
+
   function processStartURLMember(manifest, manifestURL, docURL) {
     const obj = {
       objectName: 'manifest',
       object: manifest,
       property: 'start_url',
       expectedType: 'string'
     };
 
@@ -314,10 +347,11 @@ this.ManifestProcessor.prototype.process
   const processedManifest = {
     start_url: processStartURLMember(manifest, manifestURL, docURL),
     display: processDisplayMember(manifest),
     orientation: processOrientationMember(manifest),
     name: processNameMember(manifest),
     icons: processIconsMember(manifest, manifestURL),
     short_name: processShortNameMember(manifest)
   };
+  processedManifest.scope = processScopeMember(manifest, manifestURL, docURL, processedManifest.start_url);
   return processedManifest;
 };
\ No newline at end of file
--- a/dom/manifest/test/mochitest.ini
+++ b/dom/manifest/test/mochitest.ini
@@ -8,9 +8,10 @@ support-files =
 [test_IconsProcessor_sizes.html]
 [test_IconsProcessor_src.html]
 [test_IconsProcessor_type.html]
 [test_ManifestProcessor_display.html]
 [test_ManifestProcessor_icons.html]
 [test_ManifestProcessor_JSON.html]
 [test_ManifestProcessor_name_and_short_name.html]
 [test_ManifestProcessor_orientation.html]
-[test_ManifestProcessor_start_url.html]
\ No newline at end of file
+[test_ManifestProcessor_start_url.html]
+[test_ManifestProcessor_scope.html]
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/manifest/test/test_ManifestProcessor_scope.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1079453
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1079453</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script src="common.js"></script>
+  <script>
+/**
+ * Manifest scope
+ * https://w3c.github.io/manifest/#scope-member
+ **/
+'use strict';
+var expected = 'Expect non-string scope to be undefined';
+typeTests.forEach((type) => {
+  data.jsonText = JSON.stringify({
+    scope: type
+  });
+  var result = processor.process(data);
+  ise(result.scope, undefined, expected);
+});
+
+var expected = 'Expect different origin to be treated as undefined';
+data.jsonText = JSON.stringify({
+  scope: 'http://not-same-origin'
+});
+var result = processor.process(data);
+ise(result.scope, undefined, expected);
+
+var expected = 'Expect the empty string to be treated as undefined.';
+data.jsonText = JSON.stringify({
+  scope: ''
+});
+var result = processor.process(data);
+ise(result.scope, undefined, expected);
+
+var expected = 'Resolve URLs relative to manifest.';
+var URLs = ['path', '/path', '../../path'];
+URLs.forEach((url) => {
+  data.jsonText = JSON.stringify({
+    scope: url,
+    start_url: "/path"
+  });
+  var absURL = new URL(url, manifestURL).toString();
+  var result = processor.process(data);
+  console.log(result);
+  ise(String(result.scope), absURL, expected);
+});
+
+var expected = 'If start URL is not in scope, return undefined.';
+data.jsonText = JSON.stringify({
+  scope: 'foo',
+  start_url: 'bar'
+});
+var result = processor.process(data);
+ise(result.scope, undefined, expected);
+
+var expected = 'If start URL is in scope, use the scope.';
+data.jsonText = JSON.stringify({
+  start_url: 'foobar',
+  scope: 'foo'
+});
+var result = processor.process(data);
+ise(result.scope.toString(), new URL('foo', manifestURL).toString(), expected);
+
+var expected = 'Expect start_url to be ' + new URL('foobar', manifestURL).toString();
+ise(result.start_url.toString(), new URL('foobar', manifestURL).toString(), expected);
+
+var expected = 'If start URL is in scope, use the scope.';
+data.jsonText = JSON.stringify({
+  start_url: '/foo/',
+  scope: '/foo/'
+});
+var result = processor.process(data);
+ise(result.scope.toString(), new URL('/foo/', manifestURL).toString(), expected);
+
+var expected = 'If start URL is in scope, use the scope.';
+data.jsonText = JSON.stringify({
+  start_url: '.././foo/',
+  scope: '../foo/'
+});
+var result = processor.process(data);
+ise(result.scope.toString(), new URL('/foo/', manifestURL).toString(), expected);
+
+  </script>
+</head>