-- v2: mshtml: Implement contentType for XDomainRequest. mshtml: Implement timeout for XDomainRequest. mshtml: Implement XDomainRequest.open(). mshtml: Add XDomainRequest factory implementation. mshtml: Factor out XMLHttpRequest constructor init. mshtml: Factor out XMLHttpRequest creation.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
So it can be shared with XDomainRequest constructors.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/xmlhttprequest.c | 43 ++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 16 deletions(-)
diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index e6029b85bb2..5f4d16fba1d 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1503,19 +1503,16 @@ static inline struct constructor *impl_from_IHTMLXMLHttpRequestFactory(IHTMLXMLH DISPEX_IDISPATCH_IMPL(HTMLXMLHttpRequestFactory, IHTMLXMLHttpRequestFactory, impl_from_IHTMLXMLHttpRequestFactory(iface)->dispex)
-static HRESULT WINAPI HTMLXMLHttpRequestFactory_create(IHTMLXMLHttpRequestFactory *iface, IHTMLXMLHttpRequest **p) +static HRESULT create_xhr(HTMLInnerWindow *window, dispex_static_data_t *dispex, HTMLXMLHttpRequest **p) { - struct constructor *This = impl_from_IHTMLXMLHttpRequestFactory(iface); - HTMLXMLHttpRequest *ret; - nsIXMLHttpRequest *nsxhr; - nsIDOMEventTarget *nstarget; - XMLHttpReqEventListener *event_listener; + XMLHttpReqEventListener *event_listener; + nsIDOMEventTarget *nstarget; + nsIXMLHttpRequest *nsxhr; + HTMLXMLHttpRequest *ret; nsresult nsres; unsigned i;
- TRACE("(%p)->(%p)\n", This, p); - - nsxhr = create_nsxhr(This->window->dom_window); + nsxhr = create_nsxhr(window->dom_window); if(!nsxhr) return E_FAIL;
@@ -1533,15 +1530,15 @@ static HRESULT WINAPI HTMLXMLHttpRequestFactory_create(IHTMLXMLHttpRequestFactor }
ret->nsxhr = nsxhr; - ret->window = This->window; + ret->window = window; ret->task_magic = get_task_target_magic(); - IHTMLWindow2_AddRef(&This->window->base.IHTMLWindow2_iface); + IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface);
ret->IHTMLXMLHttpRequest_iface.lpVtbl = &HTMLXMLHttpRequestVtbl; ret->IHTMLXMLHttpRequest2_iface.lpVtbl = &HTMLXMLHttpRequest2Vtbl; ret->IWineXMLHttpRequestPrivate_iface.lpVtbl = &WineXMLHttpRequestPrivateVtbl; ret->IProvideClassInfo2_iface.lpVtbl = &ProvideClassInfo2Vtbl; - init_event_target(&ret->event_target, &XMLHttpRequest_dispex, This->window); + init_event_target(&ret->event_target, dispex, window);
/* Always register the handlers because we need them to track state */ event_listener->nsIDOMEventListener_iface.lpVtbl = &XMLHttpReqEventListenerVtbl; @@ -1567,10 +1564,24 @@ static HRESULT WINAPI HTMLXMLHttpRequestFactory_create(IHTMLXMLHttpRequestFactor } nsIDOMEventTarget_Release(nstarget);
- *p = &ret->IHTMLXMLHttpRequest_iface; + *p = ret; return S_OK; }
+static HRESULT WINAPI HTMLXMLHttpRequestFactory_create(IHTMLXMLHttpRequestFactory *iface, IHTMLXMLHttpRequest **p) +{ + struct constructor *This = impl_from_IHTMLXMLHttpRequestFactory(iface); + HTMLXMLHttpRequest *xhr; + HRESULT hres; + + TRACE("(%p)->(%p)\n", This, p); + + hres = create_xhr(This->window, &XMLHttpRequest_dispex, &xhr); + if(SUCCEEDED(hres)) + *p = &xhr->IHTMLXMLHttpRequest_iface; + return hres; +} + static const IHTMLXMLHttpRequestFactoryVtbl HTMLXMLHttpRequestFactoryVtbl = { HTMLXMLHttpRequestFactory_QueryInterface, HTMLXMLHttpRequestFactory_AddRef, @@ -1596,7 +1607,7 @@ static HRESULT HTMLXMLHttpRequestFactory_value(DispatchEx *iface, LCID lcid, WOR VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { struct constructor *This = constructor_from_DispatchEx(iface); - IHTMLXMLHttpRequest *xhr; + HTMLXMLHttpRequest *xhr; HRESULT hres;
TRACE("\n"); @@ -1606,12 +1617,12 @@ static HRESULT HTMLXMLHttpRequestFactory_value(DispatchEx *iface, LCID lcid, WOR return E_NOTIMPL; }
- hres = IHTMLXMLHttpRequestFactory_create((IHTMLXMLHttpRequestFactory*)&This->iface, &xhr); + hres = create_xhr(This->window, &XMLHttpRequest_dispex, &xhr); if(FAILED(hres)) return hres;
V_VT(res) = VT_DISPATCH; - V_DISPATCH(res) = (IDispatch*)xhr; + V_DISPATCH(res) = (IDispatch*)&xhr->IHTMLXMLHttpRequest_iface; return S_OK; }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
So it can be shared with XDomainRequest constructors.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/xmlhttprequest.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 5f4d16fba1d..3dd4561e6ff 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1646,14 +1646,13 @@ static dispex_static_data_t HTMLXMLHttpRequestFactory_dispex = { .iface_tids = HTMLXMLHttpRequestFactory_iface_tids, };
-static HRESULT HTMLXMLHttpRequestFactory_init(struct constructor *constr) +static HRESULT init_constructor(struct constructor *constr, dispex_static_data_t *dispex, const void *vtbl) { struct constructor *create; HRESULT hres;
- constr->iface.lpVtbl = (const IUnknownVtbl*)&HTMLXMLHttpRequestFactoryVtbl; - init_dispatch(&constr->dispex, &HTMLXMLHttpRequestFactory_dispex, constr->window, - dispex_compat_mode(&constr->window->event_target.dispex)); + constr->iface.lpVtbl = vtbl; + init_dispatch(&constr->dispex, dispex, constr->window, dispex_compat_mode(&constr->window->event_target.dispex));
if(!constr->window->jscript) return S_OK; @@ -1679,6 +1678,11 @@ static HRESULT HTMLXMLHttpRequestFactory_init(struct constructor *constr) return hres; }
+static HRESULT HTMLXMLHttpRequestFactory_init(struct constructor *constr) +{ + return init_constructor(constr, &HTMLXMLHttpRequestFactory_dispex, &HTMLXMLHttpRequestFactoryVtbl); +} + static const tid_t HTMLXMLHttpRequest_iface_tids[] = { IHTMLXMLHttpRequest2_tid, 0
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlwindow.c | 30 ++- dlls/mshtml/mshtml_private.h | 4 + dlls/mshtml/tests/documentmode.js | 20 +- dlls/mshtml/tests/dom.c | 127 ++++++++++++- dlls/mshtml/tests/events.c | 19 ++ dlls/mshtml/xmlhttprequest.c | 298 ++++++++++++++++++++++++++++++ 6 files changed, 491 insertions(+), 7 deletions(-)
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index e5e2481299a..edd0de177bd 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -1974,8 +1974,26 @@ static HRESULT WINAPI HTMLWindow6_put_XDomainRequest(IHTMLWindow6 *iface, VARIAN static HRESULT WINAPI HTMLWindow6_get_XDomainRequest(IHTMLWindow6 *iface, VARIANT *p) { HTMLWindow *This = impl_from_IHTMLWindow6(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + HTMLInnerWindow *window = This->inner_window; + DispatchEx *constr; + HRESULT hres; + + TRACE("(%p)->(%p)\n", This, p); + + if(This->outer_window->readystate == READYSTATE_UNINITIALIZED) { + V_VT(p) = VT_EMPTY; + return S_OK; + } + + hres = get_constructor(window, OBJID_XDomainRequest, &constr); + if(FAILED(hres)) + return hres; + + V_VT(p) = VT_DISPATCH; + V_DISPATCH(p) = (IDispatch*)&constr->IWineJSDispatchHost_iface; + IDispatch_AddRef(V_DISPATCH(p)); + + return S_OK; }
static HRESULT WINAPI HTMLWindow6_get_sessionStorage(IHTMLWindow6 *iface, IHTMLStorage **p) @@ -4212,10 +4230,14 @@ 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[] = { + static const dispex_hook_t window6_ie9_hooks[] = { + {DISPID_IHTMLWINDOW6_XDOMAINREQUEST}, + + /* Common for all modes */ {DISPID_IHTMLWINDOW6_POSTMESSAGE, IHTMLWindow6_postMessage_hook}, {DISPID_UNKNOWN} }; + const dispex_hook_t *const window6_hooks = window6_ie9_hooks + 1;
if(compat_mode >= COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLWindow7_tid, NULL); @@ -4224,7 +4246,7 @@ static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compa if(compat_mode >= COMPAT_MODE_IE10) dispex_info_add_interface(info, IWineHTMLWindowPrivate_tid, NULL);
- dispex_info_add_interface(info, IHTMLWindow6_tid, window6_hooks); + dispex_info_add_interface(info, IHTMLWindow6_tid, compat_mode >= COMPAT_MODE_IE9 ? window6_ie9_hooks : window6_hooks); if(compat_mode < COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLWindow5_tid, NULL); dispex_info_add_interface(info, IHTMLWindow4_tid, compat_mode >= COMPAT_MODE_IE11 ? window4_ie11_hooks : NULL); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index d014c34ba7c..6e4a58aee55 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -159,6 +159,7 @@ struct constructor; XDIID(DispHTMLW3CComputedStyle) \ XDIID(DispHTMLWindow2) \ XDIID(DispHTMLXMLHttpRequest) \ + XDIID(DispXDomainRequest) \ XDIID(DispSVGCircleElement) \ XDIID(DispSVGSVGElement) \ XDIID(DispSVGTSpanElement) \ @@ -295,6 +296,8 @@ struct constructor; XIID(IHTMLXMLHttpRequest) \ XIID(IHTMLXMLHttpRequest2) \ XIID(IHTMLXMLHttpRequestFactory) \ + XIID(IHTMLXDomainRequest) \ + XIID(IHTMLXDomainRequestFactory) \ XIID(IOmHistory) \ XIID(IOmNavigator) \ XIID(ISVGCircleElement) \ @@ -511,6 +514,7 @@ typedef struct { X(TextRange) \ X(UIEvent) \ X(Window) \ + X(XDomainRequest) \ X(XMLDocument) \ X(XMLHttpRequest)
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index faac18c45a3..acee34c8bc1 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -329,6 +329,7 @@ sync_test("builtin_toString", function() { if(v < 11) { test("eventObject", document.createEventObject(), "MSEventObj"); test("selection", document.selection, "MSSelection"); + test("XDomainRequest", new XDomainRequest(), "XDomainRequest"); } if(v >= 9) { test("computedStyle", window.getComputedStyle(e), "CSSStyleDeclaration"); @@ -986,6 +987,7 @@ sync_test("window_props", function() { test_exposed("HTMLDocument", v === 8 || v >= 11, v === 8); test_exposed("XMLDocument", v >= 11); test_exposed("DOMParser", v >= 9); + test_exposed("XDomainRequest", v < 11); test_exposed("MutationObserver", v >= 11); test_exposed("PageTransitionEvent", v >= 11); test_exposed("ProgressEvent", v >= 10); @@ -1260,6 +1262,7 @@ sync_test("constructor props", function() { test_exposed(XMLHttpRequest, "create", true); if(v >= 9) test_exposed(DOMParser, "create", false); if(v >= 11) test_exposed(MutationObserver, "create", false); + if(v < 11) test_exposed(XDomainRequest, "create", true); });
sync_test("createElement_inline_attr", function() { @@ -3931,6 +3934,11 @@ sync_test("prototypes", function() { check(new XMLHttpRequest(), XMLHttpRequest.prototype, "xhr"); check(XMLHttpRequest.prototype, Object.prototype, "xhr prototype"); check(XMLHttpRequest, Function.prototype, "xhr constructor"); + if(v < 11) { + check(new XDomainRequest(), XDomainRequest.prototype, "xdr"); + check(XDomainRequest.prototype, Object.prototype, "xdr prototype"); + check(XDomainRequest, Function.prototype, "xdr constructor"); + } check(document.createElement("img"), HTMLImageElement.prototype, "img elem"); check(HTMLImageElement.prototype, HTMLElement.prototype, "img elem prototype"); check(Image, Function.prototype, "Image constructor"); @@ -4481,8 +4489,16 @@ sync_test("prototype props", function() { check(StyleSheet, [ "disabled", "href", "media", "ownerNode", "parentStyleSheet", "title", "type" ]); check(Text, [ "removeNode", "replaceNode", "replaceWholeText", "splitText", "swapNode", "wholeText" ], [ "replaceWholeText", "wholeText" ]); check(UIEvent, [ "detail", "initUIEvent", "view" ], null, [ "deviceSessionId" ]); + if(v < 11) + check(XDomainRequest, [ "abort", "contentType", "onerror", "onload", "onprogress", "ontimeout", "open", "responseText", "send", "timeout" ]); if(v >= 11) check(XMLDocument, []); + check(XMLHttpRequest, [ + "DONE", "HEADERS_RECEIVED", "LOADING", "OPENED", "UNSENT", "abort", "addEventListener", "dispatchEvent", "getAllResponseHeaders", "getResponseHeader", ["msCaching",11], + ["msCachingEnabled",11], ["onabort",10], ["onerror",10], "onload", ["onloadend",10], ["onloadstart",10], ["onprogress",10], "onreadystatechange", "ontimeout", "open", + ["overrideMimeType",11], "readyState", "removeEventListener", ["response",10], "responseBody", "responseText", ["responseType",10], "responseXML", "send", + "setRequestHeader", "status", "statusText", "timeout", ["upload",10], ["withCredentials",10] + ], [ "DONE", "HEADERS_RECEIVED", "LOADING", "OPENED", "UNSENT", ["msCaching",11], ["msCachingEnabled",11] ]); });
sync_test("constructors", function() { @@ -4491,6 +4507,8 @@ sync_test("constructors", function() { return;
var ctors = [ "DOMParser", "Image", "Option", "XMLHttpRequest" ]; + if (v < 11) + ctors.push("XDomainRequest"); if (v >= 11) ctors.push("MutationObserver"); for(i = 0; i < ctors.length; i++) { @@ -4658,7 +4676,7 @@ async_test("window own props", function() { ["Uint8Array",10], ["Uint8ClampedArray",11], ["URL",10], ["ValidityState",10], ["VideoPlaybackQuality",11], ["WebGLActiveInfo",11], ["WebGLBuffer",11], ["WebGLContextEvent",11], ["WebGLFramebuffer",11], ["WebGLObject",11], ["WebGLProgram",11], ["WebGLRenderbuffer",11], ["WebGLRenderingContext",11], ["WebGLShader",11], ["WebGLShaderPrecisionFormat",11], ["WebGLTexture",11], ["WebGLUniformLocation",11], ["WEBGL_compressed_texture_s3tc",11], ["WEBGL_debug_renderer_info",11], ["WebSocket",10], "WheelEvent", ["Worker",10], - ["XDomainRequest",9,10], ["XMLHttpRequestEventTarget",10], "XMLSerializer" + ["XMLHttpRequestEventTarget",10], "XMLSerializer" ]); next_test(); } diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 7250ffea636..f3aec7d9046 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -2277,6 +2277,47 @@ static void _set_object_name(unsigned line, IHTMLElement *elem, const WCHAR *nam _test_object_name(line, elem, name); }
+static void test_factory(void *window, void *factory, const WCHAR *name, const WCHAR *value) +{ + IDispatch *disp, *disp2, *window_disp = window; + DISPPARAMS dp = { NULL, NULL, 0, 0 }; + BSTR bstr = SysAllocString(name); + VARIANT var, val; + DISPID dispid; + HRESULT hres; + + hres = IDispatch_GetIDsOfNames(window_disp, &IID_NULL, &bstr, 1, 0, &dispid); + SysFreeString(bstr); + ok(hres == S_OK, "GetIDsOfNames(%s) failed: %08lx\n", wine_dbgstr_w(name), hres); + + hres = IDispatch_Invoke(window_disp, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &var, NULL, NULL); + ok(hres == S_OK, "Invoke(%s) failed: %08lx\n", wine_dbgstr_w(name), hres); + ok(V_VT(&var) == VT_DISPATCH, "VT(%s) = %d\n", wine_dbgstr_w(name), V_VT(&var)); + + hres = IUnknown_QueryInterface((IUnknown*)factory, &IID_IDispatch, (void**)&disp); + ok(hres == S_OK, "Could not get IDispatch from %s factory: %08lx\n", wine_dbgstr_w(name), hres); + hres = IUnknown_QueryInterface(V_DISPATCH(&var), &IID_IDispatch, (void**)&disp2); + ok(hres == S_OK, "Could not get IDispatch from window.%s factory: %08lx\n", wine_dbgstr_w(name), hres); + todo_wine + ok(disp != disp2, "window.%s and the builtin getter returned same dispatch\n", wine_dbgstr_w(name)); + IDispatch_Release(disp2); + + hres = IDispatch_Invoke(disp, DISPID_VALUE, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &val, NULL, NULL); + IDispatch_Release(disp); + ok(hres == S_OK, "Invoke(DISPID_VALUE) for %s builtin getter returned: %08lx\n", wine_dbgstr_w(name), hres); + ok(V_VT(&val) == VT_BSTR, "V_VT(value) for %s builtin getter = %d\n", wine_dbgstr_w(name), V_VT(&val)); + ok(!lstrcmpW(V_BSTR(&val), L"[object]"), "value for %s builtin getter = %s\n", wine_dbgstr_w(name), wine_dbgstr_w(V_BSTR(&val))); + VariantClear(&val); + + hres = IDispatch_Invoke(V_DISPATCH(&var), DISPID_VALUE, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &val, NULL, NULL); + VariantClear(&var); + ok(hres == S_OK, "Invoke(DISPID_VALUE) for %s: %08lx\n", wine_dbgstr_w(name), hres); + ok(V_VT(&val) == VT_BSTR, "V_VT(value) for %s = %d\n", wine_dbgstr_w(name), V_VT(&val)); + todo_wine + ok(!lstrcmpW(V_BSTR(&val), value), "value for %s = %s\n", wine_dbgstr_w(name), wine_dbgstr_w(V_BSTR(&val))); + VariantClear(&val); +} + #define create_option_elem(d,t,v) _create_option_elem(__LINE__,d,t,v) static IHTMLOptionElement *_create_option_elem(unsigned line, IHTMLDocument2 *doc, const WCHAR *txt, const WCHAR *val) @@ -2293,10 +2334,11 @@ static IHTMLOptionElement *_create_option_elem(unsigned line, IHTMLDocument2 *do ok_(__FILE__,line) (hres == S_OK, "get_parentElement failed: %08lx\n", hres);
hres = IHTMLWindow2_get_Option(window, &factory); - IHTMLWindow2_Release(window); ok_(__FILE__,line) (hres == S_OK, "get_Option failed: %08lx\n", hres);
+ test_factory(window, factory, L"Option", L"[object HTMLOptionElement]"); test_disp((IUnknown*)factory, &IID_IHTMLOptionElementFactory, NULL, L"[object]"); + IHTMLWindow2_Release(window);
V_VT(&text) = VT_BSTR; V_BSTR(&text) = SysAllocString(txt); @@ -2395,11 +2437,12 @@ static IHTMLImgElement *_create_img_elem(unsigned line, IHTMLDocument2 *doc, ok_(__FILE__,line) (hres == S_OK, "get_parentElement failed: %08lx\n", hres);
hres = IHTMLWindow2_get_Image(window, &factory); - IHTMLWindow2_Release(window); ok_(__FILE__,line) (hres == S_OK, "get_Image failed: %08lx\n", hres);
test_ifaces((IUnknown*)factory, img_factory_iids); + test_factory(window, factory, L"Image", L"[object HTMLImageElement]"); test_disp((IUnknown*)factory, &IID_IHTMLImageElementFactory, NULL, L"[object]"); + IHTMLWindow2_Release(window);
if(wdth >= 0){ wsprintfW(buf, L"%d", wdth); @@ -7987,6 +8030,8 @@ static void test_xmlhttprequest(IHTMLWindow5 *window) ok(hres == S_OK, "QueryInterface(&IID_IHTMLXMLHttpRequestFactory) failed: %08lx\n", hres); ok(factory != NULL, "factory == NULL\n");
+ test_factory(window, factory, L"XMLHttpRequest", L"[object XMLHttpRequest]"); + xml = NULL; hres = IHTMLXMLHttpRequestFactory_create(factory, &xml); ok(hres == S_OK, "create failed: %08lx\n", hres); @@ -7999,6 +8044,41 @@ static void test_xmlhttprequest(IHTMLWindow5 *window) VariantClear(&var); }
+static void test_xdomainrequest(IHTMLWindow6 *window) +{ + IHTMLXDomainRequestFactory *factory; + IHTMLXDomainRequest *xdr; + HRESULT hres; + VARIANT var; + + hres = IHTMLWindow6_get_XDomainRequest(window, &var); + ok(hres == S_OK, "get_XDomainRequest failed: %08lx\n", hres); + ok(V_VT(&var) == VT_DISPATCH || broken(V_VT(&var) == VT_EMPTY), "expect VT_DISPATCH, got %s\n", debugstr_variant(&var)); + + if(V_VT(&var) == VT_EMPTY) { + win_skip("Native XDomainRequest support is missing or disabled.\n"); + return; + } + + factory = NULL; + hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IHTMLXDomainRequestFactory, (void**)&factory); + ok(hres == S_OK, "QueryInterface(&IID_IHTMLXDomainRequestFactory) failed: %08lx\n", hres); + ok(factory != NULL, "factory == NULL\n"); + + test_factory(window, factory, L"XDomainRequest", L"[object XDomainRequest]"); + + xdr = NULL; + hres = IHTMLXDomainRequestFactory_create(factory, &xdr); + ok(hres == S_OK, "create failed: %08lx\n", hres); + ok(xdr != NULL, "xdr == NULL\n"); + if(is_ie9plus) + test_disp((IUnknown*)xdr, &DIID_DispXDomainRequest, NULL, L"[object]"); + + IHTMLXDomainRequest_Release(xdr); + IHTMLXDomainRequestFactory_Release(factory); + VariantClear(&var); +} + static void test_read_only_style(IHTMLCSSStyleDeclaration *style) { BSTR none = SysAllocString(L"none"), display = SysAllocString(L"display"), str; @@ -8024,6 +8104,7 @@ static void test_window(IHTMLDocument2 *doc) { IHTMLWindow2 *window, *window2, *self, *parent; IHTMLWindow5 *window5; + IHTMLWindow6 *window6; IHTMLWindow7 *window7; IHTMLDocument2 *doc2 = NULL; IDispatch *disp; @@ -8128,6 +8209,15 @@ static void test_window(IHTMLDocument2 *doc) win_skip("IHTMLWindow5 not supported!\n"); }
+ hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow6, (void**)&window6); + if(SUCCEEDED(hres)) { + ok(window6 != NULL, "window6 == NULL\n"); + test_xdomainrequest(window6); + IHTMLWindow6_Release(window6); + }else { + win_skip("IHTMLWindow6 not supported!\n"); + } + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow7, (void**)&window7); if(SUCCEEDED(hres)) { IHTMLCSSStyleDeclaration *computed_style; @@ -8353,6 +8443,29 @@ static void test_xhr(IHTMLDocument2 *doc) IDispatchEx_Release(dispex); }
+static void test_xdr(IHTMLDocument2 *doc) +{ + IHTMLWindow2 *window; + IDispatchEx *dispex; + DISPID id; + BSTR str; + HRESULT hres; + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx iface: %08lx\n", hres); + + str = SysAllocString(L"XDomainRequest"); + hres = IDispatchEx_GetDispID(dispex, str, 0, &id); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + SysFreeString(str); + + IHTMLWindow2_Release(window); + IDispatchEx_Release(dispex); +} + static void test_defaults(IHTMLDocument2 *doc) { IHTMLStyleSheetsCollection *stylesheetcol; @@ -8426,6 +8539,7 @@ static void test_defaults(IHTMLDocument2 *doc) }
test_xhr(doc); + test_xdr(doc);
hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLBodyElement, (void**)&body); ok(hres == S_OK, "Could not get IHTMBodyElement: %08lx\n", hres); @@ -13104,6 +13218,7 @@ static void test_document_mode_lock(void) IEventTarget *event_target; IPersistStreamInit *init; IHTMLWindow7 *window7; + IHTMLWindow6 *window6; IHTMLWindow5 *window5; IHTMLWindow2 *window; IDispatchEx *dispex; @@ -13157,6 +13272,14 @@ static void test_document_mode_lock(void) ok(V_VT(&var) == VT_EMPTY, "V_VT(XMLHttpRequest) = %d\n", V_VT(&var)); IHTMLWindow5_Release(window5);
+ V_VT(&var) = VT_NULL; + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow6, (void**)&window6); + ok(hres == S_OK, "Could not get IHTMLWindow6: %08lx\n", hres); + hres = IHTMLWindow6_get_XDomainRequest(window6, &var); + ok(hres == S_OK, "get_XDomainRequest failed: %08lx\n", hres); + ok(V_VT(&var) == VT_EMPTY, "V_VT(XDomainRequest) = %d\n", V_VT(&var)); + IHTMLWindow6_Release(window6); + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow7, (void**)&window7); ok(hres == S_OK, "Could not get IHTMLWindow7: %08lx\n", hres); hres = IHTMLWindow7_get_performance(window7, &var); diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index bdfbb6c6b78..fbb5a9535ee 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -4149,6 +4149,7 @@ static void test_doc_obj(IHTMLDocument2 *doc) IHTMLOptionElementFactory *option, *option2; IHTMLImageElementFactory *image, *image2; IHTMLXMLHttpRequestFactory *xhr, *xhr2; + IHTMLXDomainRequestFactory *xdr, *xdr2; IHTMLDocument2 *doc_node, *doc_node2; IOmNavigator *navigator, *navigator2; IHTMLLocation *location, *location2; @@ -4307,7 +4308,14 @@ static void test_doc_obj(IHTMLDocument2 *doc) ok(hres == S_OK, "Could not get IHTMLWindow6: %08lx\n", hres); hres = IHTMLWindow6_get_sessionStorage(window6, &storage); ok(hres == S_OK, "get_sessionStorage failed: %08lx\n", hres); + + hres = IHTMLWindow6_get_XDomainRequest(window6, &res); + ok(hres == S_OK, "get_XDomainRequest failed: %08lx\n", hres); + ok(V_VT(&res) == VT_DISPATCH, "V_VT(XDomainRequest) = %d\n", V_VT(&res)); + hres = IDispatch_QueryInterface(V_DISPATCH(&res), &IID_IHTMLXDomainRequestFactory, (void**)&xdr); + ok(hres == S_OK, "Could not get IHTMLXDomainRequestFactory: %08lx\n", hres); IHTMLWindow6_Release(window6); + VariantClear(&res);
hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow7, (void**)&window7); ok(hres == S_OK, "Could not get IHTMLWindow7: %08lx\n", hres); @@ -4491,7 +4499,18 @@ static void test_doc_obj(IHTMLDocument2 *doc) ok(storage != storage2, "storage == storage2\n"); IHTMLStorage_Release(storage2); IHTMLStorage_Release(storage); + + ok(hres == S_OK, "Could not get IHTMLWindow6: %08lx\n", hres); + hres = IHTMLWindow6_get_XDomainRequest(window6, &res); + ok(hres == S_OK, "get_XDomainRequest failed: %08lx\n", hres); + ok(V_VT(&res) == VT_DISPATCH, "V_VT(XDomainRequest) = %d\n", V_VT(&res)); + hres = IDispatch_QueryInterface(V_DISPATCH(&res), &IID_IHTMLXDomainRequestFactory, (void**)&xdr2); + ok(hres == S_OK, "Could not get IHTMLXDomainRequestFactory: %08lx\n", hres); + ok(xdr != xdr2, "xdr == xdr2\n"); + IHTMLXDomainRequestFactory_Release(xdr2); + IHTMLXDomainRequestFactory_Release(xdr); IHTMLWindow6_Release(window6); + VariantClear(&res);
hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow7, (void**)&window7); ok(hres == S_OK, "Could not get IHTMLWindow7: %08lx\n", hres); diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 3dd4561e6ff..5f042dc708b 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -136,6 +136,7 @@ struct HTMLXMLHttpRequest { IHTMLXMLHttpRequest2 IHTMLXMLHttpRequest2_iface; IWineXMLHttpRequestPrivate IWineXMLHttpRequestPrivate_iface; IProvideClassInfo2 IProvideClassInfo2_iface; + IHTMLXDomainRequest IHTMLXDomainRequest_iface; /* only for XDomainRequests */ LONG task_magic; LONG ready_state; response_type_t response_type; @@ -1695,3 +1696,300 @@ dispex_static_data_t XMLHttpRequest_dispex = { .iface_tids = HTMLXMLHttpRequest_iface_tids, .init_info = HTMLXMLHttpRequest_init_dispex_info, }; + + + +/* IHTMLXDomainRequest */ +static inline HTMLXMLHttpRequest *impl_from_IHTMLXDomainRequest(IHTMLXDomainRequest *iface) +{ + return CONTAINING_RECORD(iface, HTMLXMLHttpRequest, IHTMLXDomainRequest_iface); +} + +DISPEX_IDISPATCH_IMPL(HTMLXDomainRequest, IHTMLXDomainRequest, + impl_from_IHTMLXDomainRequest(iface)->event_target.dispex) + +static HRESULT WINAPI HTMLXDomainRequest_get_responseText(IHTMLXDomainRequest *iface, BSTR *p) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + + return HTMLXMLHttpRequest_get_responseText(&This->IHTMLXMLHttpRequest_iface, p); +} + +static HRESULT WINAPI HTMLXDomainRequest_put_timeout(IHTMLXDomainRequest *iface, LONG v) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + + FIXME("(%p)->(%ld)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLXDomainRequest_get_timeout(IHTMLXDomainRequest *iface, LONG *p) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLXDomainRequest_get_contentType(IHTMLXDomainRequest *iface, BSTR *p) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLXDomainRequest_put_onprogress(IHTMLXDomainRequest *iface, VARIANT v) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + + return set_event_handler(&This->event_target, EVENTID_PROGRESS, &v); +} + +static HRESULT WINAPI HTMLXDomainRequest_get_onprogress(IHTMLXDomainRequest *iface, VARIANT *p) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%p)\n", This, p); + + return get_event_handler(&This->event_target, EVENTID_PROGRESS, p); +} + +static HRESULT WINAPI HTMLXDomainRequest_put_onerror(IHTMLXDomainRequest *iface, VARIANT v) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + + return set_event_handler(&This->event_target, EVENTID_ERROR, &v); +} + +static HRESULT WINAPI HTMLXDomainRequest_get_onerror(IHTMLXDomainRequest *iface, VARIANT *p) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%p)\n", This, p); + + return get_event_handler(&This->event_target, EVENTID_ERROR, p); +} + +static HRESULT WINAPI HTMLXDomainRequest_put_ontimeout(IHTMLXDomainRequest *iface, VARIANT v) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + + return set_event_handler(&This->event_target, EVENTID_TIMEOUT, &v); +} + +static HRESULT WINAPI HTMLXDomainRequest_get_ontimeout(IHTMLXDomainRequest *iface, VARIANT *p) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%p)\n", This, p); + + return get_event_handler(&This->event_target, EVENTID_TIMEOUT, p); +} + +static HRESULT WINAPI HTMLXDomainRequest_put_onload(IHTMLXDomainRequest *iface, VARIANT v) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + + return set_event_handler(&This->event_target, EVENTID_LOAD, &v); +} + +static HRESULT WINAPI HTMLXDomainRequest_get_onload(IHTMLXDomainRequest *iface, VARIANT *p) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%p)\n", This, p); + + return get_event_handler(&This->event_target, EVENTID_LOAD, p); +} + +static HRESULT WINAPI HTMLXDomainRequest_abort(IHTMLXDomainRequest *iface) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + return HTMLXMLHttpRequest_abort(&This->IHTMLXMLHttpRequest_iface); +} + +static HRESULT WINAPI HTMLXDomainRequest_open(IHTMLXDomainRequest *iface, BSTR bstrMethod, BSTR bstrUrl) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + + FIXME("(%p)->(%s %s)\n", This, debugstr_w(bstrMethod), debugstr_w(bstrUrl)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLXDomainRequest_send(IHTMLXDomainRequest *iface, VARIANT varBody) +{ + HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + + return HTMLXMLHttpRequest_send(&This->IHTMLXMLHttpRequest_iface, varBody); +} + +static const IHTMLXDomainRequestVtbl HTMLXDomainRequestVtbl = { + HTMLXDomainRequest_QueryInterface, + HTMLXDomainRequest_AddRef, + HTMLXDomainRequest_Release, + HTMLXDomainRequest_GetTypeInfoCount, + HTMLXDomainRequest_GetTypeInfo, + HTMLXDomainRequest_GetIDsOfNames, + HTMLXDomainRequest_Invoke, + HTMLXDomainRequest_get_responseText, + HTMLXDomainRequest_put_timeout, + HTMLXDomainRequest_get_timeout, + HTMLXDomainRequest_get_contentType, + HTMLXDomainRequest_put_onprogress, + HTMLXDomainRequest_get_onprogress, + HTMLXDomainRequest_put_onerror, + HTMLXDomainRequest_get_onerror, + HTMLXDomainRequest_put_ontimeout, + HTMLXDomainRequest_get_ontimeout, + HTMLXDomainRequest_put_onload, + HTMLXDomainRequest_get_onload, + HTMLXDomainRequest_abort, + HTMLXDomainRequest_open, + HTMLXDomainRequest_send +}; + +static void *HTMLXDomainRequest_query_interface(DispatchEx *dispex, REFIID riid) +{ + HTMLXMLHttpRequest *This = impl_from_DispatchEx(dispex); + + if(IsEqualGUID(&IID_IHTMLXDomainRequest, riid)) + return &This->IHTMLXDomainRequest_iface; + + return EventTarget_query_interface(&This->event_target, riid); +} + +static const event_target_vtbl_t HTMLXDomainRequest_event_target_vtbl = { + { + .query_interface = HTMLXDomainRequest_query_interface, + .destructor = HTMLXMLHttpRequest_destructor, + .traverse = HTMLXMLHttpRequest_traverse, + .unlink = HTMLXMLHttpRequest_unlink, + .last_release = HTMLXMLHttpRequest_last_release + }, + .get_gecko_target = HTMLXMLHttpRequest_get_gecko_target, + .bind_event = HTMLXMLHttpRequest_bind_event +}; + +static void HTMLXDomainRequest_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) +{ + dispex_info_add_interface(info, IHTMLXDomainRequest_tid, NULL); +} + + +/* IHTMLXDomainRequestFactory */ +static inline struct constructor *impl_from_IHTMLXDomainRequestFactory(IHTMLXDomainRequestFactory *iface) +{ + return CONTAINING_RECORD(iface, struct constructor, iface); +} + +DISPEX_IDISPATCH_IMPL(HTMLXDomainRequestFactory, IHTMLXDomainRequestFactory, + impl_from_IHTMLXDomainRequestFactory(iface)->dispex) + +static HRESULT WINAPI HTMLXDomainRequestFactory_create(IHTMLXDomainRequestFactory *iface, IHTMLXDomainRequest **p) +{ + struct constructor *This = impl_from_IHTMLXDomainRequestFactory(iface); + HTMLXMLHttpRequest *xhr; + HRESULT hres; + + TRACE("(%p)->(%p)\n", This, p); + + hres = create_xhr(This->window, &XDomainRequest_dispex, &xhr); + if(FAILED(hres)) + return hres; + + xhr->IHTMLXDomainRequest_iface.lpVtbl = &HTMLXDomainRequestVtbl; + + *p = &xhr->IHTMLXDomainRequest_iface; + return hres; +} + +static const IHTMLXDomainRequestFactoryVtbl HTMLXDomainRequestFactoryVtbl = { + HTMLXDomainRequestFactory_QueryInterface, + HTMLXDomainRequestFactory_AddRef, + HTMLXDomainRequestFactory_Release, + HTMLXDomainRequestFactory_GetTypeInfoCount, + HTMLXDomainRequestFactory_GetTypeInfo, + HTMLXDomainRequestFactory_GetIDsOfNames, + HTMLXDomainRequestFactory_Invoke, + HTMLXDomainRequestFactory_create +}; + +static void *HTMLXDomainRequestFactory_query_interface(DispatchEx *dispex, REFIID riid) +{ + struct constructor *This = constructor_from_DispatchEx(dispex); + + if(IsEqualGUID(&IID_IHTMLXDomainRequestFactory, riid)) + return &This->iface; + + return NULL; +} + +static HRESULT HTMLXDomainRequestFactory_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *params, + VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + struct constructor *This = constructor_from_DispatchEx(dispex); + IHTMLXDomainRequest *xdr; + HRESULT hres; + + TRACE("\n"); + + if(flags != DISPATCH_CONSTRUCT) { + FIXME("flags %x not supported\n", flags); + return E_NOTIMPL; + } + + hres = HTMLXDomainRequestFactory_create((IHTMLXDomainRequestFactory*)&This->iface, &xdr); + if(FAILED(hres)) + return hres; + + V_VT(res) = VT_DISPATCH; + V_DISPATCH(res) = (IDispatch*)xdr; + return hres; +} + +static const dispex_static_data_vtbl_t HTMLXDomainRequestFactory_dispex_vtbl = { + .query_interface = HTMLXDomainRequestFactory_query_interface, + .destructor = constructor_destructor, + .traverse = constructor_traverse, + .unlink = constructor_unlink, + .value = HTMLXDomainRequestFactory_value, +}; + +static const tid_t HTMLXDomainRequestFactory_iface_tids[] = { + IHTMLXDomainRequestFactory_tid, + 0 +}; +static dispex_static_data_t HTMLXDomainRequestFactory_dispex = { + .name = "XDomainRequest", + .constructor_id = OBJID_XDomainRequest, + .vtbl = &HTMLXDomainRequestFactory_dispex_vtbl, + .disp_tid = IHTMLXDomainRequestFactory_tid, + .iface_tids = HTMLXDomainRequestFactory_iface_tids, +}; + +static HRESULT HTMLXDomainRequestFactory_init(struct constructor *constr) +{ + return init_constructor(constr, &HTMLXDomainRequestFactory_dispex, &HTMLXDomainRequestFactoryVtbl); +} + +dispex_static_data_t XDomainRequest_dispex = { + .id = OBJID_XDomainRequest, + .init_constructor = &HTMLXDomainRequestFactory_init, + .vtbl = &HTMLXDomainRequest_event_target_vtbl.dispex_vtbl, + .disp_tid = DispXDomainRequest_tid, + .init_info = HTMLXDomainRequest_init_dispex_info, + .max_compat_mode = COMPAT_MODE_IE10 +};
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/tests/xhr.js | 22 +++++ dlls/mshtml/tests/xmlhttprequest.c | 137 +++++++++++++++++++++++++++++ dlls/mshtml/xmlhttprequest.c | 41 ++++++++- 3 files changed, 198 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/tests/xhr.js b/dlls/mshtml/tests/xhr.js index 7685a5a8486..8de2b01545d 100644 --- a/dlls/mshtml/tests/xhr.js +++ b/dlls/mshtml/tests/xhr.js @@ -238,6 +238,28 @@ async_test("sync_xhr", function() { }, 0); });
+sync_test("xdr", function() { + if(!window.XDomainRequest) return; + + var xdr = new XDomainRequest(); + xdr.open("POST", "echo.php"); + // send() on native aborts with custom pluggable protocol handler even with the right + // response headers (`XDomainRequestAllowed: 1` and `Access-Control-Allow-Origin: *`). + + // Only http/https schemes are allowed, and it must match with the origin's scheme + xdr = new XDomainRequest(); + xdr.open("GET", "http://www.winehq.org/"); + + xdr = new XDomainRequest(); + try { + xdr.open("GET", "https://www.winehq.org/"); + ok(false, "xdr scheme mismatch did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === 0x80070005, "xdr scheme mismatch threw " + n); + } +}); + async_test("content_types", function() { var xhr = new XMLHttpRequest(), types, i = 0, override = false; var v = document.documentMode; diff --git a/dlls/mshtml/tests/xmlhttprequest.c b/dlls/mshtml/tests/xmlhttprequest.c index 44132160520..903b2218380 100644 --- a/dlls/mshtml/tests/xmlhttprequest.c +++ b/dlls/mshtml/tests/xmlhttprequest.c @@ -63,6 +63,7 @@ DEFINE_EXPECT(xmlhttprequest_onreadystatechange_opened); DEFINE_EXPECT(xmlhttprequest_onreadystatechange_headers_received); DEFINE_EXPECT(xmlhttprequest_onreadystatechange_loading); DEFINE_EXPECT(xmlhttprequest_onreadystatechange_done); +DEFINE_EXPECT(xdomainrequest_onload);
#define test_disp(u,id) _test_disp(__LINE__,u,id) static void _test_disp(unsigned line, IUnknown *unk, const IID *diid, const IID *broken_diid) @@ -266,6 +267,58 @@ static IDispatchExVtbl xmlhttprequest_onreadystatechangeFuncVtbl = { }; static IDispatchEx xmlhttprequest_onreadystatechange_obj = { &xmlhttprequest_onreadystatechangeFuncVtbl };
+static HRESULT WINAPI xdomainrequest_onload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + test_event_args(&DIID_DispXDomainRequest, &IID_IHTMLXDomainRequest, id, wFlags, pdp, pvarRes, pei, pspCaller); + CHECK_EXPECT(xdomainrequest_onload); + return S_OK; +} + +static IDispatchExVtbl xdomainrequest_onloadFuncVtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + xdomainrequest_onload, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; +static IDispatchEx xdomainrequest_onload_obj = { &xdomainrequest_onloadFuncVtbl }; + +static HRESULT WINAPI xdomainrequest_ignore(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + return S_OK; +} + +static IDispatchExVtbl xdomainrequest_ignoreFuncVtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + xdomainrequest_ignore, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; +static IDispatchEx xdomainrequest_ignore_obj = { &xdomainrequest_ignoreFuncVtbl }; + static BOOL doc_complete; static IHTMLDocument2 *notif_doc;
@@ -1081,6 +1134,89 @@ static void test_timeout(IHTMLDocument2 *doc) IHTMLXMLHttpRequest2_Release(xhr2); }
+static void test_xdr(IHTMLDocument2 *doc) +{ + IHTMLXDomainRequestFactory *factory; + IHTMLXDomainRequest *xdr; + IHTMLWindow6 *window6; + IHTMLWindow2 *window; + BSTR bstr, url; + HRESULT hres; + VARIANT v; + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + ok(window != NULL, "window == NULL\n"); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow6, (void**)&window6); + IHTMLWindow2_Release(window); + if(FAILED(hres)) { + win_skip("IHTMLWindow6 not supported\n"); + return; + } + + VariantInit(&v); + hres = IHTMLWindow6_get_XDomainRequest(window6, &v); + IHTMLWindow6_Release(window6); + ok(hres == S_OK, "get_XDomainRequest failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(&v) is %08x, expected VT_DISPATCH\n", V_VT(&v)); + + hres = IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IHTMLXDomainRequestFactory, (void**)&factory); + VariantClear(&v); + ok(hres == S_OK, "QueryInterface(IID_IXDomainRequestFactory) failed: %08lx\n", hres); + ok(factory != NULL, "factory == NULL\n"); + + hres = IHTMLXDomainRequestFactory_create(factory, &xdr); + IHTMLXDomainRequestFactory_Release(factory); + ok(hres == S_OK, "create failed: %08lx\n", hres); + ok(xdr != NULL, "xdr == NULL\n"); + + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)&xdomainrequest_onload_obj; + hres = IHTMLXDomainRequest_put_onload(xdr, v); + ok(hres == S_OK, "put_onload failed: %08lx\n", hres); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLXDomainRequest_get_onload(xdr, &v); + ok(hres == S_OK, "get_onload failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(onload) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) == (IDispatch*)&xdomainrequest_onload_obj, "unexpected onload value\n"); + VariantClear(&v); + + /* Native IE9 sometimes (rarely) aborts if the other handlers are not set */ + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)&xdomainrequest_ignore_obj; + hres = IHTMLXDomainRequest_put_onerror(xdr, v); + ok(hres == S_OK, "put_onerror failed: %08lx\n", hres); + hres = IHTMLXDomainRequest_put_onprogress(xdr, v); + ok(hres == S_OK, "put_onprogress failed: %08lx\n", hres); + hres = IHTMLXDomainRequest_put_ontimeout(xdr, v); + ok(hres == S_OK, "put_ontimeout failed: %08lx\n", hres); + + bstr = SysAllocString(L"GET"); + url = SysAllocString(L"http://test.winehq.org/tests/cors.html"); + hres = IHTMLXDomainRequest_open(xdr, bstr, url); + ok(hres == S_OK, "open failed: %08lx\n", hres); + SysFreeString(bstr); + SysFreeString(url); + + V_VT(&v) = VT_BSTR; + V_BSTR(&v) = SysAllocString(L"test"); + SET_EXPECT(xdomainrequest_onload); + hres = IHTMLXDomainRequest_send(xdr, v); + ok(hres == S_OK, "send failed: %08lx\n", hres); + if(SUCCEEDED(hres)) + pump_msgs(&called_xdomainrequest_onload); + CHECK_CALLED(xdomainrequest_onload); + + hres = IHTMLXDomainRequest_get_responseText(xdr, &bstr); + ok(hres == S_OK, "get_responseText returned %08lx\n", hres); + ok(!lstrcmpW(bstr, L"<html><body>test</body></html>\n"), "responseText = %s\n", debugstr_w(bstr)); + SysFreeString(bstr); + + IHTMLXDomainRequest_Release(xdr); +} + static IHTMLDocument2 *create_doc_from_url(const WCHAR *start_url) { BSTR url; @@ -1147,6 +1283,7 @@ START_TEST(xmlhttprequest) test_async_xhr_abort(doc, large_page_url); test_xhr_post(doc); test_timeout(doc); + test_xdr(doc); IHTMLDocument2_Release(doc); } SysFreeString(content_type); diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 5f042dc708b..fe91e738de7 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1823,10 +1823,47 @@ static HRESULT WINAPI HTMLXDomainRequest_abort(IHTMLXDomainRequest *iface) static HRESULT WINAPI HTMLXDomainRequest_open(IHTMLXDomainRequest *iface, BSTR bstrMethod, BSTR bstrUrl) { HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + VARIANT vtrue, vempty; + nsAString nsstr; + HRESULT hres; + DWORD magic; + WCHAR *p;
- FIXME("(%p)->(%s %s)\n", This, debugstr_w(bstrMethod), debugstr_w(bstrUrl)); + TRACE("(%p)->(%s %s)\n", This, debugstr_w(bstrMethod), debugstr_w(bstrUrl));
- return E_NOTIMPL; + if((p = wcschr(bstrUrl, ':')) && p[1] == '/' && p[2] == '/') { + size_t len = p - bstrUrl; + BSTR bstr; + + /* Native only allows http and https, and the scheme must match */ + if(len < 4 || len > 5 || wcsnicmp(bstrUrl, L"https", len) || !This->window->base.outer_window || !This->window->base.outer_window->uri) + return E_ACCESSDENIED; + + hres = IUri_GetSchemeName(This->window->base.outer_window->uri, &bstr); + if(FAILED(hres)) + return hres; + if(SysStringLen(bstr) != len || wcsnicmp(bstr, bstrUrl, len)) + hres = E_ACCESSDENIED; + SysFreeString(bstr); + if(FAILED(hres)) + return hres; + } + + V_VT(&vtrue) = VT_BOOL; + V_BOOL(&vtrue) = VARIANT_TRUE; + V_VT(&vempty) = VT_EMPTY; + magic = This->magic; + hres = HTMLXMLHttpRequest_open(&This->IHTMLXMLHttpRequest_iface, bstrMethod, bstrUrl, vtrue, vempty, vempty); + if(FAILED(hres) || magic + 1 != This->magic) + return hres; + + /* Prevent Gecko from parsing responseXML for no reason */ + nsAString_InitDepend(&nsstr, L"text"); + nsIXMLHttpRequest_SetResponseType(This->nsxhr, &nsstr); + nsAString_Finish(&nsstr); + + /* IE always adds Origin header, even from same origin, but Gecko doesn't allow us to alter it. */ + return S_OK; }
static HRESULT WINAPI HTMLXDomainRequest_send(IHTMLXDomainRequest *iface, VARIANT varBody)
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/tests/xmlhttprequest.c | 15 +++++++++++++++ dlls/mshtml/xmlhttprequest.c | 17 +++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/dlls/mshtml/tests/xmlhttprequest.c b/dlls/mshtml/tests/xmlhttprequest.c index 903b2218380..23a871f2991 100644 --- a/dlls/mshtml/tests/xmlhttprequest.c +++ b/dlls/mshtml/tests/xmlhttprequest.c @@ -1142,6 +1142,7 @@ static void test_xdr(IHTMLDocument2 *doc) IHTMLWindow2 *window; BSTR bstr, url; HRESULT hres; + LONG timeout; VARIANT v;
hres = IHTMLDocument2_get_parentWindow(doc, &window); @@ -1200,6 +1201,20 @@ static void test_xdr(IHTMLDocument2 *doc) SysFreeString(bstr); SysFreeString(url);
+ hres = IHTMLXDomainRequest_get_timeout(xdr, NULL); + ok(hres == E_INVALIDARG, "get_timeout returned %08lx\n", hres); + hres = IHTMLXDomainRequest_get_timeout(xdr, &timeout); + ok(hres == S_OK, "get_timeout returned %08lx\n", hres); + ok(timeout == -1, "timeout = %ld\n", timeout); + + hres = IHTMLXDomainRequest_put_timeout(xdr, -1); + ok(hres == E_INVALIDARG || broken(hres == E_FAIL), "put_timeout returned %08lx\n", hres); + hres = IHTMLXDomainRequest_put_timeout(xdr, 1337); + ok(hres == S_OK, "put_timeout returned %08lx\n", hres); + hres = IHTMLXDomainRequest_get_timeout(xdr, &timeout); + ok(hres == S_OK, "get_timeout returned %08lx\n", hres); + ok(timeout == 1337, "timeout = %ld\n", timeout); + V_VT(&v) = VT_BSTR; V_BSTR(&v) = SysAllocString(L"test"); SET_EXPECT(xdomainrequest_onload); diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index fe91e738de7..7d3056d0121 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1719,18 +1719,27 @@ static HRESULT WINAPI HTMLXDomainRequest_put_timeout(IHTMLXDomainRequest *iface, { HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface);
- FIXME("(%p)->(%ld)\n", This, v); + TRACE("(%p)->(%ld)\n", This, v);
- return E_NOTIMPL; + if(v < 0) + return E_INVALIDARG; + return map_nsresult(nsIXMLHttpRequest_SetTimeout(This->nsxhr, v)); }
static HRESULT WINAPI HTMLXDomainRequest_get_timeout(IHTMLXDomainRequest *iface, LONG *p) { HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + nsresult nsres; + UINT32 timeout;
- FIXME("(%p)->(%p)\n", This, p); + TRACE("(%p)->(%p)\n", This, p);
- return E_NOTIMPL; + if(!p) + return E_INVALIDARG; + + nsres = nsIXMLHttpRequest_GetTimeout(This->nsxhr, &timeout); + *p = timeout ? timeout : -1; + return map_nsresult(nsres); }
static HRESULT WINAPI HTMLXDomainRequest_get_contentType(IHTMLXDomainRequest *iface, BSTR *p)
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/tests/dom.c | 5 +++++ dlls/mshtml/tests/xmlhttprequest.c | 13 ++++++++++++ dlls/mshtml/xmlhttprequest.c | 34 ++++++++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index f3aec7d9046..3235cbbaca5 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -8050,6 +8050,7 @@ static void test_xdomainrequest(IHTMLWindow6 *window) IHTMLXDomainRequest *xdr; HRESULT hres; VARIANT var; + BSTR bstr;
hres = IHTMLWindow6_get_XDomainRequest(window, &var); ok(hres == S_OK, "get_XDomainRequest failed: %08lx\n", hres); @@ -8074,6 +8075,10 @@ static void test_xdomainrequest(IHTMLWindow6 *window) if(is_ie9plus) test_disp((IUnknown*)xdr, &DIID_DispXDomainRequest, NULL, L"[object]");
+ hres = IHTMLXDomainRequest_get_contentType(xdr, &bstr); + ok(hres == S_OK, "get_contentType returned %08lx\n", hres); + ok(bstr == NULL, "contentType = %s\n", debugstr_w(bstr)); + IHTMLXDomainRequest_Release(xdr); IHTMLXDomainRequestFactory_Release(factory); VariantClear(&var); diff --git a/dlls/mshtml/tests/xmlhttprequest.c b/dlls/mshtml/tests/xmlhttprequest.c index 23a871f2991..5a2afd4e1cc 100644 --- a/dlls/mshtml/tests/xmlhttprequest.c +++ b/dlls/mshtml/tests/xmlhttprequest.c @@ -1194,6 +1194,10 @@ static void test_xdr(IHTMLDocument2 *doc) hres = IHTMLXDomainRequest_put_ontimeout(xdr, v); ok(hres == S_OK, "put_ontimeout failed: %08lx\n", hres);
+ hres = IHTMLXDomainRequest_get_contentType(xdr, &bstr); + ok(hres == S_OK, "get_contentType returned %08lx\n", hres); + ok(bstr == NULL, "contentType = %s\n", debugstr_w(bstr)); + bstr = SysAllocString(L"GET"); url = SysAllocString(L"http://test.winehq.org/tests/cors.html"); hres = IHTMLXDomainRequest_open(xdr, bstr, url); @@ -1201,6 +1205,10 @@ static void test_xdr(IHTMLDocument2 *doc) SysFreeString(bstr); SysFreeString(url);
+ hres = IHTMLXDomainRequest_get_contentType(xdr, &bstr); + ok(hres == S_OK, "get_contentType returned %08lx\n", hres); + ok(bstr == NULL, "contentType = %s\n", debugstr_w(bstr)); + hres = IHTMLXDomainRequest_get_timeout(xdr, NULL); ok(hres == E_INVALIDARG, "get_timeout returned %08lx\n", hres); hres = IHTMLXDomainRequest_get_timeout(xdr, &timeout); @@ -1229,6 +1237,11 @@ static void test_xdr(IHTMLDocument2 *doc) ok(!lstrcmpW(bstr, L"<html><body>test</body></html>\n"), "responseText = %s\n", debugstr_w(bstr)); SysFreeString(bstr);
+ hres = IHTMLXDomainRequest_get_contentType(xdr, &bstr); + ok(hres == S_OK, "get_contentType returned %08lx\n", hres); + ok(!lstrcmpW(bstr, L"text/html"), "contentType = %s\n", debugstr_w(bstr)); + SysFreeString(bstr); + IHTMLXDomainRequest_Release(xdr); }
diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 7d3056d0121..50b86540278 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1745,10 +1745,40 @@ static HRESULT WINAPI HTMLXDomainRequest_get_timeout(IHTMLXDomainRequest *iface, static HRESULT WINAPI HTMLXDomainRequest_get_contentType(IHTMLXDomainRequest *iface, BSTR *p) { HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + const char *content_type = "text/plain"; + nsIChannel *nschannel; + HRESULT hres = S_OK; + nsACString nsstr; + nsresult nsres; + int len;
- FIXME("(%p)->(%p)\n", This, p); + TRACE("(%p)->(%p)\n", This, p);
- return E_NOTIMPL; + if(!p) + return E_POINTER; + + if(This->ready_state < READYSTATE_LOADED) { + *p = NULL; + return S_OK; + } + + nsACString_Init(&nsstr, NULL); + + nsres = nsIXMLHttpRequest_GetChannel(This->nsxhr, &nschannel); + if(NS_SUCCEEDED(nsres)) { + nsres = nsIChannel_GetContentType(nschannel, &nsstr); + if(NS_SUCCEEDED(nsres)) + nsACString_GetData(&nsstr, &content_type); + } + + len = MultiByteToWideChar(CP_UTF8, 0, content_type, -1, NULL, 0); + if(!(*p = SysAllocStringLen(NULL, len - 1))) + hres = E_OUTOFMEMORY; + else + MultiByteToWideChar(CP_UTF8, 0, content_type, -1, *p, len); + + nsACString_Finish(&nsstr); + return hres; }
static HRESULT WINAPI HTMLXDomainRequest_put_onprogress(IHTMLXDomainRequest *iface, VARIANT v)
On Tue Sep 16 17:12:10 2025 +0000, Gabriel Ivăncescu wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/8960/diffs?diff_id=209396&start_sha=98fd518da2b914bb923ff3cddc5ff1f016a63c2d#b34fd968e4fd704a4d4b8286906590926b3f2a1d_1775_1767)
I meant it fails the test added in the patch. But yeah, oops, it's actually my blunder. Gecko was overriding it because of my OverrideMimeType call. Switching to setting the response type to `text` fixes it since Gecko won't override channel's content type now (this happened in `nsXMLHttpRequest::OnStartRequest`).
I sent new version using GetChannel since urlmon's sniffing is enough, I hope this one is fine now.
Jacek Caban (@jacek) commented about dlls/mshtml/xmlhttprequest.c:
IHTMLXMLHttpRequest2 IHTMLXMLHttpRequest2_iface; IWineXMLHttpRequestPrivate IWineXMLHttpRequestPrivate_iface; IProvideClassInfo2 IProvideClassInfo2_iface;
- IHTMLXDomainRequest IHTMLXDomainRequest_iface; /* only for XDomainRequests */
I think repurposing the object like that is confusing, while saving very little code compared to properly splitting the data types. We could move all fields except the *_iface ones into a common base struct. XDR could then simply be: `struct { struct xhr xhr; IHTMLXDomainRequest IHTMLXDomainRequest_iface; }`.
Jacek Caban (@jacek) commented about dlls/mshtml/xmlhttprequest.c:
hres = IUri_GetSchemeName(This->window->base.outer_window->uri, &bstr);
if(FAILED(hres))
return hres;
if(SysStringLen(bstr) != len || wcsnicmp(bstr, bstrUrl, len))
hres = E_ACCESSDENIED;
SysFreeString(bstr);
if(FAILED(hres))
return hres;
- }
- V_VT(&vtrue) = VT_BOOL;
- V_BOOL(&vtrue) = VARIANT_TRUE;
- V_VT(&vempty) = VT_EMPTY;
- magic = This->magic;
- hres = HTMLXMLHttpRequest_open(&This->IHTMLXMLHttpRequest_iface, bstrMethod, bstrUrl, vtrue, vempty, vempty);
- if(FAILED(hres) || magic + 1 != This->magic)
Why do we need to worry about magic here? Shouldn't we set response time anyway?