From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlwindow.c | 84 ++++++++++++++++++++++++++++++- dlls/mshtml/tests/documentmode.js | 53 +++++++++++++++++-- dlls/mshtml/tests/events.js | 2 +- 3 files changed, 133 insertions(+), 6 deletions(-)
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 2406f9c615f..ffbdb6d890c 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -25,6 +25,7 @@ #include "winuser.h" #include "ole2.h" #include "mshtmdid.h" +#include "wininet.h" #include "shlguid.h" #include "shobjidl.h" #include "exdispid.h" @@ -2213,6 +2214,68 @@ static void post_message_destr(task_t *_task) IHTMLWindow2_Release(&task->window->base.IHTMLWindow2_iface); }
+static HRESULT check_target_origin(HTMLInnerWindow *window, const VARIANT *target_origin) +{ + IUri *uri, *target; + DWORD port, port2; + BSTR bstr, bstr2; + HRESULT hres; + + if(V_VT(target_origin) != VT_BSTR) + return E_INVALIDARG; + + if(!wcscmp(V_BSTR(target_origin), L"*")) + return S_OK; + + hres = create_uri(V_BSTR(target_origin), Uri_CREATE_NOFRAG | Uri_CREATE_NO_DECODE_EXTRA_INFO, &target); + if(FAILED(hres)) + return hres; + + if(!window->base.outer_window || !(uri = window->base.outer_window->uri)) { + hres = S_OK; + goto done; + } + + hres = IUri_GetSchemeName(uri, &bstr); + if(FAILED(hres)) + goto done; + hres = IUri_GetSchemeName(target, &bstr2); + if(SUCCEEDED(hres)) { + hres = !wcsicmp(bstr, bstr2) ? S_OK : S_FALSE; + SysFreeString(bstr2); + } + SysFreeString(bstr); + if(hres != S_OK) + goto done; + + hres = IUri_GetHost(uri, &bstr); + if(FAILED(hres)) + goto done; + hres = IUri_GetHost(target, &bstr2); + if(SUCCEEDED(hres)) { + hres = !wcsicmp(bstr, bstr2) ? S_OK : S_FALSE; + SysFreeString(bstr2); + } + SysFreeString(bstr); + if(hres != S_OK) + goto done; + + /* Legacy modes ignore port */ + if(dispex_compat_mode(&window->event_target.dispex) < COMPAT_MODE_IE9) + goto done; + + hres = IUri_GetPort(uri, &port); + if(FAILED(hres)) + goto done; + hres = IUri_GetPort(target, &port2); + if(SUCCEEDED(hres)) + hres = (port == port2) ? S_OK : S_FALSE; + +done: + IUri_Release(target); + return hres; +} + static HRESULT WINAPI HTMLWindow6_postMessage(IHTMLWindow6 *iface, BSTR msg, VARIANT targetOrigin) { HTMLWindow *This = impl_from_IHTMLWindow6(iface); @@ -2220,7 +2283,11 @@ static HRESULT WINAPI HTMLWindow6_postMessage(IHTMLWindow6 *iface, BSTR msg, VAR HRESULT hres; VARIANT var;
- FIXME("(%p)->(%s %s) semi-stub\n", This, debugstr_w(msg), debugstr_variant(&targetOrigin)); + TRACE("(%p)->(%s %s)\n", This, debugstr_w(msg), debugstr_variant(&targetOrigin)); + + hres = check_target_origin(This->inner_window, &targetOrigin); + if(hres != S_OK) + return SUCCEEDED(hres) ? S_OK : hres;
if(!This->inner_window->doc) { FIXME("No document\n"); @@ -3799,7 +3866,7 @@ static HRESULT IHTMLWindow6_postMessage_hook(DispatchEx *dispex, WORD flags, DIS EXCEPINFO *ei, IServiceProvider *caller) { HTMLInnerWindow *This = impl_from_DispatchEx(dispex); - VARIANT msg, *targetOrigin, *transfer; + VARIANT msg, targetOrigin_var, *targetOrigin, *transfer; struct post_message_task *task; DOMEvent *event; HRESULT hres; @@ -3815,6 +3882,19 @@ static HRESULT IHTMLWindow6_postMessage_hook(DispatchEx *dispex, WORD flags, DIS if(transfer) FIXME("transfer not implemented, ignoring\n");
+ V_VT(&targetOrigin_var) = VT_EMPTY; + if(V_VT(targetOrigin) != VT_BSTR) { + hres = change_type(&targetOrigin_var, targetOrigin, VT_BSTR, caller); + if(FAILED(hres)) + return hres; + targetOrigin = &targetOrigin_var; + } + + hres = check_target_origin(This, targetOrigin); + VariantClear(&targetOrigin_var); + if(hres != S_OK) + return SUCCEEDED(hres) ? S_OK : hres; + switch(V_VT(&msg)) { case VT_EMPTY: case VT_NULL: diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 0ec4785450e..5b746598dba 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -2082,10 +2082,57 @@ async_test("postMessage", function() { onmessage_called = true; if(v < 9) ok(e === undefined, "e = " + e); - else + else { ok(e.data === (v < 10 ? "10" : 10), "e.data = " + e.data); - next_test(); + next_test(); + } + } + + var invalid = [ + v < 10 ? { toString: function() { return "http://winetest.example.org"; } } : null, + (function() { return "http://winetest.example.org"; }), + "winetest.example.org", + "example.org", + undefined + ]; + for(var i = 0; i < invalid.length; i++) { + try { + window.postMessage("invalid " + i, invalid[i]); + ok(false, "expected exception with targetOrigin " + invalid[i]); + }catch(ex) { + var n = ex.number >>> 0; + todo_wine_if(v >= 10). + ok(n === (v < 10 ? 0x80070057 : 0), "postMessage with targetOrigin " + invalid[i] + " threw " + n); + if(v >= 10) + todo_wine. + ok(ex.name === "SyntaxError", "postMessage with targetOrigin " + invalid[i] + " threw " + ex.name); + } } - window.postMessage(10, "*"); + try { + window.postMessage("invalid empty", ""); + ok(false, "expected exception with empty targetOrigin"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === 0x80070057, "postMessage with empty targetOrigin threw " + n); + } + + window.postMessage("wrong port", "http://winetest.example.org:1234"); + ok(onmessage_called == (v < 9 ? true : false), "onmessage not called with wrong port"); + onmessage_called = false; + + var not_sent = [ + "http://winetest.example.com", + "ftp://winetest.example.org", + "http://wine.example.org", + "http://example.org" + ]; + for(var i = 0; i < not_sent.length; i++) { + window.postMessage("not_sent " + i, not_sent[i]); + ok(onmessage_called == false, "onmessage called with targetOrigin " + not_sent[i]); + onmessage_called = false; + } + + window.postMessage(10, (v < 10 ? "*" : { toString: function() { return "*"; } })); ok(onmessage_called == (v < 9 ? true : false), "onmessage not called"); + if(v < 9) next_test(); }); diff --git a/dlls/mshtml/tests/events.js b/dlls/mshtml/tests/events.js index e67bf07d210..997e583ad20 100644 --- a/dlls/mshtml/tests/events.js +++ b/dlls/mshtml/tests/events.js @@ -818,6 +818,6 @@ async_test("message event", function() { next_test(); });
- window.postMessage("test", "http://winetest.example.org"); + window.postMessage("test", "httP://wineTest.example.org"); ok(listener_called == false, "listener already called"); });