mshtml: Use a hook to implement postMessage.
We need the caller ServiceProvider to obtain the source. Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
This commit is contained in:
parent
7c7544aba1
commit
22214ec357
2 changed files with 211 additions and 164 deletions
|
@ -2234,6 +2234,87 @@ static HRESULT WINAPI HTMLWindow6_get_maxConnectionsPerServer(IHTMLWindow6 *ifac
|
|||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT check_target_origin(HTMLInnerWindow *window, const WCHAR *target_origin)
|
||||
{
|
||||
BOOL no_port = FALSE;
|
||||
IUri *uri, *target;
|
||||
DWORD port, port2;
|
||||
BSTR bstr, bstr2;
|
||||
HRESULT hres;
|
||||
|
||||
if(!target_origin)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if(!wcscmp(target_origin, L"*"))
|
||||
return S_OK;
|
||||
|
||||
hres = create_uri(target_origin, Uri_CREATE_NOFRAG | Uri_CREATE_NO_DECODE_EXTRA_INFO, &target);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(!(uri = window->base.outer_window->uri)) {
|
||||
FIXME("window with no URI\n");
|
||||
hres = S_FALSE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
bstr = NULL;
|
||||
hres = IUri_GetSchemeName(uri, &bstr);
|
||||
if(hres != S_OK) {
|
||||
SysFreeString(bstr);
|
||||
goto done;
|
||||
}
|
||||
hres = IUri_GetSchemeName(target, &bstr2);
|
||||
if(SUCCEEDED(hres)) {
|
||||
if(hres == S_OK && wcsicmp(bstr, bstr2))
|
||||
hres = S_FALSE;
|
||||
SysFreeString(bstr2);
|
||||
}
|
||||
SysFreeString(bstr);
|
||||
if(hres != S_OK)
|
||||
goto done;
|
||||
|
||||
bstr = NULL;
|
||||
hres = IUri_GetHost(uri, &bstr);
|
||||
if(hres != S_OK) {
|
||||
SysFreeString(bstr);
|
||||
goto done;
|
||||
}
|
||||
hres = IUri_GetHost(target, &bstr2);
|
||||
if(SUCCEEDED(hres)) {
|
||||
if(hres == S_OK && wcsicmp(bstr, bstr2))
|
||||
hres = 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(hres != S_OK) {
|
||||
if(FAILED(hres))
|
||||
goto done;
|
||||
no_port = TRUE; /* some protocols don't have ports (e.g. res) */
|
||||
}
|
||||
hres = IUri_GetPort(target, &port2);
|
||||
if(hres != S_OK) {
|
||||
if(FAILED(hres))
|
||||
goto done;
|
||||
if(no_port)
|
||||
hres = S_OK;
|
||||
}else if(no_port || port != port2) {
|
||||
hres = S_FALSE;
|
||||
}
|
||||
|
||||
done:
|
||||
IUri_Release(target);
|
||||
return hres;
|
||||
}
|
||||
|
||||
struct post_message_task {
|
||||
event_task_t header;
|
||||
DOMEvent *event;
|
||||
|
@ -2251,6 +2332,77 @@ static void post_message_destr(event_task_t *_task)
|
|||
IDOMEvent_Release(&task->event->IDOMEvent_iface);
|
||||
}
|
||||
|
||||
static HRESULT post_message(HTMLInnerWindow *window, VARIANT msg, BSTR targetOrigin, VARIANT transfer,
|
||||
IServiceProvider *caller, compat_mode_t compat_mode)
|
||||
{
|
||||
DOMEvent *event;
|
||||
HRESULT hres;
|
||||
|
||||
if(V_VT(&transfer) != VT_EMPTY && V_VT(&transfer) != VT_ERROR)
|
||||
FIXME("transfer not implemented, ignoring\n");
|
||||
|
||||
hres = check_target_origin(window, targetOrigin);
|
||||
if(hres != S_OK)
|
||||
return SUCCEEDED(hres) ? S_OK : hres;
|
||||
|
||||
switch(V_VT(&msg)) {
|
||||
case VT_EMPTY:
|
||||
case VT_NULL:
|
||||
case VT_VOID:
|
||||
case VT_I1:
|
||||
case VT_I2:
|
||||
case VT_I4:
|
||||
case VT_I8:
|
||||
case VT_UI1:
|
||||
case VT_UI2:
|
||||
case VT_UI4:
|
||||
case VT_UI8:
|
||||
case VT_INT:
|
||||
case VT_UINT:
|
||||
case VT_R4:
|
||||
case VT_R8:
|
||||
case VT_BOOL:
|
||||
case VT_BSTR:
|
||||
case VT_CY:
|
||||
case VT_DATE:
|
||||
case VT_DECIMAL:
|
||||
case VT_HRESULT:
|
||||
break;
|
||||
case VT_ERROR:
|
||||
V_VT(&msg) = VT_EMPTY;
|
||||
break;
|
||||
default:
|
||||
FIXME("Unsupported vt %d\n", V_VT(&msg));
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
if(!window->doc) {
|
||||
FIXME("No document\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
hres = create_message_event(window->doc, &msg, &event);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(compat_mode >= COMPAT_MODE_IE9) {
|
||||
struct post_message_task *task;
|
||||
if(!(task = malloc(sizeof(*task)))) {
|
||||
IDOMEvent_Release(&event->IDOMEvent_iface);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
/* Because message events can be sent to different windows, they get blocked by any context */
|
||||
task->header.thread_blocked = TRUE;
|
||||
task->event = event;
|
||||
return push_event_task(&task->header, window, post_message_proc, post_message_destr, window->task_magic);
|
||||
}
|
||||
|
||||
dispatch_event(&window->event_target, event);
|
||||
IDOMEvent_Release(&event->IDOMEvent_iface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI HTMLWindow6_postMessage(IHTMLWindow6 *iface, BSTR msg, VARIANT targetOrigin)
|
||||
{
|
||||
HTMLWindow *This = impl_from_IHTMLWindow6(iface);
|
||||
|
@ -2264,7 +2416,8 @@ static HRESULT WINAPI HTMLWindow6_postMessage(IHTMLWindow6 *iface, BSTR msg, VAR
|
|||
V_VT(&var) = VT_BSTR;
|
||||
V_BSTR(&var) = msg;
|
||||
V_VT(&transfer) = VT_EMPTY;
|
||||
return IWineHTMLWindowPrivate_postMessage(&This->IWineHTMLWindowPrivate_iface, var, V_BSTR(&targetOrigin), transfer);
|
||||
return post_message(This->inner_window, var, V_BSTR(&targetOrigin), transfer, NULL,
|
||||
dispex_compat_mode(&This->inner_window->event_target.dispex));
|
||||
}
|
||||
|
||||
static HRESULT WINAPI HTMLWindow6_toStaticHTML(IHTMLWindow6 *iface, BSTR bstrHTML, BSTR *pbstrStaticHTML)
|
||||
|
@ -3197,162 +3350,6 @@ static HRESULT WINAPI window_private_matchMedia(IWineHTMLWindowPrivate *iface, B
|
|||
return create_media_query_list(This, media_query, media_query_list);
|
||||
}
|
||||
|
||||
static HRESULT check_target_origin(HTMLInnerWindow *window, const WCHAR *target_origin)
|
||||
{
|
||||
BOOL no_port = FALSE;
|
||||
IUri *uri, *target;
|
||||
DWORD port, port2;
|
||||
BSTR bstr, bstr2;
|
||||
HRESULT hres;
|
||||
|
||||
if(!target_origin)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if(!wcscmp(target_origin, L"*"))
|
||||
return S_OK;
|
||||
|
||||
hres = create_uri(target_origin, Uri_CREATE_NOFRAG | Uri_CREATE_NO_DECODE_EXTRA_INFO, &target);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(!(uri = window->base.outer_window->uri)) {
|
||||
FIXME("window with no URI\n");
|
||||
hres = S_FALSE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
bstr = NULL;
|
||||
hres = IUri_GetSchemeName(uri, &bstr);
|
||||
if(hres != S_OK) {
|
||||
SysFreeString(bstr);
|
||||
goto done;
|
||||
}
|
||||
hres = IUri_GetSchemeName(target, &bstr2);
|
||||
if(SUCCEEDED(hres)) {
|
||||
if(hres == S_OK && wcsicmp(bstr, bstr2))
|
||||
hres = S_FALSE;
|
||||
SysFreeString(bstr2);
|
||||
}
|
||||
SysFreeString(bstr);
|
||||
if(hres != S_OK)
|
||||
goto done;
|
||||
|
||||
bstr = NULL;
|
||||
hres = IUri_GetHost(uri, &bstr);
|
||||
if(hres != S_OK) {
|
||||
SysFreeString(bstr);
|
||||
goto done;
|
||||
}
|
||||
hres = IUri_GetHost(target, &bstr2);
|
||||
if(SUCCEEDED(hres)) {
|
||||
if(hres == S_OK && wcsicmp(bstr, bstr2))
|
||||
hres = 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(hres != S_OK) {
|
||||
if(FAILED(hres))
|
||||
goto done;
|
||||
no_port = TRUE; /* some protocols don't have ports (e.g. res) */
|
||||
}
|
||||
hres = IUri_GetPort(target, &port2);
|
||||
if(hres != S_OK) {
|
||||
if(FAILED(hres))
|
||||
goto done;
|
||||
if(no_port)
|
||||
hres = S_OK;
|
||||
}else if(no_port || port != port2) {
|
||||
hres = S_FALSE;
|
||||
}
|
||||
|
||||
done:
|
||||
IUri_Release(target);
|
||||
return hres;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI window_private_postMessage(IWineHTMLWindowPrivate *iface, VARIANT msg, BSTR targetOrigin, VARIANT transfer)
|
||||
{
|
||||
HTMLWindow *This = impl_from_IWineHTMLWindowPrivateVtbl(iface);
|
||||
HTMLInnerWindow *window = This->inner_window;
|
||||
DOMEvent *event;
|
||||
HRESULT hres;
|
||||
|
||||
TRACE("iface %p, msg %s, targetOrigin %s, transfer %s\n", iface, debugstr_variant(&msg),
|
||||
debugstr_w(targetOrigin), debugstr_variant(&transfer));
|
||||
|
||||
if(V_VT(&transfer) != VT_EMPTY && V_VT(&transfer) != VT_ERROR)
|
||||
FIXME("transfer not implemented, ignoring\n");
|
||||
|
||||
hres = check_target_origin(window, targetOrigin);
|
||||
if(hres != S_OK)
|
||||
return SUCCEEDED(hres) ? S_OK : hres;
|
||||
|
||||
switch(V_VT(&msg)) {
|
||||
case VT_EMPTY:
|
||||
case VT_NULL:
|
||||
case VT_VOID:
|
||||
case VT_I1:
|
||||
case VT_I2:
|
||||
case VT_I4:
|
||||
case VT_I8:
|
||||
case VT_UI1:
|
||||
case VT_UI2:
|
||||
case VT_UI4:
|
||||
case VT_UI8:
|
||||
case VT_INT:
|
||||
case VT_UINT:
|
||||
case VT_R4:
|
||||
case VT_R8:
|
||||
case VT_BOOL:
|
||||
case VT_BSTR:
|
||||
case VT_CY:
|
||||
case VT_DATE:
|
||||
case VT_DECIMAL:
|
||||
case VT_HRESULT:
|
||||
break;
|
||||
case VT_ERROR:
|
||||
V_VT(&msg) = VT_EMPTY;
|
||||
break;
|
||||
default:
|
||||
FIXME("Unsupported vt %d\n", V_VT(&msg));
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
if(!window->doc) {
|
||||
FIXME("No document\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
hres = create_message_event(window->doc, &msg, &event);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(dispex_compat_mode(&window->event_target.dispex) >= COMPAT_MODE_IE9) {
|
||||
struct post_message_task *task;
|
||||
if(!(task = malloc(sizeof(*task)))) {
|
||||
IDOMEvent_Release(&event->IDOMEvent_iface);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
/* Because message events can be sent to different windows, they get blocked by any context */
|
||||
task->header.thread_blocked = TRUE;
|
||||
task->event = event;
|
||||
return push_event_task(&task->header, window, post_message_proc, post_message_destr, window->task_magic);
|
||||
}
|
||||
|
||||
dispatch_event(&window->event_target, event);
|
||||
IDOMEvent_Release(&event->IDOMEvent_iface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI window_private_get_console(IWineHTMLWindowPrivate *iface, IDispatch **console)
|
||||
{
|
||||
HTMLWindow *This = impl_from_IWineHTMLWindowPrivateVtbl(iface);
|
||||
|
@ -3401,7 +3398,6 @@ static const IWineHTMLWindowPrivateVtbl WineHTMLWindowPrivateVtbl = {
|
|||
window_private_cancelAnimationFrame,
|
||||
window_private_get_console,
|
||||
window_private_matchMedia,
|
||||
window_private_postMessage,
|
||||
window_private_get_MutationObserver
|
||||
};
|
||||
|
||||
|
@ -4219,6 +4215,57 @@ static HRESULT IHTMLWindow3_setTimeout_hook(DispatchEx *dispex, WORD flags, DISP
|
|||
return dispex_call_builtin(dispex, DISPID_IHTMLWINDOW3_SETTIMEOUT, &new_dp, res, ei, caller);
|
||||
}
|
||||
|
||||
static HRESULT IHTMLWindow6_postMessage_hook(DispatchEx *dispex, WORD flags, DISPPARAMS *dp, VARIANT *res,
|
||||
EXCEPINFO *ei, IServiceProvider *caller)
|
||||
{
|
||||
HTMLInnerWindow *This = impl_from_DispatchEx(dispex);
|
||||
BSTR targetOrigin, converted_msg = NULL;
|
||||
VARIANT msg, transfer, converted;
|
||||
compat_mode_t compat_mode;
|
||||
HRESULT hres;
|
||||
|
||||
if(!(flags & DISPATCH_METHOD) || dp->cArgs < 2 || dp->cNamedArgs)
|
||||
return S_FALSE;
|
||||
compat_mode = dispex_compat_mode(&This->event_target.dispex);
|
||||
|
||||
msg = dp->rgvarg[dp->cArgs - 1];
|
||||
V_VT(&transfer) = VT_EMPTY;
|
||||
if(compat_mode >= COMPAT_MODE_IE10 && dp->cArgs > 2)
|
||||
transfer = dp->rgvarg[dp->cArgs - 3];
|
||||
|
||||
TRACE("(%p)->(msg %s, targetOrigin %s, transfer %s)\n", This, debugstr_variant(&msg),
|
||||
debugstr_variant(&dp->rgvarg[dp->cArgs - 2]), debugstr_variant(&transfer));
|
||||
|
||||
if(compat_mode < COMPAT_MODE_IE10 && V_VT(&msg) != VT_BSTR) {
|
||||
hres = change_type(&msg, &dp->rgvarg[dp->cArgs - 1], VT_BSTR, caller);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
converted_msg = V_BSTR(&msg);
|
||||
}
|
||||
|
||||
if(V_VT(&dp->rgvarg[dp->cArgs - 2]) == VT_BSTR) {
|
||||
targetOrigin = V_BSTR(&dp->rgvarg[dp->cArgs - 2]);
|
||||
V_BSTR(&converted) = NULL;
|
||||
}else {
|
||||
if(compat_mode < COMPAT_MODE_IE10) {
|
||||
SysFreeString(converted_msg);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
hres = change_type(&converted, &dp->rgvarg[dp->cArgs - 2], VT_BSTR, caller);
|
||||
if(FAILED(hres)) {
|
||||
SysFreeString(converted_msg);
|
||||
return hres;
|
||||
}
|
||||
targetOrigin = V_BSTR(&converted);
|
||||
}
|
||||
|
||||
hres = post_message(This, msg, targetOrigin, transfer, caller, compat_mode);
|
||||
|
||||
SysFreeString(V_BSTR(&converted));
|
||||
SysFreeString(converted_msg);
|
||||
return hres;
|
||||
}
|
||||
|
||||
static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode)
|
||||
{
|
||||
static const dispex_hook_t window2_hooks[] = {
|
||||
|
@ -4244,6 +4291,10 @@ static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compa
|
|||
{DISPID_IHTMLWINDOW4_CREATEPOPUP, NULL},
|
||||
{DISPID_UNKNOWN}
|
||||
};
|
||||
static const dispex_hook_t window6_hooks[] = {
|
||||
{DISPID_IHTMLWINDOW6_POSTMESSAGE, IHTMLWindow6_postMessage_hook},
|
||||
{DISPID_UNKNOWN}
|
||||
};
|
||||
|
||||
/* Hide props not available in IE10 */
|
||||
static const dispex_hook_t private_ie10_hooks[] = {
|
||||
|
@ -4259,6 +4310,7 @@ static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compa
|
|||
dispex_info_add_interface(info, IWineHTMLWindowPrivate_tid,
|
||||
compat_mode >= COMPAT_MODE_IE11 ? NULL : private_ie10_hooks);
|
||||
|
||||
dispex_info_add_interface(info, IHTMLWindow6_tid, window6_hooks);
|
||||
dispex_info_add_interface(info, IHTMLWindow5_tid, NULL);
|
||||
dispex_info_add_interface(info, IHTMLWindow4_tid, compat_mode >= COMPAT_MODE_IE11 ? window4_ie11_hooks : NULL);
|
||||
dispex_info_add_interface(info, IHTMLWindow3_tid, compat_mode >= COMPAT_MODE_IE11 ? window3_ie11_hooks : window3_hooks);
|
||||
|
@ -4290,10 +4342,7 @@ static const event_target_vtbl_t HTMLWindow_event_target_vtbl = {
|
|||
.set_current_event = HTMLWindow_set_current_event
|
||||
};
|
||||
|
||||
static const tid_t HTMLWindow_iface_tids[] = {
|
||||
IHTMLWindow6_tid,
|
||||
0
|
||||
};
|
||||
static const tid_t HTMLWindow_iface_tids[] = { 0 };
|
||||
|
||||
static dispex_static_data_t HTMLWindow_dispex = {
|
||||
"Window",
|
||||
|
|
|
@ -131,8 +131,6 @@ interface IWineHTMLWindowPrivate : IDispatch
|
|||
HRESULT console([retval, out] IDispatch **console);
|
||||
[id(53)]
|
||||
HRESULT matchMedia([in] BSTR media_query, [retval, out] IDispatch **media_query_list);
|
||||
[id(54)]
|
||||
HRESULT postMessage([in] VARIANT msg, [in] BSTR targetOrigin, [in, optional] VARIANT transfer);
|
||||
[propget, id(DISPID_IWINEHTMLWINDOWPRIVATE_MUTATIONOBSERVER)]
|
||||
HRESULT MutationObserver([retval, out] IDispatch **observer_ctor);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue