1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/components/sessionstore/test/browser_formdata.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,231 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + * http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +"use strict"; 1.8 + 1.9 +/** 1.10 + * This test ensures that form data collection respects the privacy level as 1.11 + * set by the user. 1.12 + */ 1.13 +add_task(function test_formdata() { 1.14 + const URL = "http://mochi.test:8888/browser/browser/components/" + 1.15 + "sessionstore/test/browser_formdata_sample.html"; 1.16 + 1.17 + const OUTER_VALUE = "browser_formdata_" + Math.random(); 1.18 + const INNER_VALUE = "browser_formdata_" + Math.random(); 1.19 + 1.20 + // Creates a tab, loads a page with some form fields, 1.21 + // modifies their values and closes the tab. 1.22 + function createAndRemoveTab() { 1.23 + return Task.spawn(function () { 1.24 + // Create a new tab. 1.25 + let tab = gBrowser.addTab(URL); 1.26 + let browser = tab.linkedBrowser; 1.27 + yield promiseBrowserLoaded(browser); 1.28 + 1.29 + // Modify form data. 1.30 + yield setInputValue(browser, {id: "txt", value: OUTER_VALUE}); 1.31 + yield setInputValue(browser, {id: "txt", value: INNER_VALUE, frame: 0}); 1.32 + 1.33 + // Remove the tab. 1.34 + gBrowser.removeTab(tab); 1.35 + }); 1.36 + } 1.37 + 1.38 + yield createAndRemoveTab(); 1.39 + let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window)); 1.40 + is(formdata.id.txt, OUTER_VALUE, "outer value is correct"); 1.41 + is(formdata.children[0].id.txt, INNER_VALUE, "inner value is correct"); 1.42 + 1.43 + // Disable saving data for encrypted sites. 1.44 + Services.prefs.setIntPref("browser.sessionstore.privacy_level", 1); 1.45 + 1.46 + yield createAndRemoveTab(); 1.47 + let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window)); 1.48 + is(formdata.id.txt, OUTER_VALUE, "outer value is correct"); 1.49 + ok(!formdata.children, "inner value was *not* stored"); 1.50 + 1.51 + // Disable saving data for any site. 1.52 + Services.prefs.setIntPref("browser.sessionstore.privacy_level", 2); 1.53 + 1.54 + yield createAndRemoveTab(); 1.55 + let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window)); 1.56 + ok(!formdata, "form data has *not* been stored"); 1.57 + 1.58 + // Restore the default privacy level. 1.59 + Services.prefs.clearUserPref("browser.sessionstore.privacy_level"); 1.60 +}); 1.61 + 1.62 +/** 1.63 + * This test ensures that we maintain backwards compatibility with the form 1.64 + * data format used pre Fx 29. 1.65 + */ 1.66 +add_task(function test_old_format() { 1.67 + const URL = "data:text/html;charset=utf-8,<input%20id=input>"; 1.68 + const VALUE = "value-" + Math.random(); 1.69 + 1.70 + // Create a tab with an iframe containing an input field. 1.71 + let tab = gBrowser.addTab(URL); 1.72 + let browser = tab.linkedBrowser; 1.73 + yield promiseBrowserLoaded(browser); 1.74 + 1.75 + // Check that the form value is restored. 1.76 + let state = {entries: [{url: URL, formdata: {id: {input: VALUE}}}]}; 1.77 + ss.setTabState(tab, JSON.stringify(state)); 1.78 + yield promiseTabRestored(tab); 1.79 + is((yield getInputValue(browser, "input")), VALUE, "form data restored"); 1.80 + 1.81 + // Cleanup. 1.82 + gBrowser.removeTab(tab); 1.83 +}); 1.84 + 1.85 +/** 1.86 + * This test ensures that we maintain backwards compatibility with the form 1.87 + * data form used pre Fx 29, esp. the .innerHTML property for editable docs. 1.88 + */ 1.89 +add_task(function test_old_format_inner_html() { 1.90 + const URL = "data:text/html;charset=utf-8,<h1>mozilla</h1>" + 1.91 + "<script>document.designMode='on'</script>"; 1.92 + const VALUE = "<h1>value-" + Math.random() + "</h1>"; 1.93 + 1.94 + // Create a tab with an iframe containing an input field. 1.95 + let tab = gBrowser.addTab(URL); 1.96 + let browser = tab.linkedBrowser; 1.97 + yield promiseBrowserLoaded(browser); 1.98 + 1.99 + // Restore the tab state. 1.100 + let state = {entries: [{url: URL, innerHTML: VALUE}]}; 1.101 + ss.setTabState(tab, JSON.stringify(state)); 1.102 + yield promiseTabRestored(tab); 1.103 + 1.104 + // Check that the innerHTML value was restored. 1.105 + let html = yield getInnerHTML(browser); 1.106 + is(html, VALUE, "editable document has been restored correctly"); 1.107 + 1.108 + // Cleanup. 1.109 + gBrowser.removeTab(tab); 1.110 +}); 1.111 + 1.112 +/** 1.113 + * This test ensures that a malicious website can't trick us into restoring 1.114 + * form data into a wrong website and that we always check the stored URL 1.115 + * before doing so. 1.116 + */ 1.117 +add_task(function test_url_check() { 1.118 + const URL = "data:text/html;charset=utf-8,<input%20id=input>"; 1.119 + const VALUE = "value-" + Math.random(); 1.120 + 1.121 + // Create a tab with an iframe containing an input field. 1.122 + let tab = gBrowser.addTab(URL); 1.123 + let browser = tab.linkedBrowser; 1.124 + yield promiseBrowserLoaded(browser); 1.125 + 1.126 + // Restore a tab state with a given form data url. 1.127 + function restoreStateWithURL(url) { 1.128 + let state = {entries: [{url: URL}], formdata: {id: {input: VALUE}}}; 1.129 + 1.130 + if (url) { 1.131 + state.formdata.url = url; 1.132 + } 1.133 + 1.134 + ss.setTabState(tab, JSON.stringify(state)); 1.135 + return promiseTabRestored(tab).then(() => getInputValue(browser, "input")); 1.136 + } 1.137 + 1.138 + // Check that the form value is restored with the correct URL. 1.139 + is((yield restoreStateWithURL(URL)), VALUE, "form data restored"); 1.140 + 1.141 + // Check that the form value is *not* restored with the wrong URL. 1.142 + is((yield restoreStateWithURL(URL + "?")), "", "form data not restored"); 1.143 + is((yield restoreStateWithURL()), "", "form data not restored"); 1.144 + 1.145 + // Cleanup. 1.146 + gBrowser.removeTab(tab); 1.147 +}); 1.148 + 1.149 +/** 1.150 + * This test ensures that collecting form data works as expected when having 1.151 + * nested frame sets. 1.152 + */ 1.153 +add_task(function test_nested() { 1.154 + const URL = "data:text/html;charset=utf-8," + 1.155 + "<iframe src='data:text/html;charset=utf-8," + 1.156 + "<input autofocus=true>'/>"; 1.157 + 1.158 + const FORM_DATA = { 1.159 + children: [{ 1.160 + xpath: {"/xhtml:html/xhtml:body/xhtml:input": "M"}, 1.161 + url: "data:text/html;charset=utf-8,<input%20autofocus=true>" 1.162 + }] 1.163 + }; 1.164 + 1.165 + // Create a tab with an iframe containing an input field. 1.166 + let tab = gBrowser.selectedTab = gBrowser.addTab(URL); 1.167 + let browser = tab.linkedBrowser; 1.168 + yield promiseBrowserLoaded(browser); 1.169 + 1.170 + // Modify the input field's value. 1.171 + yield sendMessage(browser, "ss-test:sendKeyEvent", {key: "m", frame: 0}); 1.172 + 1.173 + // Remove the tab and check that we stored form data correctly. 1.174 + gBrowser.removeTab(tab); 1.175 + let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window)); 1.176 + is(JSON.stringify(formdata), JSON.stringify(FORM_DATA), 1.177 + "formdata for iframe stored correctly"); 1.178 + 1.179 + // Restore the closed tab. 1.180 + let tab = ss.undoCloseTab(window, 0); 1.181 + let browser = tab.linkedBrowser; 1.182 + yield promiseTabRestored(tab); 1.183 + 1.184 + // Check that the input field has the right value. 1.185 + SyncHandlers.get(browser).flush(); 1.186 + let {formdata} = JSON.parse(ss.getTabState(tab)); 1.187 + is(JSON.stringify(formdata), JSON.stringify(FORM_DATA), 1.188 + "formdata for iframe restored correctly"); 1.189 + 1.190 + // Cleanup. 1.191 + gBrowser.removeTab(tab); 1.192 +}); 1.193 + 1.194 +/** 1.195 + * This test ensures that collecting form data for documents with 1.196 + * designMode=on works as expected. 1.197 + */ 1.198 +add_task(function test_design_mode() { 1.199 + const URL = "data:text/html;charset=utf-8,<h1>mozilla</h1>" + 1.200 + "<script>document.designMode='on'</script>"; 1.201 + 1.202 + // Load a tab with an editable document. 1.203 + let tab = gBrowser.selectedTab = gBrowser.addTab(URL); 1.204 + let browser = tab.linkedBrowser; 1.205 + yield promiseBrowserLoaded(browser); 1.206 + 1.207 + // Modify the document content. 1.208 + yield sendMessage(browser, "ss-test:sendKeyEvent", {key: "m"}); 1.209 + 1.210 + // Duplicate the modified tab. 1.211 + let tab2 = gBrowser.duplicateTab(tab); 1.212 + yield promiseTabRestored(tab2); 1.213 + 1.214 + // Check that the innerHTML value was restored. 1.215 + let html = yield getInnerHTML(browser); 1.216 + let expected = "<h1>Mmozilla</h1><script>document.designMode='on'</script>"; 1.217 + is(html, expected, "editable document has been restored correctly"); 1.218 + 1.219 + // Cleanup. 1.220 + gBrowser.removeTab(tab2); 1.221 + gBrowser.removeTab(tab); 1.222 +}); 1.223 + 1.224 +function getInputValue(browser, id) { 1.225 + return sendMessage(browser, "ss-test:getInputValue", {id: id}); 1.226 +} 1.227 + 1.228 +function setInputValue(browser, data) { 1.229 + return sendMessage(browser, "ss-test:setInputValue", data); 1.230 +} 1.231 + 1.232 +function getInnerHTML(browser) { 1.233 + return sendMessage(browser, "ss-test:getInnerHTML", {selector: "body"}); 1.234 +}