Merge m-c to inbound. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 14 Mar 2016 22:10:42 -0400
changeset 288679 8732ddfbff87d14bc516db2ab016405385472ef6
parent 288678 676fc640c532865c16cda8102b9c3ddc2e8357fa (current diff)
parent 288567 d6ee82b9a74155b6bfd544166f036fc572ae8c56 (diff)
child 288680 556446426ca25a592e6596d2de05ec636997c597
push id30087
push usercbook@mozilla.com
push dateTue, 15 Mar 2016 09:43:43 +0000
treeherdermozilla-central@5e14887312d4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone48.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
Merge m-c to inbound. a=merge
--- a/dom/tests/mochitest/pointerlock/mochitest.ini
+++ b/dom/tests/mochitest/pointerlock/mochitest.ini
@@ -17,9 +17,9 @@ support-files =
   file_screenClientXYConst.html
   file_suppressSomeMouseEvents.html
   file_locksvgelement.html
   file_allowPointerLockSandboxFlag.html
   iframe_differentDOM.html
 
 [test_pointerlock-api.html]
 tags = fullscreen
-skip-if = buildapp == 'b2g' || toolkit == 'android' # B2G - window.open focus issues using fullscreen.
+skip-if = buildapp == 'b2g' || toolkit == 'android' || os == 'linux' || os == 'win' # B2G - window.open focus issues using fullscreen. Linux/Win: Bug 931445
--- a/mobile/android/base/java/org/mozilla/gecko/home/BookmarksListView.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/BookmarksListView.java
@@ -115,16 +115,21 @@ public class BookmarksListView extends H
     public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
         // Adjust the item position to account for the parent folder row that is inserted
         // at the top of the list when viewing the contents of a folder.
         final BookmarksListAdapter adapter = getBookmarksListAdapter();
         if (adapter.isShowingChildFolder()) {
             position--;
         }
 
+        // Temporarily prevent crashes until we figure out what we actually want to do here (bug 1252316).
+        if (adapter.getOpenFolderType() == BookmarksListAdapter.FolderType.SCREENSHOTS) {
+            return false;
+        }
+
         return super.onItemLongClick(parent, view, position, id);
     }
 
     private BookmarksListAdapter getBookmarksListAdapter() {
         BookmarksListAdapter adapter;
         ListAdapter listAdapter = getAdapter();
         if (listAdapter instanceof HeaderViewListAdapter) {
             adapter = (BookmarksListAdapter) ((HeaderViewListAdapter) listAdapter).getWrappedAdapter();
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -65,41 +65,50 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
              aLoadingContext->NodePrincipal() == aLoadingPrincipal);
 
   // if the load is sandboxed, we can not also inherit the principal
   if (mSecurityFlags & nsILoadInfo::SEC_SANDBOXED) {
     mSecurityFlags ^= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
   }
 
   if (aLoadingContext) {
+    nsCOMPtr<nsPIDOMWindowOuter> contextOuter = aLoadingContext->OwnerDoc()->GetWindow();
+    if (contextOuter) {
+      ComputeIsThirdPartyContext(contextOuter);
+    }
+
     nsCOMPtr<nsPIDOMWindowOuter> outerWindow;
 
     // When the element being loaded is a frame, we choose the frame's window
     // for the window ID and the frame element's window as the parent
     // window. This is the behavior that Chrome exposes to add-ons.
-    nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner = do_QueryInterface(aLoadingContext);
-    if (frameLoaderOwner) {
-      nsCOMPtr<nsIFrameLoader> fl = frameLoaderOwner->GetFrameLoader();
+    // NB: If the frameLoaderOwner doesn't have a frame loader, then the load
+    // must be coming from an object (such as a plugin) that's loaded into it
+    // instead of a document being loaded. In that case, treat this object like
+    // any other non-document-loading element.
+    nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner =
+      do_QueryInterface(aLoadingContext);
+    nsCOMPtr<nsIFrameLoader> fl = frameLoaderOwner ?
+      frameLoaderOwner->GetFrameLoader() : nullptr;
+    if (fl) {
       nsCOMPtr<nsIDocShell> docShell;
-      if (fl && NS_SUCCEEDED(fl->GetDocShell(getter_AddRefs(docShell))) && docShell) {
+      if (NS_SUCCEEDED(fl->GetDocShell(getter_AddRefs(docShell))) && docShell) {
         outerWindow = do_GetInterface(docShell);
       }
     } else {
-      outerWindow = aLoadingContext->OwnerDoc()->GetWindow();
+      outerWindow = contextOuter.forget();
     }
 
     if (outerWindow) {
       nsCOMPtr<nsPIDOMWindowInner> inner = outerWindow->GetCurrentInnerWindow();
       mInnerWindowID = inner ? inner->WindowID() : 0;
       mOuterWindowID = outerWindow->WindowID();
 
       nsCOMPtr<nsPIDOMWindowOuter> parent = outerWindow->GetScriptableParent();
       mParentOuterWindowID = parent->WindowID();
-
-      ComputeIsThirdPartyContext(outerWindow);
     }
 
     // if the document forces all requests to be upgraded from http to https, then
     // we should do that for all requests. If it only forces preloads to be upgraded
     // then we should enforce upgrade insecure requests only for preloads.
     mUpgradeInsecureRequests =
       aLoadingContext->OwnerDoc()->GetUpgradeInsecureRequests(false) ||
       (nsContentUtils::IsPreloadType(mInternalContentPolicyType) &&
@@ -230,32 +239,22 @@ LoadInfo::ComputeIsThirdPartyContext(nsP
   nsContentPolicyType type =
     nsContentUtils::InternalContentPolicyTypeToExternal(mInternalContentPolicyType);
   if (type == nsIContentPolicy::TYPE_DOCUMENT) {
     // Top-level loads are never third-party.
     mIsThirdPartyContext = false;
     return;
   }
 
-  nsPIDOMWindowOuter* win = aOuterWindow;
-  if (type == nsIContentPolicy::TYPE_SUBDOCUMENT) {
-    // If we're loading a subdocument, aOuterWindow points to the new window.
-    // Check if its parent is third-party (and then we can do the same check for
-    // it as we would do for other sub-resource loads.
-
-    win = aOuterWindow->GetScriptableParent();
-    MOZ_ASSERT(win);
-  }
-
   nsCOMPtr<mozIThirdPartyUtil> util(do_GetService(THIRDPARTYUTIL_CONTRACTID));
   if (NS_WARN_IF(!util)) {
     return;
   }
 
-  util->IsThirdPartyWindow(win, nullptr, &mIsThirdPartyContext);
+  util->IsThirdPartyWindow(aOuterWindow, nullptr, &mIsThirdPartyContext);
 }
 
 NS_IMPL_ISUPPORTS(LoadInfo, nsILoadInfo)
 
 already_AddRefed<nsILoadInfo>
 LoadInfo::Clone() const
 {
   RefPtr<LoadInfo> copy(new LoadInfo(*this));
--- a/toolkit/components/search/nsSearchService.js
+++ b/toolkit/components/search/nsSearchService.js
@@ -2862,16 +2862,19 @@ SearchService.prototype = {
     cache.metaData = this._metaData;
     cache.engines = [];
 
     for (let name in this._engines) {
       cache.engines.push(this._engines[name]);
     }
 
     try {
+      if (!cache.engines.length)
+        throw "cannot write without any engine.";
+
       LOG("_buildCache: Writing to cache file.");
       let path = OS.Path.join(OS.Constants.Path.profileDir, CACHE_FILENAME);
       let data = gEncoder.encode(JSON.stringify(cache));
       let promise = OS.File.writeAtomic(path, data, {compression: "lz4",
                                                      tmpPath: path + ".tmp"});
 
       promise.then(
         function onSuccess() {
@@ -3180,17 +3183,20 @@ SearchService.prototype = {
                   .createInstance(Ci.nsIBinaryInputStream);
       bis.setInputStream(stream);
 
       let count = stream.available();
       let array = new Uint8Array(count);
       bis.readArrayBuffer(count, array.buffer);
 
       let bytes = Lz4.decompressFileContent(array);
-      return JSON.parse(new TextDecoder().decode(bytes));
+      let json = JSON.parse(new TextDecoder().decode(bytes));
+      if (!json.engines || !json.engines.length)
+        throw "no engine in the file";
+      return json;
     } catch(ex) {
       LOG("_readCacheFile: Error reading cache file: " + ex);
     } finally {
       stream.close();
     }
 
     try {
       cacheFile.leafName = "search-metadata.json";
@@ -3233,16 +3239,18 @@ SearchService.prototype = {
    */
   _asyncReadCacheFile: function SRCH_SVC__asyncReadCacheFile() {
     return Task.spawn(function() {
       let json;
       try {
         let cacheFilePath = OS.Path.join(OS.Constants.Path.profileDir, CACHE_FILENAME);
         let bytes = yield OS.File.read(cacheFilePath, {compression: "lz4"});
         json = JSON.parse(new TextDecoder().decode(bytes));
+        if (!json.engines || !json.engines.length)
+          throw "no engine in the file";
         this._cacheFileJSON = json;
       } catch (ex) {
         LOG("_asyncReadCacheFile: Error reading cache file: " + ex);
         json = {};
 
         let oldMetadata =
           OS.Path.join(OS.Constants.Path.profileDir, "search-metadata.json");
         try {
--- a/toolkit/components/search/tests/xpcshell/head_search.js
+++ b/toolkit/components/search/tests/xpcshell/head_search.js
@@ -210,16 +210,22 @@ function getSearchMetadata()
 function promiseCacheData() {
   return new Promise(resolve => Task.spawn(function* () {
     let path = OS.Path.join(OS.Constants.Path.profileDir, CACHE_FILENAME);
     let bytes = yield OS.File.read(path, {compression: "lz4"});
     resolve(JSON.parse(new TextDecoder().decode(bytes)));
   }));
 }
 
+function promiseSaveCacheData(data) {
+  return OS.File.writeAtomic(OS.Path.join(OS.Constants.Path.profileDir, CACHE_FILENAME),
+                             new TextEncoder().encode(JSON.stringify(data)),
+                             {compression: "lz4"});
+}
+
 function promiseEngineMetadata() {
   return new Promise(resolve => Task.spawn(function* () {
     let cache = yield promiseCacheData();
     let data = {};
     for (let engine of cache.engines) {
       data[engine._shortName] = engine._metaData;
     }
     resolve(data);
@@ -232,41 +238,42 @@ function promiseGlobalMetadata() {
     resolve(cache.metaData);
   }));
 }
 
 function promiseSaveGlobalMetadata(globalData) {
   return new Promise(resolve => Task.spawn(function* () {
     let data = yield promiseCacheData();
     data.metaData = globalData;
-    yield OS.File.writeAtomic(OS.Path.join(OS.Constants.Path.profileDir, CACHE_FILENAME),
-                              new TextEncoder().encode(JSON.stringify(data)),
-                              {compression: "lz4"});
+    yield promiseSaveCacheData(data);
     resolve();
   }));
 }
 
 var forceExpiration = Task.async(function* () {
   let metadata = yield promiseGlobalMetadata();
 
   // Make the current geodefaults expire 1s ago.
   metadata.searchDefaultExpir = Date.now() - 1000;
   yield promiseSaveGlobalMetadata(metadata);
 });
 
 /**
  * Clean the profile of any cache file left from a previous run.
+ * Returns a boolean indicating if the cache file existed.
  */
 function removeCacheFile()
 {
   let file = gProfD.clone();
   file.append(CACHE_FILENAME);
   if (file.exists()) {
     file.remove(false);
+    return true;
   }
+  return false;
 }
 
 /**
  * isUSTimezone taken from nsSearchService.js
  */
 function isUSTimezone() {
   // Timezone assumptions! We assume that if the system clock's timezone is
   // between Newfoundland and Hawaii, that the user is in North America.
--- a/toolkit/components/search/tests/xpcshell/test_hidden.js
+++ b/toolkit/components/search/tests/xpcshell/test_hidden.js
@@ -40,35 +40,37 @@ add_task(function* async_init() {
   do_check_neq(engine, null);
 
   // The next test does a sync init, which won't do the geoSpecificDefaults XHR,
   // so it depends on the metadata having been written to disk.
   yield commitPromise;
 });
 
 add_task(function* sync_init() {
+  let unInitPromise = waitForSearchNotification("uninit-complete");
   let reInitPromise = asyncReInit();
+  yield unInitPromise;
+  do_check_false(Services.search.isInitialized);
+
   // Synchronously check the current default engine, to force a sync init.
-  do_check_false(Services.search.isInitialized);
   do_check_eq(Services.search.currentEngine.name, "hidden");
   do_check_true(Services.search.isInitialized);
 
   let engines = Services.search.getEngines();
   do_check_eq(engines.length, 1);
 
   // The default test jar engine has been hidden.
   let engine = Services.search.getEngineByName("bug645970");
   do_check_eq(engine, null);
 
   // The hidden engine is visible.
   engine = Services.search.getEngineByName("hidden");
   do_check_neq(engine, null);
 
   yield reInitPromise;
-  yield promiseAfterCache();
 });
 
 add_task(function* invalid_engine() {
   // Trigger a new request.
   yield forceExpiration();
 
   // Set the visibleDefaultEngines list to something that contains a non-existent engine.
   // This should cause the search service to ignore the list altogether and fallback to
new file mode 100644
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/test_require_engines_in_cache.js
@@ -0,0 +1,74 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function run_test() {
+  removeMetadata();
+  removeCacheFile();
+
+  do_load_manifest("data/chrome.manifest");
+
+  configureToLoadJarEngines();
+  do_check_false(Services.search.isInitialized);
+
+  run_next_test();
+}
+
+add_task(function* ignore_cache_files_without_engines() {
+  let commitPromise = promiseAfterCache()
+  yield asyncInit();
+
+  let engineCount = Services.search.getEngines().length;
+  do_check_eq(engineCount, 1);
+
+  // Wait for the file to be saved to disk, so that we can mess with it.
+  yield commitPromise;
+
+  // Remove all engines from the cache file.
+  let cache = yield promiseCacheData();
+  cache.engines = [];
+  yield promiseSaveCacheData(cache);
+
+  // Check that after an async re-initialization, we still have the same engine count.
+  commitPromise = promiseAfterCache()
+  yield asyncReInit();
+  do_check_eq(engineCount, Services.search.getEngines().length);
+  yield commitPromise;
+
+  // Check that after a sync re-initialization, we still have the same engine count.
+  yield promiseSaveCacheData(cache);
+  let unInitPromise = waitForSearchNotification("uninit-complete");
+  let reInitPromise = asyncReInit();
+  yield unInitPromise;
+  do_check_false(Services.search.isInitialized);
+  // Synchronously check the engine count; will force a sync init.
+  do_check_eq(engineCount, Services.search.getEngines().length);
+  do_check_true(Services.search.isInitialized);
+  yield reInitPromise;
+});
+
+add_task(function* skip_writing_cache_without_engines() {
+  let unInitPromise = waitForSearchNotification("uninit-complete");
+  let reInitPromise = asyncReInit();
+  yield unInitPromise;
+
+  // Configure so that no engines will be found.
+  do_check_true(removeCacheFile());
+  let resProt = Services.io.getProtocolHandler("resource")
+                        .QueryInterface(Ci.nsIResProtocolHandler);
+  resProt.setSubstitution("search-plugins",
+                          Services.io.newURI("about:blank", null, null));
+
+  // Let the async-reInit happen.
+  yield reInitPromise;
+  do_check_eq(0, Services.search.getEngines().length);
+
+  // Trigger yet another re-init, to flush of any pending cache writing task.
+  unInitPromise = waitForSearchNotification("uninit-complete");
+  reInitPromise = asyncReInit();
+  yield unInitPromise;
+
+  // Now check that a cache file doesn't exist.
+  do_check_false(removeCacheFile());
+
+  yield reInitPromise;
+});
--- a/toolkit/components/search/tests/xpcshell/xpcshell.ini
+++ b/toolkit/components/search/tests/xpcshell/xpcshell.ini
@@ -83,9 +83,10 @@ tags = addons
 [test_sync_migration.js]
 [test_sync_profile_engine.js]
 [test_rel_searchform.js]
 [test_remove_profile_engine.js]
 [test_selectedEngine.js]
 [test_geodefaults.js]
 [test_hidden.js]
 [test_currentEngine_fallback.js]
+[test_require_engines_in_cache.js]
 [test_svg_icon.js]