|
1 <?xml version="1.0"?> |
|
2 <?xml-stylesheet type="text/css" href="chrome://global/skin"?> |
|
3 <?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?> |
|
4 <!-- Any copyright is dedicated to the Public Domain. |
|
5 http://creativecommons.org/publicdomain/zero/1.0/ --> |
|
6 <!-- |
|
7 https://bugzilla.mozilla.org/show_bug.cgi?id=762993 |
|
8 --> |
|
9 <window title="Mozilla Bug 762993" |
|
10 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" |
|
11 onload="run_next_test();"> |
|
12 <script type="application/javascript" |
|
13 src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> |
|
14 |
|
15 <!-- test results are displayed in the html:body --> |
|
16 <body xmlns="http://www.w3.org/1999/xhtml"> |
|
17 <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=762993" |
|
18 target="_blank">Mozilla Bug 762993</a> |
|
19 </body> |
|
20 |
|
21 <!-- test code goes here --> |
|
22 <script type="application/javascript;version=1.8"> |
|
23 <![CDATA[ |
|
24 |
|
25 /** Test for Bug 762993 **/ |
|
26 |
|
27 "use strict"; |
|
28 |
|
29 SimpleTest.expectAssertions(1); |
|
30 |
|
31 SimpleTest.waitForExplicitFinish(); |
|
32 |
|
33 const Cc = Components.classes; |
|
34 const Ci = Components.interfaces; |
|
35 const Cu = Components.utils; |
|
36 |
|
37 const secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager); |
|
38 |
|
39 const TEST_URL_1 = "https://example.com/"; |
|
40 // No trailing slash plus port to test normalization |
|
41 const TEST_URL_2 = "https://example.com:443"; |
|
42 |
|
43 const TEST_BASE = "http://mochi.test:8888/chrome/toolkit/identity/tests/chrome/" |
|
44 const STATE_URL = TEST_BASE + "sandbox_content.sjs" |
|
45 |
|
46 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
47 Cu.import("resource://gre/modules/Services.jsm"); |
|
48 |
|
49 Services.prefs.setBoolPref("toolkit.identity.debug", true); |
|
50 |
|
51 XPCOMUtils.defineLazyModuleGetter(this, "Sandbox", |
|
52 "resource://gre/modules/identity/Sandbox.jsm"); |
|
53 |
|
54 function check_sandbox(aSandbox, aURL) { |
|
55 ok(aSandbox.id > 0, "valid ID"); |
|
56 is(aSandbox._url, aURL, "matching URL (with normalization)"); |
|
57 isnot(aSandbox._frame, null, "frame"); |
|
58 isnot(aSandbox._container, null, "container"); |
|
59 let docPrincipal = aSandbox._frame.contentDocument.nodePrincipal; |
|
60 is(secMan.isSystemPrincipal(docPrincipal), false, |
|
61 "principal must not be system"); |
|
62 } |
|
63 |
|
64 /** |
|
65 * Free the sandbox and make sure all properties that are not booleans, |
|
66 * functions or numbers were freed. |
|
67 */ |
|
68 function free_and_check_sandbox(aSandbox) { |
|
69 SimpleTest.executeSoon(function() { |
|
70 aSandbox.free(); |
|
71 |
|
72 for(let prop in aSandbox) { |
|
73 // Don't trigger the "id" getter when the frame is supposed to be freed already |
|
74 if (prop == "id") |
|
75 continue; |
|
76 let propType = typeof(aSandbox[prop]); |
|
77 if (propType == "boolean" || propType == "function" || propType == "number") |
|
78 continue; |
|
79 is(aSandbox[prop], null, "freed " + prop); |
|
80 } |
|
81 run_next_test(); |
|
82 }); |
|
83 } |
|
84 |
|
85 function reset_server_state() { |
|
86 // Now reset the server state |
|
87 let resetReq = new XMLHttpRequest(); |
|
88 resetReq.open("GET", STATE_URL + "?reset", false); |
|
89 resetReq.send(); |
|
90 } |
|
91 |
|
92 function test_creation() { |
|
93 new Sandbox(TEST_URL_1, function sandboxCB(aSandbox) { |
|
94 check_sandbox(aSandbox, TEST_URL_1); |
|
95 free_and_check_sandbox(aSandbox); |
|
96 }); |
|
97 } |
|
98 |
|
99 function test_reload() { |
|
100 new Sandbox(TEST_URL_1, function sandboxCB(aSandbox) { |
|
101 check_sandbox(aSandbox, TEST_URL_1); |
|
102 let originalId = aSandbox.id; |
|
103 |
|
104 aSandbox.reload(function sandboxReloadCB(aSandbox) { |
|
105 check_sandbox(aSandbox, TEST_URL_1); |
|
106 is(aSandbox.id, originalId, "Sandbox ID should be the same after reload"); |
|
107 free_and_check_sandbox(aSandbox); |
|
108 }); |
|
109 }); |
|
110 } |
|
111 |
|
112 function test_url_normalization() { |
|
113 new Sandbox(TEST_URL_2, function sandboxCB(aSandbox) { |
|
114 // TEST_URL_2 should be normalized into the form of TEST_URL_1 |
|
115 check_sandbox(aSandbox, TEST_URL_1); |
|
116 free_and_check_sandbox(aSandbox); |
|
117 }); |
|
118 } |
|
119 |
|
120 /** |
|
121 * Check with the server's state to see what content was loaded then reset it. |
|
122 */ |
|
123 function check_loaded_content(aSandbox, aNothingShouldLoad, aCallback) { |
|
124 |
|
125 let xhr = new XMLHttpRequest(); |
|
126 xhr.open("GET", STATE_URL + "?get_loaded", true); |
|
127 xhr.onload = function() { |
|
128 let res = xhr.responseText; |
|
129 is(xhr.status, 200, "Check successful response"); |
|
130 |
|
131 if (aNothingShouldLoad) { |
|
132 is(res, "NOTHING", "Check that nothing was loaded on the server"); |
|
133 } else { |
|
134 let allowedTypes = [ "application/javascript", "text/html", "application/x-test" ]; |
|
135 let loadedTypes = res == "NOTHING" ? [] : res.split(","); |
|
136 |
|
137 for (let loadedType of loadedTypes) { |
|
138 isnot(allowedTypes.indexOf(loadedType), -1, "Check that " + loadedType + " was expected to load"); // TODO |
|
139 } |
|
140 |
|
141 isnot(loadedTypes.indexOf("application/javascript"), -1, "Check JS was loaded"); |
|
142 isnot(loadedTypes.indexOf("text/html"), -1, "Check iframe was loaded"); |
|
143 is(loadedTypes.indexOf("video/webm"), -1, "Check webm was not loaded"); |
|
144 is(loadedTypes.indexOf("audio/ogg"), -1, "Check ogg was not loaded"); |
|
145 |
|
146 // Check that no plugin tags have a type other than TYPE_NULL (failed load) |
|
147 // -- |
|
148 // Checking if a channel was opened is not sufficient for plugin tags -- |
|
149 // An object tag may still be allowed to load a sub-document, but not a |
|
150 // plugin, so it will open a channel but then abort when it gets a |
|
151 // plugin-type. |
|
152 let doc = aSandbox._frame.contentDocument; |
|
153 let nullType = Components.interfaces.nsIObjectLoadingContent.TYPE_NULL; |
|
154 for (let tag of doc.querySelectorAll("embed, object, applet")) { |
|
155 tag instanceof Components.interfaces.nsIObjectLoadingContent; |
|
156 is(tag.displayedType, nullType, "Check that plugin did not load content"); |
|
157 } |
|
158 } |
|
159 |
|
160 reset_server_state(); |
|
161 |
|
162 aCallback(); |
|
163 }; |
|
164 xhr.send(); |
|
165 } |
|
166 |
|
167 /** |
|
168 * Helper to check that only certain content is loaded on creation and during reload. |
|
169 */ |
|
170 function check_disabled_content(aSandboxURL, aNothingShouldLoad = false) { |
|
171 new Sandbox(aSandboxURL, function sandboxCB(aSandbox) { |
|
172 check_sandbox(aSandbox, aSandboxURL); |
|
173 let originalId = aSandbox.id; |
|
174 |
|
175 setTimeout(function() { |
|
176 check_loaded_content(aSandbox, aNothingShouldLoad, function checkFinished() { |
|
177 |
|
178 info("reload the sandbox content"); |
|
179 aSandbox.reload(function sandboxReloadCB(aSandbox) { |
|
180 check_sandbox(aSandbox, aSandboxURL); |
|
181 is(aSandbox.id, originalId, "Sandbox ID should be the same after reload"); |
|
182 |
|
183 setTimeout(function() { |
|
184 check_loaded_content(aSandbox, aNothingShouldLoad, function reloadCheckFinished() { |
|
185 free_and_check_sandbox(aSandbox); |
|
186 }); |
|
187 }, 5000); |
|
188 }); |
|
189 }); |
|
190 }, 5000); |
|
191 }); |
|
192 } |
|
193 |
|
194 function test_disabled_content() { |
|
195 let url = TEST_BASE + "sandbox_content.html"; |
|
196 check_disabled_content(url); |
|
197 } |
|
198 |
|
199 // Same as test above but with content in an iframe. |
|
200 function test_disabled_content_framed() { |
|
201 let url = TEST_BASE + "sandbox_content_framed.html"; |
|
202 check_disabled_content(url); |
|
203 } |
|
204 |
|
205 function test_redirect() { |
|
206 let url = TEST_BASE + "sandbox_content_redirect.html"; |
|
207 check_disabled_content(url); |
|
208 } |
|
209 |
|
210 function WindowObserver(aCallback) { |
|
211 this.observe = function(aSubject, aTopic, aData) { |
|
212 if (aTopic != "domwindowopened") { |
|
213 return; |
|
214 } |
|
215 Services.ww.unregisterNotification(this); |
|
216 |
|
217 let domWin = aSubject.QueryInterface(Ci.nsIDOMWindow); |
|
218 ok(!domWin, "No window should be opened"); |
|
219 SimpleTest.executeSoon(function() { |
|
220 info("Closing opened window"); |
|
221 domWin.close(); |
|
222 aCallback(); |
|
223 }); |
|
224 } |
|
225 } |
|
226 |
|
227 // Can the sandbox call window.alert() or popup other UI? |
|
228 function test_alert() { |
|
229 let alertURL = TEST_BASE + "sandbox_content_alert.html"; |
|
230 |
|
231 new Sandbox(alertURL, function sandboxCB(aSandbox) { |
|
232 check_sandbox(aSandbox, alertURL); |
|
233 setTimeout(function() { |
|
234 |
|
235 let win = Services.wm.getMostRecentWindow(null); |
|
236 isnot(win.document.documentElement.getAttribute("id"), "commonDialog", |
|
237 "Make sure most recent window is not a dialog"); |
|
238 if (win.document.documentElement.getAttribute("id") == "commonDialog") { |
|
239 // If a dialog did open, close it so we don't interfere with future tests |
|
240 win.close() |
|
241 } |
|
242 |
|
243 free_and_check_sandbox(aSandbox); |
|
244 }, 1000); |
|
245 }); |
|
246 } |
|
247 |
|
248 // Can the sandboxed page open a popup with window.open? |
|
249 function test_popup() { |
|
250 let alertURL = TEST_BASE + "sandbox_content_popup.html"; |
|
251 let theSandbox; |
|
252 function continueTest() { |
|
253 // avoid double-free |
|
254 if (!theSandbox) |
|
255 return; |
|
256 free_and_check_sandbox(theSandbox); |
|
257 theSandbox = null; |
|
258 } |
|
259 let winObs = new WindowObserver(continueTest); |
|
260 Services.ww.registerNotification(winObs); |
|
261 new Sandbox(alertURL, function sandboxCB(aSandbox) { |
|
262 theSandbox = aSandbox; |
|
263 check_sandbox(aSandbox, alertURL); |
|
264 // Wait 5 seconds to see if the window is going to open. |
|
265 setTimeout(function() { |
|
266 Services.ww.unregisterNotification(winObs); |
|
267 continueTest(); |
|
268 }, 5000); |
|
269 }); |
|
270 } |
|
271 |
|
272 // Loading a page with a bad cert |
|
273 function test_bad_cert() { |
|
274 let url = TEST_BASE + "sandbox_content.sjs?text/html"; |
|
275 url = url.replace("http://mochi.test:8888", "https://untrusted.example.com"); |
|
276 check_disabled_content(url, /*nothingShouldLoad=*/true); |
|
277 } |
|
278 |
|
279 // Loading a page to check window.top and other permissions. |
|
280 function test_frame_perms() { |
|
281 let url = TEST_BASE + "sandbox_content_perms.html"; |
|
282 new Sandbox(url, function sandboxCB(aSandbox) { |
|
283 check_sandbox(aSandbox, url); |
|
284 |
|
285 // Give the content time to load |
|
286 setTimeout(function() { |
|
287 let xhr = new XMLHttpRequest(); |
|
288 xhr.open("GET", STATE_URL + "?get_loaded", true); |
|
289 xhr.responseType = "json"; |
|
290 xhr.onload = function() { |
|
291 is(xhr.status, 200, "Check successful response"); |
|
292 is(typeof(xhr.response), "object", "Check response is object"); |
|
293 is(Object.keys(xhr.response).length, 3, "Check the number of perm. tests"); |
|
294 for (let test in xhr.response) { |
|
295 ok(xhr.response[test], "Check result of " + test); |
|
296 } |
|
297 |
|
298 reset_server_state(); |
|
299 free_and_check_sandbox(aSandbox); |
|
300 }; |
|
301 xhr.send(); |
|
302 }, 3000); |
|
303 }); |
|
304 } |
|
305 |
|
306 let TESTS = [test_creation, test_reload, test_url_normalization]; |
|
307 TESTS.push(test_disabled_content, test_disabled_content_framed); |
|
308 TESTS.push(test_alert, test_popup, test_bad_cert); |
|
309 TESTS.push(test_redirect, test_frame_perms); |
|
310 |
|
311 function run_next_test() { |
|
312 if (TESTS.length) { |
|
313 let test = TESTS.shift(); |
|
314 info(test.name); |
|
315 test(); |
|
316 } else { |
|
317 Services.prefs.clearUserPref("toolkit.identity.debug"); |
|
318 SimpleTest.finish(); |
|
319 } |
|
320 } |
|
321 |
|
322 ]]> |
|
323 </script> |
|
324 </window> |