Bug 1452533 - JsonSchemaValidator should output URL types as URL objects instead of nsIURIs. r=felipe
authorKanika Saini <ksaini@mozilla.com>
Tue, 05 Jun 2018 19:20:40 +0530
changeset 423165 b40000a76390dc25ab8af43fadf33a2c2d8f5a3e
parent 423164 da427a67372e19b219eaec6fada813babfd6e4b2
child 423166 3b66a441d832b077dde52a5a2692d1b07fde3f0e
push id34164
push usercsabou@mozilla.com
push dateThu, 21 Jun 2018 01:17:13 +0000
treeherdermozilla-central@d231a3231680 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfelipe
bugs1452533
milestone62.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 1452533 - JsonSchemaValidator should output URL types as URL objects instead of nsIURIs. r=felipe
browser/components/enterprisepolicies/Policies.jsm
browser/components/enterprisepolicies/helpers/BookmarksPolicies.jsm
browser/components/enterprisepolicies/helpers/ProxyPolicies.jsm
browser/components/enterprisepolicies/tests/browser/browser_policy_bookmarks.js
browser/components/enterprisepolicies/tests/browser/browser_policy_proxy.js
toolkit/components/utils/JsonSchemaValidator.jsm
toolkit/components/utils/test/browser/browser_JsonSchemaValidator.js
--- a/browser/components/enterprisepolicies/Policies.jsm
+++ b/browser/components/enterprisepolicies/Policies.jsm
@@ -122,20 +122,20 @@ var Policies = {
     }
   },
 
   "Cookies": {
     onBeforeUIStartup(manager, param) {
       addAllowDenyPermissions("cookie", param.Allow, param.Block);
 
       if (param.Block) {
-        const hosts = param.Block.map(uri => uri.host).sort().join("\n");
+        const hosts = param.Block.map(url => url.hostname).sort().join("\n");
         runOncePerModification("clearCookiesForBlockedHosts", hosts, () => {
           for (let blocked of param.Block) {
-            Services.cookies.removeCookiesWithOriginAttributes("{}", blocked.host);
+            Services.cookies.removeCookiesWithOriginAttributes("{}", blocked.hostname);
           }
         });
       }
 
       if (param.Default !== undefined ||
           param.AcceptThirdParty !== undefined ||
           param.Locked) {
         const ACCEPT_COOKIES = 0;
@@ -503,19 +503,19 @@ var Policies = {
     }
   },
 
   "Homepage": {
     onBeforeUIStartup(manager, param) {
       // |homepages| will be a string containing a pipe-separated ('|') list of
       // URLs because that is what the "Home page" section of about:preferences
       // (and therefore what the pref |browser.startup.homepage|) accepts.
-      let homepages = param.URL.spec;
+      let homepages = param.URL.href;
       if (param.Additional && param.Additional.length > 0) {
-        homepages += "|" + param.Additional.map(url => url.spec).join("|");
+        homepages += "|" + param.Additional.map(url => url.href).join("|");
       }
       if (param.Locked) {
         setAndLockPref("browser.startup.homepage", homepages);
         setAndLockPref("browser.startup.page", 1);
         setAndLockPref("pref.browser.homepage.disable_button.current_page", true);
         setAndLockPref("pref.browser.homepage.disable_button.bookmark_page", true);
         setAndLockPref("pref.browser.homepage.disable_button.restore_default", true);
       } else {
@@ -558,24 +558,24 @@ var Policies = {
   "OfferToSaveLogins": {
     onBeforeUIStartup(manager, param) {
       setAndLockPref("signon.rememberSignons", param);
     }
   },
 
   "OverrideFirstRunPage": {
     onProfileAfterChange(manager, param) {
-      let url = param ? param.spec : "";
+      let url = param ? param.href : "";
       setAndLockPref("startup.homepage_welcome_url", url);
     }
   },
 
   "OverridePostUpdatePage": {
     onProfileAfterChange(manager, param) {
-      let url = param ? param.spec : "";
+      let url = param ? param.href : "";
       setAndLockPref("startup.homepage_override_url", url);
       // The pref startup.homepage_override_url is only used
       // as a fallback when the update.xml file hasn't provided
       // a specific post-update URL.
       manager.disallowFeature("postUpdateCustomPage");
     }
   },
 
@@ -852,28 +852,28 @@ function setDefaultPermission(policyName
  *        The list of URLs to be set as DENY_ACTION for the chosen permission.
  */
 function addAllowDenyPermissions(permissionName, allowList, blockList) {
   allowList = allowList || [];
   blockList = blockList || [];
 
   for (let origin of allowList) {
     try {
-      Services.perms.add(origin,
+      Services.perms.add(Services.io.newURI(origin.href),
                          permissionName,
                          Ci.nsIPermissionManager.ALLOW_ACTION,
                          Ci.nsIPermissionManager.EXPIRE_POLICY);
     } catch (ex) {
       log.error(`Added by default for ${permissionName} permission in the permission
-      manager - ${origin.spec}`);
+      manager - ${origin.href}`);
     }
   }
 
   for (let origin of blockList) {
-    Services.perms.add(origin,
+    Services.perms.add(Services.io.newURI(origin.href),
                        permissionName,
                        Ci.nsIPermissionManager.DENY_ACTION,
                        Ci.nsIPermissionManager.EXPIRE_POLICY);
   }
 }
 
 /**
  * runOnce
--- a/browser/components/enterprisepolicies/helpers/BookmarksPolicies.jsm
+++ b/browser/components/enterprisepolicies/helpers/BookmarksPolicies.jsm
@@ -3,43 +3,43 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 /*
  * A Bookmark object received through the policy engine will be an
  * object with the following properties:
  *
- * - URL (nsIURI)
+ * - URL (URL)
  *   (required) The URL for this bookmark
  *
  * - Title (string)
  *   (required) The title for this bookmark
  *
  * - Placement (string)
  *   (optional) Either "toolbar" or "menu". If missing or invalid,
  *   "toolbar" will be used
  *
  * - Folder (string)
  *   (optional) The name of the folder to put this bookmark into.
  *   If present, a folder with this name will be created in the
  *   chosen placement above, and the bookmark will be created there.
  *   If missing, the bookmark will be created directly into the
  *   chosen placement.
  *
- * - Favicon (nsIURI)
+ * - Favicon (URL)
  *   (optional) An http:, https: or data: URL with the favicon.
  *   If possible, we recommend against using this property, in order
  *   to keep the json file small.
  *   If a favicon is not provided through the policy, it will be loaded
  *   naturally after the user first visits the bookmark.
  *
  *
  * Note: The Policy Engine automatically converts the strings given to
- * the URL and favicon properties into a nsIURI object.
+ * the URL and favicon properties into a URL object.
  *
  * The schema for this object is defined in policies-schema.json.
  */
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 ChromeUtils.defineModuleGetter(this, "PlacesUtils",
@@ -104,17 +104,17 @@ async function calculateLists(specifiedB
   // --------- STEP 1 ---------
   // Build two Maps (one with the existing bookmarks, another with
   // the specified bookmarks), to make iteration quicker.
 
   // LIST A
   // MAP of url (string) -> bookmarks objects from the Policy Engine
   let specifiedBookmarksMap = new Map();
   for (let bookmark of specifiedBookmarks) {
-    specifiedBookmarksMap.set(bookmark.URL.spec, bookmark);
+    specifiedBookmarksMap.set(bookmark.URL.href, bookmark);
   }
 
   // LIST B
   // MAP of url (string) -> bookmarks objects from Places
   let existingBookmarksMap = new Map();
   await PlacesUtils.bookmarks.fetch(
     { guidPrefix: BookmarksPolicies.BOOKMARK_GUID_PREFIX },
     (bookmark) => existingBookmarksMap.set(bookmark.url.href, bookmark)
@@ -188,60 +188,60 @@ async function calculateLists(specifiedB
   };
 }
 
 async function insertBookmark(bookmark) {
   let parentGuid = await getParentGuid(bookmark.Placement,
                                        bookmark.Folder);
 
   await PlacesUtils.bookmarks.insert({
-    url: bookmark.URL,
+    url: Services.io.newURI(bookmark.URL.href),
     title: bookmark.Title,
     guid: generateGuidWithPrefix(BookmarksPolicies.BOOKMARK_GUID_PREFIX),
     parentGuid,
   });
 
   if (bookmark.Favicon) {
     await setFaviconForBookmark(bookmark).catch(
       () => log.error(`Error setting favicon for ${bookmark.Title}`));
   }
 }
 
 async function setFaviconForBookmark(bookmark) {
   let faviconURI;
   let nullPrincipal = Services.scriptSecurityManager.createNullPrincipal({});
 
-  switch (bookmark.Favicon.scheme) {
-    case "data":
+  switch (bookmark.Favicon.protocol) {
+    case "data:":
       // data urls must first call replaceFaviconDataFromDataURL, using a
       // fake URL. Later, it's needed to call setAndFetchFaviconForPage
       // with the same URL.
-      faviconURI = Services.io.newURI("fake-favicon-uri:" + bookmark.URL.spec);
+      faviconURI = Services.io.newURI("fake-favicon-uri:" + bookmark.URL.href);
 
       PlacesUtils.favicons.replaceFaviconDataFromDataURL(
         faviconURI,
-        bookmark.Favicon.spec,
+        bookmark.Favicon.href,
         0, /* max expiration length */
         nullPrincipal
       );
       break;
 
-    case "http":
-    case "https":
-      faviconURI = bookmark.Favicon;
+    case "http:":
+    case "https:":
+      faviconURI = Services.io.newURI(bookmark.Favicon.href);
       break;
 
     default:
       log.error(`Bad URL given for favicon on bookmark "${bookmark.Title}"`);
       return Promise.resolve();
   }
 
   return new Promise(resolve => {
     PlacesUtils.favicons.setAndFetchFaviconForPage(
-      bookmark.URL,
+      Services.io.newURI(bookmark.URL.href),
       faviconURI,
       false, /* forceReload */
       PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
       resolve,
       nullPrincipal
     );
   });
 }
--- a/browser/components/enterprisepolicies/helpers/ProxyPolicies.jsm
+++ b/browser/components/enterprisepolicies/helpers/ProxyPolicies.jsm
@@ -35,17 +35,17 @@ var EXPORTED_SYMBOLS = [ "ProxyPolicies"
 
 var ProxyPolicies = {
   configureProxySettings(param, setPref) {
     if (param.Mode) {
       setPref("network.proxy.type", PROXY_TYPES_MAP.get(param.Mode));
     }
 
     if (param.AutoConfigURL) {
-      setPref("network.proxy.autoconfig_url", param.AutoConfigURL.spec);
+      setPref("network.proxy.autoconfig_url", param.AutoConfigURL.href);
     }
 
     if (param.UseProxyForDNS !== undefined) {
       setPref("network.proxy.socks_remote_dns", param.UseProxyForDNS);
     }
 
     if (param.AutoLogin !== undefined) {
       setPref("signon.autologin.proxy", param.AutoLogin);
--- a/browser/components/enterprisepolicies/tests/browser/browser_policy_bookmarks.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_bookmarks.js
@@ -10,17 +10,17 @@ ChromeUtils.import("resource://gre/modul
 const FAVICON_DATA = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gwMDAsTBZbkNwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAABNElEQVQ4y8WSsU0DURBE3yyWIaAJaqAAN4DPSL6AlIACKIEOyJEgRsIgOOkiInJqgAKowNg7BHdn7MOksNl+zZ//dvbDf5cAiklp22BdVtXdeTEpDYDB9m1VzU6OJuVp2NdEQCaI96fH2YHG4+mDduKYNMYINTcjcGbXzQVDEAphG0k48zUsajIbnAiMIXThpW8EICE0RAK4dvoKg9NIcTiQ589otyHOZLnwqK5nLwBFUZ4igc3iM0d1ff8CMC6mZ6Ihiaqq3gi1aUAnArD00SW1fq5OLBg0ymYmSZsR2/t4e/rGyCLW0sbp3oq+yTYqVgytQWui2FS7XYF7GFprY921T4CNQt8zr47dNzCkIX7y/jBtH+v+RGMQrc828W8pApnZbmEVQp/Ae7BlOy2ttib81/UFc+WRWEbjckIAAAAASUVORK5CYII=";
 
 const { BookmarksPolicies } = ChromeUtils.import("resource:///modules/policies/BookmarksPolicies.jsm", {});
 
 let CURRENT_POLICY;
 
 const BASE_POLICY = {
   "policies": {
-    "display_bookmarks_toolbar": true,
+    "DisplayBookmarksToolbar": true,
     "Bookmarks": [
       {
         "Title": "Bookmark 1",
         "URL": "https://bookmark1.example.com/",
         "Favicon": FAVICON_DATA
       },
       {
         "Title": "Bookmark 2",
--- a/browser/components/enterprisepolicies/tests/browser/browser_policy_proxy.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_proxy.js
@@ -11,19 +11,19 @@ add_task(async function test_proxy_modes
   let { ProxyPolicies, PROXY_TYPES_MAP } = ChromeUtils.import("resource:///modules/policies/ProxyPolicies.jsm", {});
 
   for (let [mode, expectedValue] of PROXY_TYPES_MAP) {
     ProxyPolicies.configureProxySettings({Mode: mode}, (_, value) => {
       is(value, expectedValue, "Correct proxy mode");
     });
   }
 
-  let autoconfigURL = Services.io.newURI("data:text/plain,test");
+  let autoconfigURL = new URL("data:text/plain,test");
   ProxyPolicies.configureProxySettings({AutoConfigURL: autoconfigURL}, (_, value) => {
-    is(value, autoconfigURL.spec, "AutoconfigURL correctly set");
+    is(value, autoconfigURL.href, "AutoconfigURL correctly set");
   });
 });
 
 add_task(async function test_proxy_boolean_settings() {
   // Tests that both false and true values are correctly set and locked
   await setupPolicyEngineWithJson({
     "policies": {
       "Proxy": {
--- a/toolkit/components/utils/JsonSchemaValidator.jsm
+++ b/toolkit/components/utils/JsonSchemaValidator.jsm
@@ -12,16 +12,18 @@
  * - The boolean type accepts (and casts) 0 and 1 as valid values.
  */
 
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
+XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
+
 XPCOMUtils.defineLazyGetter(this, "log", () => {
   let { ConsoleAPI } = ChromeUtils.import("resource://gre/modules/Console.jsm", {});
   return new ConsoleAPI({
     prefix: "JsonSchemaValidator.jsm",
     // tip: set maxLogLevel to "debug" and use log.debug() to create detailed
     // messages during development. See LOG_LEVELS in Console.jsm for details.
     maxLogLevel: "error",
   });
@@ -151,19 +153,19 @@ function validateAndParseSimpleParam(par
       break;
 
     case "origin":
       if (typeof(param) != "string") {
         break;
       }
 
       try {
-        parsedParam = Services.io.newURI(param);
+        parsedParam = new URL(param);
 
-        let pathQueryRef = parsedParam.pathQueryRef;
+        let pathQueryRef = parsedParam.pathname + parsedParam.hash;
         // Make sure that "origin" types won't accept full URLs.
         if (pathQueryRef != "/" && pathQueryRef != "") {
           valid = false;
         } else {
           valid = true;
         }
       } catch (ex) {
         valid = false;
@@ -177,17 +179,17 @@ function validateAndParseSimpleParam(par
       }
 
       if (type == "URLorEmpty" && param === "") {
         valid = true;
         break;
       }
 
       try {
-        parsedParam = Services.io.newURI(param);
+        parsedParam = new URL(param);
         valid = true;
       } catch (ex) {
         valid = false;
       }
       break;
   }
 
   return [valid, parsedParam];
--- a/toolkit/components/utils/test/browser/browser_JsonSchemaValidator.js
+++ b/toolkit/components/utils/test/browser/browser_JsonSchemaValidator.js
@@ -85,38 +85,38 @@ add_task(async function test_string_valu
 add_task(async function test_URL_values() {
   let schema = {
     type: "URL"
   };
 
   let valid, parsed;
   [valid, parsed] = JsonSchemaValidator.validateAndParseParameters("https://www.example.com/foo#bar", schema);
   ok(valid, "URL is valid");
-  ok(parsed instanceof Ci.nsIURI, "parsed is a nsIURI");
-  is(parsed.prePath, "https://www.example.com", "prePath is correct");
-  is(parsed.pathQueryRef, "/foo#bar", "pathQueryRef is correct");
+  ok(parsed instanceof URL, "parsed is a URL");
+  is(parsed.origin, "https://www.example.com", "origin is correct");
+  is(parsed.pathname + parsed.hash, "/foo#bar", "pathname is correct");
 
   // Invalid values:
   ok(!JsonSchemaValidator.validateAndParseParameters("", schema)[0], "Empty string is not accepted for URL");
   ok(!JsonSchemaValidator.validateAndParseParameters("www.example.com", schema)[0], "Scheme is required for URL");
   ok(!JsonSchemaValidator.validateAndParseParameters("https://:!$%", schema)[0], "Invalid URL");
   ok(!JsonSchemaValidator.validateAndParseParameters({}, schema)[0], "Invalid value");
 });
 
 add_task(async function test_URLorEmpty_values() {
   let schema = {
     type: "URLorEmpty"
   };
 
   let valid, parsed;
   [valid, parsed] = JsonSchemaValidator.validateAndParseParameters("https://www.example.com/foo#bar", schema);
   ok(valid, "URL is valid");
-  ok(parsed instanceof Ci.nsIURI, "parsed is a nsIURI");
-  is(parsed.prePath, "https://www.example.com", "prePath is correct");
-  is(parsed.pathQueryRef, "/foo#bar", "pathQueryRef is correct");
+  ok(parsed instanceof URL, "parsed is a nsIURI");
+  is(parsed.origin, "https://www.example.com", "origin is correct");
+  is(parsed.pathname + parsed.hash, "/foo#bar", "pathname is correct");
 
   // Test that this type also accept empty strings
   [valid, parsed] = JsonSchemaValidator.validateAndParseParameters("", schema);
   ok(valid, "URLorEmpty is valid");
   ok(!parsed, "parsed value is falsy");
   is(typeof(parsed), "string", "parsed is a string");
   is(parsed, "", "parsed is an empty string");
 
@@ -132,19 +132,19 @@ add_task(async function test_origin_valu
   // Origin is a URL that doesn't contain a path/query string (i.e., it's only scheme + host + port)
   let schema = {
     type: "origin"
   };
 
   let valid, parsed;
   [valid, parsed] = JsonSchemaValidator.validateAndParseParameters("https://www.example.com", schema);
   ok(valid, "Origin is valid");
-  ok(parsed instanceof Ci.nsIURI, "parsed is a nsIURI");
-  is(parsed.prePath, "https://www.example.com", "prePath is correct");
-  is(parsed.pathQueryRef, "/", "pathQueryRef is corect");
+  ok(parsed instanceof URL, "parsed is a nsIURI");
+  is(parsed.origin, "https://www.example.com", "origin is correct");
+  is(parsed.pathname + parsed.hash, "/", "pathname is corect");
 
   // Invalid values:
   ok(!JsonSchemaValidator.validateAndParseParameters("https://www.example.com/foobar", schema)[0], "Origin cannot contain a path part");
   ok(!JsonSchemaValidator.validateAndParseParameters("https://:!$%", schema)[0], "Invalid origin");
   ok(!JsonSchemaValidator.validateAndParseParameters({}, schema)[0], "Invalid value");
 });
 
 add_task(async function test_array_values() {
@@ -193,18 +193,18 @@ add_task(async function test_object_valu
       url: "https://www.example.com/foo#bar",
       title: "Foo",
       alias: "Bar"
     },
     schema);
 
   ok(valid, "Object is valid");
   ok(typeof(parsed) == "object", "parsed in an object");
-  ok(parsed.url instanceof Ci.nsIURI, "types inside the object are also parsed");
-  is(parsed.url.spec, "https://www.example.com/foo#bar", "URL was correctly parsed");
+  ok(parsed.url instanceof URL, "types inside the object are also parsed");
+  is(parsed.url.href, "https://www.example.com/foo#bar", "URL was correctly parsed");
   is(parsed.title, "Foo", "title was correctly parsed");
   is(parsed.alias, undefined, "property not described in the schema is not present in the parsed object");
 
   // Invalid values:
   ok(!JsonSchemaValidator.validateAndParseParameters(
     {
       url: "https://www.example.com/foo#bar",
       title: 3,
@@ -248,18 +248,18 @@ add_task(async function test_array_of_ob
     }],
     schema);
 
   ok(valid, "Array is valid");
   is(parsed.length, 2, "Correct number of items");
 
   ok(typeof(parsed[0]) == "object" && typeof(parsed[1]) == "object", "Correct objects inside array");
 
-  is(parsed[0].url.spec, "https://www.example.com/bookmark1", "Correct URL for bookmark 1");
-  is(parsed[1].url.spec, "https://www.example.com/bookmark2", "Correct URL for bookmark 2");
+  is(parsed[0].url.href, "https://www.example.com/bookmark1", "Correct URL for bookmark 1");
+  is(parsed[1].url.href, "https://www.example.com/bookmark2", "Correct URL for bookmark 2");
 
   is(parsed[0].title, "Foo", "Correct title for bookmark 1");
   is(parsed[1].title, "Bar", "Correct title for bookmark 2");
 });
 
 add_task(async function test_missing_arrays_inside_objects() {
   let schema = {
     type: "object",