Bug 1287658 - Implement migration from mimeTypes.rdf to the JSON Handler Store. r?Paolo draft
authorAlphan Chen <alchen@mozilla.com>
Wed, 15 Mar 2017 15:17:59 +0800
changeset 498757 0e98afb44a8e04fa585335b8768953dcbd92a4a1
parent 498756 7eae2847b3792897e6941b848581fbe66ec46d2c
child 549241 395eb0a7185eee21f793d6165819fb4edd0b4c67
push id49296
push useralchen@mozilla.com
push dateWed, 15 Mar 2017 08:09:26 +0000
reviewersPaolo
bugs1287658
milestone55.0a1
Bug 1287658 - Implement migration from mimeTypes.rdf to the JSON Handler Store. r?Paolo MozReview-Commit-ID: 6BxgOxhgrew
uriloader/exthandler/nsHandlerService-json.js
uriloader/exthandler/nsHandlerService-json.manifest
uriloader/exthandler/nsHandlerService.manifest
uriloader/exthandler/tests/unit/mimeTypesAndroid.rdf
uriloader/exthandler/tests/unit/test_handlerService.js
uriloader/exthandler/tests/unit/test_handlerService_json.js
uriloader/exthandler/tests/unit/test_handlerService_migration.js
uriloader/exthandler/tests/unit/test_handlerService_rdf.js
uriloader/exthandler/tests/unit/xpcshell.ini
--- a/uriloader/exthandler/nsHandlerService-json.js
+++ b/uriloader/exthandler/nsHandlerService-json.js
@@ -9,16 +9,22 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "JSONFile",
                                   "resource://gre/modules/JSONFile.jsm");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gDirService",
+                                   "@mozilla.org/file/directory_service;1",
+                                   "nsIProperties");
+XPCOMUtils.defineLazyServiceGetter(this, "gHandlerServiceRDF",
+                                   "@mozilla.org/uriloader/handler-service-rdf;1",
+                                   "nsIHandlerService");
 XPCOMUtils.defineLazyServiceGetter(this, "gExternalProtocolService",
                                    "@mozilla.org/uriloader/external-protocol-service;1",
                                    "nsIExternalProtocolService");
 XPCOMUtils.defineLazyServiceGetter(this, "gMIMEService",
                                    "@mozilla.org/mime;1",
                                    "nsIMIMEService");
 
 function HandlerService() {
@@ -39,25 +45,55 @@ HandlerService.prototype = {
   get _store() {
     if (!this.__store) {
       this.__store = new JSONFile({
         path: OS.Path.join(OS.Constants.Path.profileDir,
                            "handlers.json"),
         dataPostProcessor: this._dataPostProcessor.bind(this),
       });
       this.__store.ensureDataReady();
+      this._migration();
       this._updateDB();
     }
     return this.__store;
   },
 
   _dataPostProcessor(data) {
     return data.schemes ? data : { version: {}, mimetypes: {}, schemes: {} };
   },
 
+  _migration() {
+    try {
+      if (Services.prefs.getBoolPref("gecko.handlerService.migrated")) {
+        return;
+      }
+    } catch (ex) {
+      // If the preference does not exist, we need to import.
+    }
+
+    let file = new FileUtils.File(gDirService.get("UMimTyp", Ci.nsIFile).path);
+    if (!file.exists()) {
+      return;
+    }
+
+    let handlerInfos = gHandlerServiceRDF.enumerate();
+    while (handlerInfos.hasMoreElements()) {
+      let handlerInfo = handlerInfos.getNext().QueryInterface(Ci.nsIHandlerInfo);
+      try {
+        gHandlerServiceRDF.fillHandlerInfo(handlerInfo, null);
+        this.store(handlerInfo);
+      } catch(ex) {
+        Cu.reportError(ex);
+      }
+    }
+
+    // We won't attempt import again on next startup.
+    Services.prefs.setBoolPref("gecko.handlerService.migrated", true);
+  },
+
   _updateDB() {
     try {
 
       let locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
                      .getService(Ci.nsIXULChromeRegistry)
                      .getSelectedLocale("global");
       let prefsDefaultHandlersVersion = Number(Services.prefs.getComplexValue(
         "gecko.handlerService.defaultHandlersVersion",
--- a/uriloader/exthandler/nsHandlerService-json.manifest
+++ b/uriloader/exthandler/nsHandlerService-json.manifest
@@ -1,2 +1,2 @@
 component {220cc253-b60f-41f6-b9cf-fdcb325f970f} nsHandlerService-json.js
-contract @mozilla.org/uriloader/handler-service-json;1 {220cc253-b60f-41f6-b9cf-fdcb325f970f} process=main
+contract @mozilla.org/uriloader/handler-service;1 {220cc253-b60f-41f6-b9cf-fdcb325f970f} process=main
--- a/uriloader/exthandler/nsHandlerService.manifest
+++ b/uriloader/exthandler/nsHandlerService.manifest
@@ -1,2 +1,2 @@
 component {32314cc8-22f7-4f7f-a645-1a45453ba6a6} nsHandlerService.js
-contract @mozilla.org/uriloader/handler-service;1 {32314cc8-22f7-4f7f-a645-1a45453ba6a6} process=main
\ No newline at end of file
+contract @mozilla.org/uriloader/handler-service-rdf;1 {32314cc8-22f7-4f7f-a645-1a45453ba6a6} process=main
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/tests/unit/mimeTypesAndroid.rdf
@@ -0,0 +1,79 @@
+<?xml version="1.0"?>
+<RDF:RDF xmlns:NC="http://home.netscape.com/NC-rdf#"
+         xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+  <RDF:Description RDF:about="urn:handler:web:https://compose.mail.yahoo.com/?To=%s"
+                   NC:prettyName="Yahoo! Mail"
+                   NC:uriTemplate="https://compose.mail.yahoo.com/?To=%s" />
+  <RDF:Description RDF:about="urn:mimetype:application/pdf"
+                   NC:value="application/pdf"
+                   NC:fileExtensions="pdf">
+    <NC:handlerProp RDF:resource="urn:mimetype:handler:application/pdf"/>
+  </RDF:Description>
+  <RDF:Description RDF:about="urn:mimetype:handler:mailto"
+                   NC:useSystemDefault="true"
+                   NC:alwaysAsk="false">
+    <NC:possibleApplication RDF:resource="urn:handler:web:https://compose.mail.yahoo.com/?To=%s"/>
+    <NC:possibleApplication RDF:resource="urn:handler:web:https://mail.google.com/mail/?extsrc=mailto&amp;url=%s"/>
+  </RDF:Description>
+  <RDF:Description RDF:about="urn:root"
+                   NC:en-US_defaultHandlersVersion="999" />
+  <RDF:Description RDF:about="urn:mimetype:irc"
+                   NC:value="irc">
+    <NC:handlerProp RDF:resource="urn:mimetype:handler:irc"/>
+  </RDF:Description>
+  <RDF:Description RDF:about="urn:mimetype:mailto"
+                   NC:value="mailto">
+    <NC:handlerProp RDF:resource="urn:mimetype:handler:mailto"/>
+  </RDF:Description>
+  <RDF:Seq RDF:about="urn:mimetypes:root">
+  </RDF:Seq>
+  <RDF:Description RDF:about="urn:mimetype:webcal"
+                   NC:value="webcal">
+    <NC:handlerProp RDF:resource="urn:mimetype:handler:webcal"/>
+  </RDF:Description>
+  <RDF:Seq RDF:about="urn:mimetypes:root">
+    <RDF:li RDF:resource="urn:mimetype:application/pdf"/>
+    <RDF:li RDF:resource="urn:mimetype:webcal"/>
+    <RDF:li RDF:resource="urn:mimetype:ircs"/>
+    <RDF:li RDF:resource="urn:mimetype:mailto"/>
+    <RDF:li RDF:resource="urn:mimetype:irc"/>
+  </RDF:Seq>
+  <RDF:Description RDF:about="urn:handler:web:https://30boxes.com/external/widget?refer=ff&amp;url=%s"
+                   NC:prettyName="30 Boxes"
+                   NC:uriTemplate="https://30boxes.com/external/widget?refer=ff&amp;url=%s" />
+  <RDF:Description RDF:about="urn:mimetypes">
+    <NC:Protocol-Schemes RDF:resource="urn:mimetypes:root"/>
+  </RDF:Description>
+  <RDF:Description RDF:about="urn:handler:web:https://www.mibbit.com/?url=%s"
+                   NC:prettyName="Mibbit"
+                   NC:uriTemplate="https://www.mibbit.com/?url=%s" />
+  <RDF:Description RDF:about="urn:mimetype:handler:webcal"
+                   NC:alwaysAsk="true">
+    <NC:possibleApplication RDF:resource="urn:handler:web:https://30boxes.com/external/widget?refer=ff&amp;url=%s"/>
+    <NC:externalApplication RDF:resource="urn:mimetype:externalApplication:webcal"/>
+  </RDF:Description>
+  <RDF:Description RDF:about="urn:mimetype:handler:irc"
+                   NC:alwaysAsk="true">
+    <NC:possibleApplication RDF:resource="urn:handler:web:https://www.mibbit.com/?url=%s"/>
+  </RDF:Description>
+  <RDF:Description RDF:about="urn:handler:web:https://mail.google.com/mail/?extsrc=mailto&amp;url=%s"
+                   NC:prettyName="Gmail"
+                   NC:uriTemplate="https://mail.google.com/mail/?extsrc=mailto&amp;url=%s" />
+  <RDF:Description RDF:about="urn:mimetype:handler:application/pdf"
+                   NC:handleInternal="true"
+                   NC:alwaysAsk="false" />
+  <RDF:Description RDF:about="urn:mimetypes">
+    <NC:MIME-types RDF:resource="urn:mimetypes:root"/>
+  </RDF:Description>
+  <RDF:Description RDF:about="urn:mimetype:externalApplication:webcal"
+                   NC:prettyName="30 Boxes"
+                   NC:uriTemplate="http://30boxes.com/external/widget?refer=ff&amp;url=%s"/>
+  <RDF:Description RDF:about="urn:mimetype:ircs"
+                   NC:value="ircs">
+    <NC:handlerProp RDF:resource="urn:mimetype:handler:ircs"/>
+  </RDF:Description>
+  <RDF:Description RDF:about="urn:mimetype:handler:ircs"
+                   NC:alwaysAsk="true">
+    <NC:possibleApplication RDF:resource="urn:handler:web:https://www.mibbit.com/?url=%s"/>
+  </RDF:Description>
+</RDF:RDF>
--- a/uriloader/exthandler/tests/unit/test_handlerService.js
+++ b/uriloader/exthandler/tests/unit/test_handlerService.js
@@ -426,41 +426,23 @@ function run_test() {
 
   // add a handler for the extension
   var lolHandler = mimeSvc.getFromTypeAndExtension("application/lolcat", null);
 
   do_check_false(lolHandler.extensionExists("lolcat"));
   lolHandler.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
   lolHandler.preferredApplicationHandler = localHandler;
   lolHandler.alwaysAskBeforeHandling = false;
+  lolHandler.appendExtension("lolcat");
 
   // store the handler
   do_check_false(handlerSvc.exists(lolHandler));
   handlerSvc.store(lolHandler);
   do_check_true(handlerSvc.exists(lolHandler));
 
-  // Get a file:// string pointing to mimeTypes.rdf
-  var rdfFile = HandlerServiceTest._dirSvc.get("UMimTyp", Ci.nsIFile);
-  var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler);
-  var rdfFileURI = fileHandler.getURLSpecFromFile(rdfFile);
-
-  // Assign a file extenstion to the handler. handlerSvc.store() doesn't
-  // actually store any file extensions added with setFileExtensions(), you
-  // have to wade into RDF muck to do so.
-
-  // Based on toolkit/mozapps/downloads/content/helperApps.js :: addExtension()
-  var gRDF = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
-  var mimeSource    = gRDF.GetUnicodeResource("urn:mimetype:application/lolcat");
-  var valueProperty = gRDF.GetUnicodeResource("http://home.netscape.com/NC-rdf#fileExtensions");
-  var mimeLiteral   = gRDF.GetLiteral("lolcat");
-
-  var DS = gRDF.GetDataSourceBlocking(rdfFileURI);
-  DS.Assert(mimeSource, valueProperty, mimeLiteral, true);
-
-
   // test now-existent extension
   lolType = handlerSvc.getTypeFromExtension("lolcat");
   do_check_eq(lolType, "application/lolcat");
 
   // test mailcap entries with needsterminal are ignored on non-Windows non-Mac.
   if (mozinfo.os != "win" && mozinfo.os != "mac") {
     env.set('PERSONAL_MAILCAP', do_get_file('mailcap').path);
     handlerInfo = mimeSvc.getFromTypeAndExtension("text/plain", null);
--- a/uriloader/exthandler/tests/unit/test_handlerService_json.js
+++ b/uriloader/exthandler/tests/unit/test_handlerService_json.js
@@ -10,17 +10,17 @@
 "use strict"
 
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gHandlerService",
-                                   "@mozilla.org/uriloader/handler-service-json;1",
+                                   "@mozilla.org/uriloader/handler-service;1",
                                    "nsIHandlerService");
 
 var scriptFile = do_get_file("common_test_handlerService.js");
 Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec);
 
 var prepareImportDB = Task.async(function* () {
   yield reloadData();
 
@@ -33,14 +33,16 @@ var removeImportDB = Task.async(function
   yield reloadData();
 
   let dst = OS.Path.join(OS.Constants.Path.profileDir, "handlers.json");
   yield OS.File.remove(dst);
   Assert.ok(!(yield OS.File.exists(dst)), "should not have a DB now");
 });
 
 var reloadData = Task.async(function* () {
+  // prevent migration
+  Services.prefs.setBoolPref("gecko.handlerService.migrated", true);
   // Force the initialization of handlerService to prevent observer is not initialized yet.
   let svc = gHandlerService;
   let promise = TestUtils.topicObserved("handlersvc-json-replace-complete");
   Services.obs.notifyObservers(null, "handlersvc-json-replace", null);
   yield promise;
 });
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/tests/unit/test_handlerService_migration.js
@@ -0,0 +1,254 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests the migration functionality of handlerService.
+ */
+
+"use strict"
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
+Cu.import("resource://gre/modules/osfile.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://testing-common/TestUtils.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "gMIMEService",
+                                   "@mozilla.org/mime;1",
+                                   "nsIMIMEService");
+XPCOMUtils.defineLazyServiceGetter(this, "gExternalProtocolService",
+                                   "@mozilla.org/uriloader/external-protocol-service;1",
+                                   "nsIExternalProtocolService");
+XPCOMUtils.defineLazyServiceGetter(this, "gHandlerServiceRDF",
+                                   "@mozilla.org/uriloader/handler-service-rdf;1",
+                                   "nsIHandlerService");
+XPCOMUtils.defineLazyServiceGetter(this, "gHandlerService",
+                                   "@mozilla.org/uriloader/handler-service;1",
+                                   "nsIHandlerService");
+
+const pdfHandlerInfo = gMIMEService.getFromTypeAndExtension("application/pdf", null);
+const gzipHandlerInfo = gMIMEService.getFromTypeAndExtension("application/x-gzip", null);
+
+let executable = HandlerServiceTest._dirSvc.get("TmpD", Ci.nsIFile);
+let localHandler = {
+  name: "Local Handler",
+  executable: executable,
+  interfaces: [Ci.nsIHandlerApp, Ci.nsILocalHandlerApp, Ci.nsISupports],
+  QueryInterface: function(iid) {
+    if (!this.interfaces.some( function(v) { return iid.equals(v) } ))
+      throw Cr.NS_ERROR_NO_INTERFACE;
+    return this;
+  }
+};
+
+let webHandler = {
+  name: "Web Handler",
+  uriTemplate: "https://www.webhandler.com/?url=%s",
+  interfaces: [Ci.nsIHandlerApp, Ci.nsIWebHandlerApp, Ci.nsISupports],
+  QueryInterface: function(iid) {
+    if (!this.interfaces.some( function(v) { return iid.equals(v) } ))
+      throw Cr.NS_ERROR_NO_INTERFACE;
+    return this;
+  }
+};
+
+var prepareImportRDF = Task.async(function* () {
+  HandlerServiceTest._deleteDatasourceFile();
+  let dst = HandlerServiceTest._dirSvc.get("UMimTyp", Ci.nsIFile);
+  Assert.ok(!(yield OS.File.exists(dst.path)), "should not have a DB now");
+
+  // Force the initialization of handlerService to prevent observer is not initialized yet.
+  let svc = gHandlerServiceRDF;
+  let promise = TestUtils.topicObserved("handlersvc-rdf-replace-complete");
+  Services.obs.notifyObservers(null, "handlersvc-rdf-replace", null);
+  yield promise;
+
+  if (Services.appinfo.widgetToolkit == "android") {
+    yield OS.File.copy(do_get_file("mimeTypesAndroid.rdf").path, dst.path);
+  } else {
+    yield OS.File.copy(do_get_file("mimeTypes.rdf").path, dst.path);
+  }
+
+  Assert.ok((yield OS.File.exists(dst.path)), "should have a DB now");
+});
+
+var removeExistingJSON = Task.async(function* () {
+  yield reloadData();
+
+  let dst = OS.Path.join(OS.Constants.Path.profileDir, "handlers.json");
+  yield OS.File.remove(dst);
+  Assert.ok(!(yield OS.File.exists(dst)), "should not have a DB now");
+});
+
+var reloadData = Task.async(function* () {
+  // Force the initialization of handlerService to prevent observer is not initialized yet.
+  let svc = gHandlerService;
+  let promise = TestUtils.topicObserved("handlersvc-json-replace-complete");
+  Services.obs.notifyObservers(null, "handlersvc-json-replace", null);
+  yield promise;
+});
+
+function run_test() {
+  do_get_profile();
+  run_next_test();
+}
+
+function getAllTypesByEnumerate() {
+  let handlerInfos = gHandlerService.enumerate();
+  let types = [];
+  while (handlerInfos.hasMoreElements()) {
+    let handlerInfo = handlerInfos.getNext().QueryInterface(Ci.nsIHandlerInfo);
+    types.push(handlerInfo.type);
+  }
+  return types.sort();
+}
+
+function compareDetailByEnumerate() {
+  let handlerInfos = gHandlerServiceRDF.enumerate();
+  let types = [];
+  while (handlerInfos.hasMoreElements()) {
+    let handlerInfoFromRDF = handlerInfos.getNext().QueryInterface(Ci.nsIHandlerInfo);
+    let handlerInfoFromJSON;
+    if (handlerInfoFromRDF.type == "application/pdf") {
+      handlerInfoFromJSON = gMIMEService.getFromTypeAndExtension(handlerInfoFromRDF.type, null);
+    } else {
+      handlerInfoFromJSON = gExternalProtocolService.getProtocolHandlerInfo(handlerInfoFromRDF.type, null);
+    }
+    do_check_eq(handlerInfoFromRDF.preferredAction, handlerInfoFromJSON.preferredAction);
+    do_check_eq(handlerInfoFromRDF.alwaysAskBeforeHandling,
+                handlerInfoFromJSON.alwaysAskBeforeHandling);
+    if (handlerInfoFromRDF.preferredApplicationHandler) {
+      do_check_eq(handlerInfoFromRDF.preferredApplicationHandler.name,
+                  handlerInfoFromJSON.preferredApplicationHandler.name);
+    }
+    do_check_eq(handlerInfoFromRDF.possibleApplicationHandlers.length,
+                handlerInfoFromJSON.possibleApplicationHandlers.length);
+  }
+}
+
+add_task(function* testMigration() {
+  // I. test the basic (JSON DS migrates from RDF DS)
+  yield prepareImportRDF();
+  yield removeExistingJSON();
+  Services.prefs.setBoolPref("gecko.handlerService.migrated", false);
+  Assert.deepEqual(getAllTypesByEnumerate(),
+                   ["application/pdf", "irc", "ircs", "mailto", "webcal"]);
+  do_check_true(Services.prefs.getBoolPref("gecko.handlerService.migrated"));
+
+  // II. Do modification on JSON DS and force reloading again.
+  gHandlerService.remove(pdfHandlerInfo);
+  yield reloadData();
+  Assert.deepEqual(getAllTypesByEnumerate(),
+                   ["irc", "ircs", "mailto", "webcal"]);
+
+  // III. Force migration again by setting the preference to false
+  Services.prefs.setBoolPref("gecko.handlerService.migrated", false);
+  yield reloadData();
+  Assert.deepEqual(getAllTypesByEnumerate(),
+                   ["application/pdf", "irc", "ircs", "mailto", "webcal"]);
+
+  // IV. Do modification on RDF DS and force migration again without removing JSON DS.
+  gHandlerServiceRDF.store(gzipHandlerInfo);
+  gHandlerServiceRDF.remove(pdfHandlerInfo);
+  Services.prefs.setBoolPref("gecko.handlerService.migrated", false);
+  yield reloadData();
+  Assert.deepEqual(getAllTypesByEnumerate(),
+                   ["application/pdf","application/x-gzip", "irc", "ircs", "mailto", "webcal"]);
+
+  // V. Force migration again with existing JSON DB.
+  Services.prefs.setBoolPref("gecko.handlerService.migrated", false);
+  Assert.deepEqual(getAllTypesByEnumerate(),
+                   ["application/pdf","application/x-gzip", "irc", "ircs", "mailto", "webcal"]);
+
+  // VI. Reset JSON DB and do migration.
+  Services.prefs.setBoolPref("gecko.handlerService.migrated", false);
+  yield removeExistingJSON();
+  Assert.deepEqual(getAllTypesByEnumerate(),
+                   ["application/x-gzip", "irc", "ircs", "mailto", "webcal"]);
+});
+
+add_task(function* testMigrationDetail() {
+  yield prepareImportRDF();
+  Services.prefs.setBoolPref("gecko.handlerService.migrated", false);
+  yield removeExistingJSON();
+  Assert.deepEqual(getAllTypesByEnumerate(),
+                   ["application/pdf", "irc", "ircs", "mailto", "webcal"]);
+  compareDetailByEnumerate();
+
+  // mimeType
+  let mimeInfo = gMIMEService.getFromTypeAndExtension("nonexistent/type", null);
+  do_check_true(mimeInfo.alwaysAskBeforeHandling);
+  if (mimeInfo.possibleApplicationHandlers.length) {
+    let apps = mimeInfo.possibleApplicationHandlers.enumerate();
+    let app = apps.getNext().QueryInterface(Ci.nsIHandlerApp);
+    do_check_eq(app.name, "Android chooser");
+  } else {
+    do_check_eq(mimeInfo.preferredAction, Ci.nsIHandlerInfo.saveToDisk);
+  }
+
+  let storedHandlerInfo = gMIMEService.getFromTypeAndExtension("nonexistent/type", null);
+  storedHandlerInfo.preferredAction = Ci.nsIHandlerInfo.useSystemDefault;
+  storedHandlerInfo.preferredApplicationHandler = webHandler;
+  storedHandlerInfo.possibleApplicationHandlers.appendElement(localHandler, false);
+  storedHandlerInfo.possibleApplicationHandlers.appendElement(webHandler, false);
+  storedHandlerInfo.alwaysAskBeforeHandling = false;
+  gHandlerServiceRDF.store(storedHandlerInfo);
+
+  // protocol type
+  let osDefaultHandlerFound = {};
+  let protoInfo = gExternalProtocolService.getProtocolHandlerInfo("nonexistent",
+                                                                  osDefaultHandlerFound);
+  do_check_true(protoInfo.alwaysAskBeforeHandling);
+  if (protoInfo.possibleApplicationHandlers.length) {
+    let apps = protoInfo.possibleApplicationHandlers.enumerate();
+    let app = apps.getNext().QueryInterface(Ci.nsIHandlerApp);
+    do_check_eq(app.name, "Android chooser");
+  } else {
+    do_check_eq(protoInfo.preferredAction, Ci.nsIHandlerInfo.alwaysAsk);
+  }
+
+  let storedProtoInfo = gExternalProtocolService.getProtocolHandlerInfo("nonexistent",
+                                                                        osDefaultHandlerFound);
+  storedProtoInfo.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
+  storedProtoInfo.alwaysAskBeforeHandling = false;
+  storedProtoInfo.preferredApplicationHandler = webHandler;
+  storedProtoInfo.possibleApplicationHandlers.appendElement(webHandler, false);
+  gHandlerServiceRDF.store(storedProtoInfo);
+
+  // Force migration
+  Services.prefs.setBoolPref("gecko.handlerService.migrated", false);
+  yield reloadData();
+
+  // Get handlerInfo by fillHandlerInfo without overrideType
+  for (let handlerInfo of [mimeInfo, protoInfo]) {
+    let handlerInfo2 = storedProtoInfo;
+    if (handlerInfo.type == "nonexistent/type") {
+      handlerInfo2 = storedHandlerInfo;
+    }
+    gHandlerService.fillHandlerInfo(handlerInfo, null);
+    do_check_eq(handlerInfo.preferredAction, handlerInfo2.preferredAction);
+    do_check_eq(handlerInfo.alwaysAskBeforeHandling,
+                handlerInfo2.alwaysAskBeforeHandling);
+    do_check_eq(handlerInfo.preferredApplicationHandler.name,
+                handlerInfo2.preferredApplicationHandler.name);
+    let possibleHandlers = handlerInfo.possibleApplicationHandlers;
+    do_check_eq(possibleHandlers.length, handlerInfo2.possibleApplicationHandlers.length);
+    let apps = possibleHandlers.enumerate();
+    let app;
+    if (Services.appinfo.widgetToolkit == "android") {
+      app = apps.getNext().QueryInterface(Ci.nsIHandlerApp);
+      do_check_eq(app.name, "Android chooser");
+    }
+    app = apps.getNext().QueryInterface(Ci.nsIWebHandlerApp);
+    do_check_eq(app.name, webHandler.name);
+    do_check_eq(app.uriTemplate, webHandler.uriTemplate);
+    if (apps.hasMoreElements()) {
+      app = apps.getNext().QueryInterface(Ci.nsILocalHandlerApp);
+      do_check_eq(app.name, localHandler.name);
+      do_check_eq(app.executable.path, executable.path);
+    }
+  }
+});
--- a/uriloader/exthandler/tests/unit/test_handlerService_rdf.js
+++ b/uriloader/exthandler/tests/unit/test_handlerService_rdf.js
@@ -9,17 +9,17 @@
 
 "use strict"
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gHandlerService",
-                                   "@mozilla.org/uriloader/handler-service;1",
+                                   "@mozilla.org/uriloader/handler-service-rdf;1",
                                    "nsIHandlerService");
 
 var scriptFile = do_get_file("common_test_handlerService.js");
 Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec);
 
 var prepareImportDB = Task.async(function* () {
   yield reloadData();
 
--- a/uriloader/exthandler/tests/unit/xpcshell.ini
+++ b/uriloader/exthandler/tests/unit/xpcshell.ini
@@ -10,11 +10,13 @@ support-files = common_test_handlerServi
 [test_handlerService.js]
 support-files = mailcap
 # Bug 676997: test consistently fails on Android
 fail-if = os == "android"
 [test_handlerService_json.js]
 support-files = handlers.json
 [test_handlerService_rdf.js]
 support-files = mimeTypes.rdf
+[test_handlerService_migration.js]
+support-files = mimeTypes.rdf mimeTypesAndroid.rdf
 [test_punycodeURIs.js]
 # Bug 676997: test consistently fails on Android
 fail-if = os == "android"