forked from mirrors/gecko-dev
		
	Bug 1669961: Return null from .contentWindow when inner window is inactive. r=nika
				
					
				
			Differential Revision: https://phabricator.services.mozilla.com/D93853
This commit is contained in:
		
							parent
							
								
									61a922522e
								
							
						
					
					
						commit
						cfebcd3fd2
					
				
					 11 changed files with 108 additions and 16 deletions
				
			
		|  | @ -360,10 +360,14 @@ async function unregisterServiceWorker(tab, expectedPageUrl) { | |||
| async function waitForRegistrationReady(tab, expectedPageUrl) { | ||||
|   await asyncWaitUntil(() => | ||||
|     SpecialPowers.spawn(tab.linkedBrowser, [expectedPageUrl], function(_url) { | ||||
|       try { | ||||
|         const win = content.wrappedJSObject; | ||||
|         const isExpectedUrl = win.location.href === _url; | ||||
|         const hasRegistration = !!win.registration; | ||||
|         return isExpectedUrl && hasRegistration; | ||||
|       } catch (e) { | ||||
|         return false; | ||||
|       } | ||||
|     }) | ||||
|   ); | ||||
| } | ||||
|  |  | |||
|  | @ -31,7 +31,6 @@ add_task(async function() { | |||
|                 "History listener got called after a content viewer was evicted" | ||||
|               ); | ||||
|               legacySHistory.removeSHistoryListener(historyListener); | ||||
|               delete content._testListener; | ||||
|               // 6. Resolve the promise when we got our 'content viewer evicted' event
 | ||||
|               resolve(); | ||||
|             }, | ||||
|  |  | |||
|  | @ -124,9 +124,17 @@ nsIDocShell* JSWindowActorChild::GetDocShell(ErrorResult& aRv) { | |||
| 
 | ||||
| Nullable<WindowProxyHolder> JSWindowActorChild::GetContentWindow( | ||||
|     ErrorResult& aRv) { | ||||
|   if (BrowsingContext* bc = GetBrowsingContext(aRv)) { | ||||
|     return WindowProxyHolder(bc); | ||||
|   if (!mManager) { | ||||
|     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); | ||||
|     return nullptr; | ||||
|   } | ||||
| 
 | ||||
|   if (nsGlobalWindowInner* window = mManager->GetWindowGlobal()) { | ||||
|     if (window->IsCurrentInnerWindow()) { | ||||
|       return WindowProxyHolder(window->GetBrowsingContext()); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| support-files = | ||||
|   head.js | ||||
| 
 | ||||
| [browser_contentWindow.js] | ||||
| [browser_crash_report.js] | ||||
| [browser_destroy_callbacks.js] | ||||
| skip-if = !debug && (os == 'mac') #Bug 1604538 | ||||
|  |  | |||
							
								
								
									
										47
									
								
								dom/ipc/tests/JSWindowActor/browser_contentWindow.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								dom/ipc/tests/JSWindowActor/browser_contentWindow.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | |||
| /* Any copyright is dedicated to the Public Domain. | ||||
|    http://creativecommons.org/publicdomain/zero/1.0/ */
 | ||||
| "use strict"; | ||||
| 
 | ||||
| declTest("contentWindow null when inner window inactive", { | ||||
|   matches: [TEST_URL + "*"], | ||||
|   url: TEST_URL + "?1", | ||||
| 
 | ||||
|   async test(browser) { | ||||
|     { | ||||
|       let parent = browser.browsingContext.currentWindowGlobal; | ||||
|       let actorParent = parent.getActor("TestWindow"); | ||||
| 
 | ||||
|       await actorParent.sendQuery("storeActor"); | ||||
|     } | ||||
| 
 | ||||
|     { | ||||
|       let url = TEST_URL + "?2"; | ||||
|       let loaded = BrowserTestUtils.browserLoaded(browser, false, url); | ||||
|       await BrowserTestUtils.loadURI(browser, url); | ||||
|       await loaded; | ||||
|     } | ||||
| 
 | ||||
|     let parent = browser.browsingContext.currentWindowGlobal; | ||||
|     let actorParent = parent.getActor("TestWindow"); | ||||
| 
 | ||||
|     let result = await actorParent.sendQuery("checkActor"); | ||||
|     if (SpecialPowers.useRemoteSubframes) { | ||||
|       is( | ||||
|         result.status, | ||||
|         "error", | ||||
|         "Should get an error when bfcache is disabled for Fission" | ||||
|       ); | ||||
|       is( | ||||
|         result.errorType, | ||||
|         "InvalidStateError", | ||||
|         "Should get an InvalidStateError without bfcache" | ||||
|       ); | ||||
|     } else { | ||||
|       is(result.status, "success", "Should succeed when bfcache is enabled"); | ||||
|       ok( | ||||
|         result.valueIsNull, | ||||
|         "Should get a null contentWindow when inner window is inactive" | ||||
|       ); | ||||
|     } | ||||
|   }, | ||||
| }); | ||||
|  | @ -35,7 +35,7 @@ declTest("sendQuery Error", { | |||
|     is(error.name, "SyntaxError", "Error should have the correct name"); | ||||
|     is( | ||||
|       error.stack, | ||||
|       "receiveMessage@resource://testing-common/TestWindowChild.jsm:33:31\n" + | ||||
|       "receiveMessage@resource://testing-common/TestWindowChild.jsm:35:31\n" + | ||||
|         asyncStack, | ||||
|       "Error should have the correct stack" | ||||
|     ); | ||||
|  | @ -63,7 +63,7 @@ declTest("sendQuery Exception", { | |||
|     ); | ||||
|     is( | ||||
|       error.stack, | ||||
|       "receiveMessage@resource://testing-common/TestWindowChild.jsm:36:22\n" + | ||||
|       "receiveMessage@resource://testing-common/TestWindowChild.jsm:38:22\n" + | ||||
|         asyncStack, | ||||
|       "Error should have the correct stack" | ||||
|     ); | ||||
|  |  | |||
|  | @ -50,9 +50,10 @@ async function openPage(enableDialogs) { | |||
|         const { Services } = ChromeUtils.import( | ||||
|           "resource://gre/modules/Services.jsm" | ||||
|         ); | ||||
|         let win = content; | ||||
|         Services.obs.addObserver(doc => { | ||||
|           if (content && doc == content.document) { | ||||
|             content.windowUtils[name](); | ||||
|           if (doc == win.document) { | ||||
|             win.windowUtils[name](); | ||||
|           } | ||||
|         }, "document-element-inserted"); | ||||
|       }); | ||||
|  |  | |||
|  | @ -138,7 +138,11 @@ class ReftestFissionChild extends JSWindowActorChild { | |||
|               } | ||||
|             } | ||||
| 
 | ||||
|             // `contentWindow` will be null if the inner window for this actor
 | ||||
|             // has been navigated away from.
 | ||||
|             if (this.contentWindow) { | ||||
|               flushWindow(this.contentWindow); | ||||
|             } | ||||
| 
 | ||||
|             if (anyPendingPaintsGeneratedInDescendants && | ||||
|                 !this.contentWindow.windowUtils.isMozAfterPaintPending) { | ||||
|  |  | |||
|  | @ -8,6 +8,8 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); | |||
| 
 | ||||
| var EXPORTED_SYMBOLS = ["TestWindowChild"]; | ||||
| 
 | ||||
| var docShellThunks = new Map(); | ||||
| 
 | ||||
| class TestWindowChild extends JSWindowActorChild { | ||||
|   constructor() { | ||||
|     super(); | ||||
|  | @ -41,6 +43,31 @@ class TestWindowChild extends JSWindowActorChild { | |||
|       case "noncloneReply": | ||||
|         // Return a value which is non-cloneable, like a WindowProxy.
 | ||||
|         return this.contentWindow; | ||||
|       case "storeActor": | ||||
|         docShellThunks.set(this.docShell, this); | ||||
|         break; | ||||
|       case "checkActor": { | ||||
|         let actor = docShellThunks.get(this.docShell); | ||||
|         docShellThunks.delete(this.docShell); | ||||
| 
 | ||||
|         let contentWindow; | ||||
|         let error; | ||||
|         try { | ||||
|           contentWindow = actor.contentWindow; | ||||
|         } catch (e) { | ||||
|           error = e; | ||||
|         } | ||||
|         if (error) { | ||||
|           return { | ||||
|             status: "error", | ||||
|             errorType: error.name, | ||||
|           }; | ||||
|         } | ||||
|         return { | ||||
|           status: "success", | ||||
|           valueIsNull: contentWindow === null, | ||||
|         }; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     return undefined; | ||||
|  |  | |||
|  | @ -267,10 +267,10 @@ async function submitForm(browser) { | |||
|   await SpecialPowers.spawn(browser, [], async function() { | ||||
|     content.document.querySelector("form").submit(); | ||||
| 
 | ||||
|     let win = content; | ||||
|     await ContentTaskUtils.waitForCondition(() => { | ||||
|       return ( | ||||
|         content.location.pathname == "/" && | ||||
|         content.document.readyState == "complete" | ||||
|         win.location.pathname == "/" && win.document.readyState == "complete" | ||||
|       ); | ||||
|     }, "Wait for form submission load"); | ||||
|   }); | ||||
|  |  | |||
|  | @ -457,10 +457,11 @@ async function submitForm(browser, action = "") { | |||
|     info("Submitting form to:" + form.action); | ||||
|     form.submit(); | ||||
| 
 | ||||
|     let win = content; | ||||
|     await ContentTaskUtils.waitForCondition(() => { | ||||
|       return ( | ||||
|         content.location.pathname == actionPathname && | ||||
|         content.document.readyState == "complete" | ||||
|         win.location.pathname == actionPathname && | ||||
|         win.document.readyState == "complete" | ||||
|       ); | ||||
|     }, "Wait for form submission load"); | ||||
|   }); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Kris Maglione
						Kris Maglione