From: <asa...@us...> - 2013-11-14 07:34:08
|
Revision: 8780 http://sourceforge.net/p/htmlunit/code/8780 Author: asashour Date: 2013-11-14 07:34:03 +0000 (Thu, 14 Nov 2013) Log Message: ----------- JavaScript: fix window.postMessage() to verify protocol, port and hostname. Modified Paths: -------------- trunk/htmlunit/src/changes/changes.xml trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/BrowserVersionFeatures.java trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Window.java trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/Window2Test.java Modified: trunk/htmlunit/src/changes/changes.xml =================================================================== --- trunk/htmlunit/src/changes/changes.xml 2013-11-13 21:48:50 UTC (rev 8779) +++ trunk/htmlunit/src/changes/changes.xml 2013-11-14 07:34:03 UTC (rev 8780) @@ -8,6 +8,9 @@ <body> <release version="2.14" date="???" description="Bugfixes"> + <action type="fix" dev="asashour"> + JavaScript: fix window.postMessage() to verify protocol, port and hostname. + </action> <action type="fix" dev="rbri"> JavaScript: XMLHttpRequest CORS handling fixed, some new tests added and implementation fixed. </action> Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/BrowserVersionFeatures.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/BrowserVersionFeatures.java 2013-11-13 21:48:50 UTC (rev 8779) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/BrowserVersionFeatures.java 2013-11-14 07:34:03 UTC (rev 8780) @@ -1193,9 +1193,13 @@ @BrowserFeature(@WebBrowser(value = IE, maxVersion = 9)) JS_WINDOW_IS_A_FUNCTION, - /** Window.postMessage is synchronouse. */ + /** Window.postMessage is sent when the targetOrigin port is different than the current port. */ + @BrowserFeature(@WebBrowser(IE)) + JS_WINDOW_POST_MESSAGE_ALLOW_INVALID_PORT, + + /** Window.postMessage is synchronous. */ @BrowserFeature(@WebBrowser(value = IE, maxVersion = 9)) - JS_WINDOW_POST_MESSAGE_SYNCHRONOUSE, + JS_WINDOW_POST_MESSAGE_SYNCHRONOUS, /** Supports XML. */ @BrowserFeature({ @WebBrowser(FF), @WebBrowser(CHROME) }) Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Window.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Window.java 2013-11-13 21:48:50 UTC (rev 8779) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Window.java 2013-11-14 07:34:03 UTC (rev 8780) @@ -19,7 +19,8 @@ import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_WINDOW_CHANGE_OPENER_NOT_ALLOWED; import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_WINDOW_FRAMES_ACCESSIBLE_BY_ID; import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_WINDOW_IS_A_FUNCTION; -import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_WINDOW_POST_MESSAGE_SYNCHRONOUSE; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_WINDOW_POST_MESSAGE_ALLOW_INVALID_PORT; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_WINDOW_POST_MESSAGE_SYNCHRONOUS; import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_XML_SUPPORT_VIA_ACTIVEXOBJECT; import static com.gargoylesoftware.htmlunit.javascript.configuration.BrowserName.CHROME; import static com.gargoylesoftware.htmlunit.javascript.configuration.BrowserName.FF; @@ -2047,11 +2048,33 @@ */ @JsxFunction public void postMessage(final String message, final String targetOrigin) { + if (!"*".equals(targetOrigin)) { + final URL currentURL = getWebWindow().getEnclosedPage().getUrl(); + URL targetURL = null; + try { + targetURL = new URL(targetOrigin); + } + catch (final Exception e) { + Context.throwAsScriptRuntimeEx( + new Exception("SyntaxError: An invalid or illegal string was specified.")); + } + + if (getPort(targetURL) != getPort(currentURL) + && !getBrowserVersion().hasFeature(JS_WINDOW_POST_MESSAGE_ALLOW_INVALID_PORT)) { + return; + } + if (!targetURL.getHost().equals(currentURL.getHost())) { + return; + } + if (!targetURL.getProtocol().equals(currentURL.getProtocol())) { + return; + } + } final MessageEvent event = new MessageEvent(message); event.setParentScope(this); event.setPrototype(getPrototype(event.getClass())); - if (getBrowserVersion().hasFeature(JS_WINDOW_POST_MESSAGE_SYNCHRONOUSE)) { + if (getBrowserVersion().hasFeature(JS_WINDOW_POST_MESSAGE_SYNCHRONOUS)) { dispatchEvent(event); return; } @@ -2064,6 +2087,19 @@ }; getWebWindow().getWebClient().getJavaScriptEngine().addPostponedAction(action); } + + private static int getPort(final URL url) { + int port = url.getPort(); + if (port == -1) { + if ("http".equals(url.getProtocol())) { + port = 80; + } + else { + port = 443; + } + } + return port; + } } class HTMLCollectionFrames extends HTMLCollection { Modified: trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/Window2Test.java =================================================================== --- trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/Window2Test.java 2013-11-13 21:48:50 UTC (rev 8779) +++ trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/Window2Test.java 2013-11-14 07:34:03 UTC (rev 8780) @@ -27,6 +27,8 @@ import com.gargoylesoftware.htmlunit.BrowserRunner; import com.gargoylesoftware.htmlunit.BrowserRunner.Alerts; import com.gargoylesoftware.htmlunit.BrowserRunner.Browsers; +import com.gargoylesoftware.htmlunit.BrowserRunner.BuggyWebDriver; +import com.gargoylesoftware.htmlunit.BrowserRunner.NotYetImplemented; import com.gargoylesoftware.htmlunit.WebDriverTestCase; /** @@ -1238,4 +1240,87 @@ getMockWebConnection().setResponse(URL_SECOND, iframe); loadPageWithAlerts2(html); } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = { "received", "posted" }, + CHROME = { "posted", "received" }) + @BuggyWebDriver(FF) + @NotYetImplemented(FF) + public void postMessage_exactURL() throws Exception { + // FF: strange: the result is different than postMessageSyncOrAsync() + // if alert() is done in URL2 just after postMessage() we will have postMessage_exactURL() expectation + // if alert() is removed in URL2 after postMessage(), we will have postMessageSyncOrAsync() expectation + postMessage(URL_FIRST.toExternalForm()); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts("posted") + public void postMessage_otherHost() throws Exception { + postMessage("http://127.0.0.1:" + PORT + "/"); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = "posted", + IE = { "received", "posted" }) + public void postMessage_otherPort() throws Exception { + postMessage("http://localhost:" + (PORT + 1) + "/"); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts("exception") + public void postMessage_invalidTargetOrigin() throws Exception { + postMessage("abcdefg"); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts("posted") + public void postMessage_otherProtocol() throws Exception { + postMessage("https://localhost:" + PORT + "/"); + } + + private void postMessage(final String url) throws Exception { + final String html + = "<html>" + + "<head><title>foo</title></head>\n" + + "<body>\n" + + "<script>\n" + + " function receiveMessage(event) {\n" + + " alert('received');\n" + + " }\n" + + " if (window.addEventListener) {\n" + + " window.addEventListener('message', receiveMessage, false);\n" + + " } else {\n" + + " window.attachEvent('onmessage', receiveMessage);\n" + + " }\n" + + "</script>\n" + + " <iframe src='" + URL_SECOND + "'></iframe>\n" + + "</body></html>"; + + final String iframe = "<html><body><script>\n" + + " try {\n" + + " top.postMessage('hello', '" + url + "');\n" + + " alert('posted');\n" + + " } catch (e) {\n" + + " alert('exception');\n" + + " }\n" + + "</script></body></html>"; + + getMockWebConnection().setResponse(URL_SECOND, iframe); + loadPageWithAlerts2(html); + } } |