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 | 54 +++++++++++- 3 files changed, 211 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..565d82101af 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_contentType 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..1379307ffc5 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1823,10 +1823,60 @@ 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; + nsACString str1, str2; + nsAString nsstr; + nsresult nsres; + 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 != This->magic) + return hres; + + /* Prevent Gecko from parsing responseXML for no reason */ + nsAString_InitDepend(&nsstr, L"text/plain"); + nsIXMLHttpRequest_SlowOverrideMimeType(This->nsxhr, &nsstr); + nsAString_Finish(&nsstr); + + /* XDomainRequest only accepts text/plain */ + nsACString_InitDepend(&str1, "Accept"); + nsACString_InitDepend(&str2, "text/plain"); + nsres = nsIXMLHttpRequest_SetRequestHeader(This->nsxhr, &str1, &str2); + nsACString_Finish(&str1); + nsACString_Finish(&str2); + if(NS_FAILED(nsres)) { + ERR("nsIXMLHttpRequest_SetRequestHeader failed: %08lx\n", nsres); + return map_nsresult(nsres); + } + + /* 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 565d82101af..846cdc0aec8 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 1379307ffc5..918e82f7266 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 | 38 ++++++++++++++++++++++++++++-- 3 files changed, 54 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 846cdc0aec8..c9e76ae7eb7 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 918e82f7266..9513ea34060 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1745,10 +1745,44 @@ static HRESULT WINAPI HTMLXDomainRequest_get_timeout(IHTMLXDomainRequest *iface, static HRESULT WINAPI HTMLXDomainRequest_get_contentType(IHTMLXDomainRequest *iface, BSTR *p) { HTMLXMLHttpRequest *This = impl_from_IHTMLXDomainRequest(iface); + nsAString nsstr; + nsresult nsres; + HRESULT hres;
- 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; + } + + nsAString_InitDepend(&nsstr, NULL); + nsres = nsIXMLHttpRequest_GetResponseText(This->nsxhr, &nsstr); + if(NS_SUCCEEDED(nsres)) { + const PRUnichar *data; + char text[256 * 3]; + unsigned len; + WCHAR *mime; + + nsAString_GetData(&nsstr, &data); + len = WideCharToMultiByte(CP_ACP, 0, data, wcsnlen(data, 256), text, ARRAY_SIZE(text), NULL, NULL); + nsAString_Finish(&nsstr); + + if(len) { + hres = FindMimeFromData(NULL, NULL, text, len, NULL, 0, &mime, 0); + if(SUCCEEDED(hres)) { + *p = SysAllocString(mime); + CoTaskMemFree(mime); + return *p ? S_OK : E_OUTOFMEMORY; + } + } + } + + *p = SysAllocString(L"text/plain"); + return *p ? S_OK : E_OUTOFMEMORY; }
static HRESULT WINAPI HTMLXDomainRequest_put_onprogress(IHTMLXDomainRequest *iface, VARIANT v)
Jacek Caban (@jacek) commented about dlls/mshtml/xmlhttprequest.c:
- }
- nsAString_InitDepend(&nsstr, NULL);
- nsres = nsIXMLHttpRequest_GetResponseText(This->nsxhr, &nsstr);
- if(NS_SUCCEEDED(nsres)) {
const PRUnichar *data;
char text[256 * 3];
unsigned len;
WCHAR *mime;
nsAString_GetData(&nsstr, &data);
len = WideCharToMultiByte(CP_ACP, 0, data, wcsnlen(data, 256), text, ARRAY_SIZE(text), NULL, NULL);
nsAString_Finish(&nsstr);
if(len) {
hres = FindMimeFromData(NULL, NULL, text, len, NULL, 0, &mime, 0);
This looks like a hack. urlmon already does that earlier, using the right encoding and response headers as a hint and that's what's propagated to Gecko. Can we use that here somehow?
On Fri Sep 12 09:24:44 2025 +0000, Jacek Caban wrote:
This looks like a hack. urlmon already does that earlier, using the right encoding and response headers as a hint and that's what's propagated to Gecko. Can we use that here somehow?
I'm not sure. XDR only accepts text/plain responses, but this method seems to detect it from the content (not from headers, else it would be pointless).
urlmon reports its sniffing via `BINDSTATUS_MIMETYPEAVAILABLE`, but that's on the channel, how do I obtain the channel from the XHR or associate it with it? (so I can access its `content_type` field)
From what I see, Gecko creates the channel internally during open() and there's no way to directly obtain it from the XHR.
An ugly solution would be some sort of thread-local hack wrapping open() (and read it in `nsIOServiceHook_NewChannel` to give it a pointer to it), but that's not very pretty either. Any better ideas?
On Fri Sep 12 17:23:12 2025 +0000, Gabriel Ivăncescu wrote:
I'm not sure. XDR only accepts text/plain responses, but this method seems to detect it from the content (not from headers, else it would be pointless). urlmon reports its sniffing via `BINDSTATUS_MIMETYPEAVAILABLE`, but that's on the channel, how do I obtain the channel from the XHR or associate it with it? (so I can access its `content_type` field) From what I see, Gecko creates the channel internally during open() and there's no way to directly obtain it from the XHR. An ugly solution would be some sort of thread-local hack wrapping open() (and read it in `nsIOServiceHook_NewChannel` to give it a pointer to it), but that's not very pretty either. Any better ideas?
There is `nsIXMLHttpRequest::GetChannel` and `nsIChannel::GetContentType` that could potentially be useful. And if we really need to do parsing here, there is `nsIXMLHttpRequest::GetResponseBuffer` that would give us raw data instead of converting it back and forth with potentially different code pages.
What's the exact Windows behavior? For example "Accept" header from the other patch could probably be tested with our emulated http protocol handler, I'm not sure how practical that is. It should be easy to capture http traffic on Windows to see, does it behave the same?
On Sun Sep 14 14:40:22 2025 +0000, Jacek Caban wrote:
There is `nsIXMLHttpRequest::GetChannel` and `nsIChannel::GetContentType` that could potentially be useful. And if we really need to do parsing here, there is `nsIXMLHttpRequest::GetResponseBuffer` that would give us raw data instead of converting it back and forth with potentially different code pages. What's the exact Windows behavior? For example "Accept" header from the other patch could probably be tested with our emulated http protocol handler, I'm not sure how practical that is. It should be easy to capture http traffic on Windows to see, does it behave the same?
I can't get the custom pluggable http protocol to work on native, it keeps aborting on send(). To be specific, it's the `IHttpNegotiate_OnResponse` on the sink that aborts. I tried to find out why, even copy pasted the response headers from the test URL that works (http://test.winehq.org/tests/cors.html) and nothing worked.
nsChannel's GetContentType doesn't seem to help, unfortunately. Because it's going to use the content type specified in the response header instead by that time (Gecko will issue SetContentType on it), so the test will fail.
If you want here's the snippet you can test the nsChannel way with: ```diff diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 52608f7..2f1db09 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 = "wine/test"; + 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) ```
The last problem is with `GetResponseBuffer`. I'm not sure what's ideal to do here. GetResponseBuffer works with ArrayBuffer response only (it uses gecko's ArrayBuffer methods for it). Sure, I can use `nsIXMLHttpRequest_SetResponseType` after open() to set it to ArrayBuffer, but then GetResponseText isn't gonna work. Should I manually allocate and convert in GetResponseText or is that too ugly?
On Mon Sep 15 19:14:42 2025 +0000, Gabriel Ivăncescu wrote:
I can't get the custom pluggable http protocol to work on native, it keeps aborting on send(). To be specific, it's the `IHttpNegotiate_OnResponse` on the sink that aborts. I tried to find out why, even copy pasted the response headers from the test URL that works (http://test.winehq.org/tests/cors.html) and nothing worked. nsChannel's GetContentType doesn't seem to help, unfortunately. Because it's going to use the content type specified in the response header instead by that time (Gecko will issue SetContentType on it), so the test will fail. If you want here's the snippet you can test the nsChannel way with:
diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 52608f7..2f1db09 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 = "wine/test"; + 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)
The last problem is with `GetResponseBuffer`. I'm not sure what's ideal to do here. GetResponseBuffer works with ArrayBuffer response only (it uses gecko's ArrayBuffer methods for it). Sure, I can use `nsIXMLHttpRequest_SetResponseType` after open() to set it to ArrayBuffer, but then GetResponseText isn't gonna work. Should I manually allocate and convert in GetResponseText or is that too ugly?
BTW sorry forgot to mention, it seems native may not send the `Accept: text/plain` header (even if it somehow rejects), so I will get rid of that part. I also had a bug and that code path wasn't even executed (`magic` needs to be tested with +1 value after open), which I fixed now. But I'm unsure what to do with GetResponseBuffer or if there's a better way.
nsChannel's GetContentType doesn't seem to help, unfortunately. Because it's going to use the content type specified in the response header instead by that time (Gecko will issue SetContentType on it), so the test will fail.
Isn't using the response content type the point? If it should be ignored, could you explain why? It should be easy to send text with an XML content type, and the other way around, using a local HTTP server and then check what IE reports. Did you try something like that?
Also, what do you mean by “issued by Gecko”? Normally this is called by bsc based on the MIME type from urlmon. Does Gecko override that somehow? If so, how? If we really need to, we can fetch bsc from the channel or store the original MIME in it, but I think we need a better understanding of the problem first.