| /* | |
| * Copyright 2015 Zhenbo Li | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| */ | |
| #include <stdarg.h> | |
| #include <assert.h> | |
| #define COBJMACROS | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winuser.h" | |
| #include "ole2.h" | |
| #include "wine/debug.h" | |
| #include "mshtml_private.h" | |
| #include "htmlevent.h" | |
| #include "initguid.h" | |
| #include "msxml6.h" | |
| #include "objsafe.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(mshtml); | |
| static HRESULT bstr_to_nsacstr(BSTR bstr, nsACString *str) | |
| { | |
| char *cstr = heap_strdupWtoU(bstr); | |
| if(!cstr) | |
| return E_OUTOFMEMORY; | |
| nsACString_Init(str, cstr); | |
| heap_free(cstr); | |
| return S_OK; | |
| } | |
| static HRESULT variant_to_nsastr(VARIANT var, nsAString *ret) | |
| { | |
| switch(V_VT(&var)) { | |
| case VT_NULL: | |
| case VT_ERROR: | |
| case VT_EMPTY: | |
| nsAString_Init(ret, NULL); | |
| return S_OK; | |
| case VT_BSTR: | |
| nsAString_InitDepend(ret, V_BSTR(&var)); | |
| return S_OK; | |
| default: | |
| FIXME("Unsupported VARIANT: %s\n", debugstr_variant(&var)); | |
| return E_INVALIDARG; | |
| } | |
| } | |
| static HRESULT return_nscstr(nsresult nsres, nsACString *nscstr, BSTR *p) | |
| { | |
| const char *str; | |
| int len; | |
| if(NS_FAILED(nsres)) { | |
| ERR("failed: %08x\n", nsres); | |
| nsACString_Finish(nscstr); | |
| return E_FAIL; | |
| } | |
| nsACString_GetData(nscstr, &str); | |
| if(*str) { | |
| len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); | |
| *p = SysAllocStringLen(NULL, len); | |
| if(!*p) { | |
| nsACString_Finish(nscstr); | |
| return E_OUTOFMEMORY; | |
| } | |
| MultiByteToWideChar(CP_UTF8, 0, str, -1, *p, len); | |
| }else { | |
| *p = NULL; | |
| } | |
| nsACString_Finish(nscstr); | |
| return S_OK; | |
| } | |
| typedef struct { | |
| nsIDOMEventListener nsIDOMEventListener_iface; | |
| LONG ref; | |
| HTMLXMLHttpRequest *xhr; | |
| } XMLHttpReqEventListener; | |
| struct HTMLXMLHttpRequest { | |
| EventTarget event_target; | |
| IHTMLXMLHttpRequest IHTMLXMLHttpRequest_iface; | |
| IProvideClassInfo2 IProvideClassInfo2_iface; | |
| LONG ref; | |
| nsIXMLHttpRequest *nsxhr; | |
| XMLHttpReqEventListener *event_listener; | |
| }; | |
| static void detach_xhr_event_listener(XMLHttpReqEventListener *event_listener) | |
| { | |
| nsIDOMEventTarget *event_target; | |
| nsAString str; | |
| nsresult nsres; | |
| static const WCHAR readystatechangeW[] = | |
| {'o','n','r','e','a','d','y','s','t','a','t','e','c','h','a','n','g','e',0}; | |
| nsres = nsIXMLHttpRequest_QueryInterface(event_listener->xhr->nsxhr, &IID_nsIDOMEventTarget, (void**)&event_target); | |
| assert(nsres == NS_OK); | |
| nsAString_InitDepend(&str, readystatechangeW); | |
| nsres = nsIDOMEventTarget_RemoveEventListener(event_target, &str, &event_listener->nsIDOMEventListener_iface, FALSE); | |
| nsAString_Finish(&str); | |
| nsIDOMEventTarget_Release(event_target); | |
| event_listener->xhr->event_listener = NULL; | |
| event_listener->xhr = NULL; | |
| nsIDOMEventListener_Release(&event_listener->nsIDOMEventListener_iface); | |
| } | |
| static inline XMLHttpReqEventListener *impl_from_nsIDOMEventListener(nsIDOMEventListener *iface) | |
| { | |
| return CONTAINING_RECORD(iface, XMLHttpReqEventListener, nsIDOMEventListener_iface); | |
| } | |
| static nsresult NSAPI XMLHttpReqEventListener_QueryInterface(nsIDOMEventListener *iface, | |
| nsIIDRef riid, void **result) | |
| { | |
| XMLHttpReqEventListener *This = impl_from_nsIDOMEventListener(iface); | |
| if(IsEqualGUID(&IID_nsISupports, riid)) { | |
| TRACE("(%p)->(IID_nsISupports, %p)\n", This, result); | |
| *result = &This->nsIDOMEventListener_iface; | |
| }else if(IsEqualGUID(&IID_nsIDOMEventListener, riid)) { | |
| TRACE("(%p)->(IID_nsIDOMEventListener %p)\n", This, result); | |
| *result = &This->nsIDOMEventListener_iface; | |
| }else { | |
| *result = NULL; | |
| TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result); | |
| return NS_NOINTERFACE; | |
| } | |
| nsIDOMEventListener_AddRef(&This->nsIDOMEventListener_iface); | |
| return NS_OK; | |
| } | |
| static nsrefcnt NSAPI XMLHttpReqEventListener_AddRef(nsIDOMEventListener *iface) | |
| { | |
| XMLHttpReqEventListener *This = impl_from_nsIDOMEventListener(iface); | |
| LONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p) ref=%d\n", This, ref); | |
| return ref; | |
| } | |
| static nsrefcnt NSAPI XMLHttpReqEventListener_Release(nsIDOMEventListener *iface) | |
| { | |
| XMLHttpReqEventListener *This = impl_from_nsIDOMEventListener(iface); | |
| LONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p) ref=%d\n", This, ref); | |
| if(!ref) { | |
| assert(!This->xhr); | |
| heap_free(This); | |
| } | |
| return ref; | |
| } | |
| static nsresult NSAPI XMLHttpReqEventListener_HandleEvent(nsIDOMEventListener *iface, nsIDOMEvent *event) | |
| { | |
| XMLHttpReqEventListener *This = impl_from_nsIDOMEventListener(iface); | |
| TRACE("(%p)\n", This); | |
| if(!This->xhr) | |
| return NS_OK; | |
| call_event_handlers(NULL, NULL, &This->xhr->event_target, NULL, EVENTID_READYSTATECHANGE, | |
| (IDispatch*)&This->xhr->IHTMLXMLHttpRequest_iface); | |
| return NS_OK; | |
| } | |
| static const nsIDOMEventListenerVtbl XMLHttpReqEventListenerVtbl = { | |
| XMLHttpReqEventListener_QueryInterface, | |
| XMLHttpReqEventListener_AddRef, | |
| XMLHttpReqEventListener_Release, | |
| XMLHttpReqEventListener_HandleEvent | |
| }; | |
| static inline HTMLXMLHttpRequest *impl_from_IHTMLXMLHttpRequest(IHTMLXMLHttpRequest *iface) | |
| { | |
| return CONTAINING_RECORD(iface, HTMLXMLHttpRequest, IHTMLXMLHttpRequest_iface); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_QueryInterface(IHTMLXMLHttpRequest *iface, REFIID riid, void **ppv) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); | |
| if(IsEqualGUID(&IID_IUnknown, riid)) { | |
| *ppv = &This->IHTMLXMLHttpRequest_iface; | |
| }else if(IsEqualGUID(&IID_IDispatch, riid)) { | |
| *ppv = &This->IHTMLXMLHttpRequest_iface; | |
| }else if(IsEqualGUID(&IID_IHTMLXMLHttpRequest, riid)) { | |
| *ppv = &This->IHTMLXMLHttpRequest_iface; | |
| }else if(IsEqualGUID(&IID_IProvideClassInfo, riid)) { | |
| *ppv = &This->IProvideClassInfo2_iface; | |
| }else if(IsEqualGUID(&IID_IProvideClassInfo2, riid)) { | |
| *ppv = &This->IProvideClassInfo2_iface; | |
| }else { | |
| return EventTarget_QI(&This->event_target, riid, ppv); | |
| } | |
| IUnknown_AddRef((IUnknown*)*ppv); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI HTMLXMLHttpRequest_AddRef(IHTMLXMLHttpRequest *iface) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| LONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p) ref=%d\n", This, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI HTMLXMLHttpRequest_Release(IHTMLXMLHttpRequest *iface) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| LONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p) ref=%d\n", This, ref); | |
| if(!ref) { | |
| if(This->event_listener) | |
| detach_xhr_event_listener(This->event_listener); | |
| release_event_target(&This->event_target); | |
| release_dispex(&This->event_target.dispex); | |
| nsIXMLHttpRequest_Release(This->nsxhr); | |
| heap_free(This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_GetTypeInfoCount(IHTMLXMLHttpRequest *iface, UINT *pctinfo) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| return IDispatchEx_GetTypeInfoCount(&This->event_target.dispex.IDispatchEx_iface, pctinfo); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_GetTypeInfo(IHTMLXMLHttpRequest *iface, UINT iTInfo, | |
| LCID lcid, ITypeInfo **ppTInfo) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| return IDispatchEx_GetTypeInfo(&This->event_target.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_GetIDsOfNames(IHTMLXMLHttpRequest *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames, | |
| LCID lcid, DISPID *rgDispId) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| return IDispatchEx_GetIDsOfNames(&This->event_target.dispex.IDispatchEx_iface, riid, rgszNames, cNames, | |
| lcid, rgDispId); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_Invoke(IHTMLXMLHttpRequest *iface, DISPID dispIdMember, REFIID riid, LCID lcid, | |
| WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| return IDispatchEx_Invoke(&This->event_target.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, | |
| pDispParams, pVarResult, pExcepInfo, puArgErr); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_get_readyState(IHTMLXMLHttpRequest *iface, LONG *p) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| UINT16 val; | |
| nsresult nsres; | |
| TRACE("(%p)->(%p)\n", This, p); | |
| if(!p) | |
| return E_POINTER; | |
| nsres = nsIXMLHttpRequest_GetReadyState(This->nsxhr, &val); | |
| if(NS_FAILED(nsres)) { | |
| ERR("nsIXMLHttpRequest_GetReadyState failed: %08x\n", nsres); | |
| return E_FAIL; | |
| } | |
| *p = val; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_get_responseBody(IHTMLXMLHttpRequest *iface, VARIANT *p) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| FIXME("(%p)->(%p)\n", This, p); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_get_responseText(IHTMLXMLHttpRequest *iface, BSTR *p) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| nsAString nsstr; | |
| nsresult nsres; | |
| TRACE("(%p)->(%p)\n", This, p); | |
| if(!p) | |
| return E_POINTER; | |
| nsAString_Init(&nsstr, NULL); | |
| nsres = nsIXMLHttpRequest_GetResponseText(This->nsxhr, &nsstr); | |
| return return_nsstr(nsres, &nsstr, p); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_get_responseXML(IHTMLXMLHttpRequest *iface, IDispatch **p) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| IXMLDOMDocument *xmldoc = NULL; | |
| BSTR str; | |
| HRESULT hres; | |
| VARIANT_BOOL vbool; | |
| IObjectSafety *safety; | |
| TRACE("(%p)->(%p)\n", This, p); | |
| hres = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void**)&xmldoc); | |
| if(FAILED(hres)) { | |
| ERR("CoCreateInstance failed: %08x\n", hres); | |
| return hres; | |
| } | |
| hres = IHTMLXMLHttpRequest_get_responseText(iface, &str); | |
| if(FAILED(hres)) { | |
| IXMLDOMDocument_Release(xmldoc); | |
| ERR("get_responseText failed: %08x\n", hres); | |
| return hres; | |
| } | |
| hres = IXMLDOMDocument_loadXML(xmldoc, str, &vbool); | |
| SysFreeString(str); | |
| if(hres != S_OK || vbool != VARIANT_TRUE) | |
| WARN("loadXML failed: %08x, returning an empty xmldoc\n", hres); | |
| hres = IXMLDOMDocument_QueryInterface(xmldoc, &IID_IObjectSafety, (void**)&safety); | |
| assert(SUCCEEDED(hres)); | |
| hres = IObjectSafety_SetInterfaceSafetyOptions(safety, NULL, | |
| INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA | INTERFACE_USES_SECURITY_MANAGER, | |
| INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA | INTERFACE_USES_SECURITY_MANAGER); | |
| assert(SUCCEEDED(hres)); | |
| IObjectSafety_Release(safety); | |
| *p = (IDispatch*)xmldoc; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_get_status(IHTMLXMLHttpRequest *iface, LONG *p) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| DWORD val; | |
| nsresult nsres; | |
| TRACE("(%p)->(%p)\n", This, p); | |
| if(!p) | |
| return E_POINTER; | |
| nsres = nsIXMLHttpRequest_GetStatus(This->nsxhr, &val); | |
| if(NS_FAILED(nsres)) { | |
| ERR("nsIXMLHttpRequest_GetStatus failed: %08x\n", nsres); | |
| return E_FAIL; | |
| } | |
| *p = val; | |
| if(val == 0) | |
| return E_FAIL; /* WinAPI thinks this is an error */ | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_get_statusText(IHTMLXMLHttpRequest *iface, BSTR *p) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| nsACString nscstr; | |
| nsresult nsres; | |
| HRESULT hres; | |
| LONG state; | |
| TRACE("(%p)->(%p)\n", This, p); | |
| if(!p) | |
| return E_POINTER; | |
| hres = IHTMLXMLHttpRequest_get_readyState(iface, &state); | |
| if(FAILED(hres)) | |
| return hres; | |
| if(state < 2) { | |
| *p = NULL; | |
| return E_FAIL; | |
| } | |
| nsACString_Init(&nscstr, NULL); | |
| nsres = nsIXMLHttpRequest_GetStatusText(This->nsxhr, &nscstr); | |
| return return_nscstr(nsres, &nscstr, p); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_put_onreadystatechange(IHTMLXMLHttpRequest *iface, VARIANT v) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); | |
| return set_event_handler(&This->event_target, EVENTID_READYSTATECHANGE, &v); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_get_onreadystatechange(IHTMLXMLHttpRequest *iface, VARIANT *p) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| TRACE("(%p)->(%p)\n", This, p); | |
| return get_event_handler(&This->event_target, EVENTID_READYSTATECHANGE, p); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_abort(IHTMLXMLHttpRequest *iface) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| nsresult nsres; | |
| TRACE("(%p)->()\n", This); | |
| nsres = nsIXMLHttpRequest_SlowAbort(This->nsxhr); | |
| if(NS_FAILED(nsres)) { | |
| ERR("nsIXMLHttpRequest_SlowAbort failed: %08x\n", nsres); | |
| return E_FAIL; | |
| } | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_open(IHTMLXMLHttpRequest *iface, BSTR bstrMethod, BSTR bstrUrl, VARIANT varAsync, VARIANT varUser, VARIANT varPassword) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| nsACString method, url; | |
| nsAString user, password; | |
| nsresult nsres; | |
| HRESULT hres; | |
| TRACE("(%p)->(%s %s %s %s %s)\n", This, debugstr_w(bstrMethod), debugstr_w(bstrUrl), debugstr_variant(&varAsync), debugstr_variant(&varUser), debugstr_variant(&varPassword)); | |
| if(V_VT(&varAsync) != VT_BOOL) { | |
| FIXME("varAsync not supported: %s\n", debugstr_variant(&varAsync)); | |
| return E_FAIL; | |
| } | |
| /* Note: Starting with Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27), | |
| * synchronous requests on the main thread have been deprecated due to the negative | |
| * effects to the user experience. | |
| */ | |
| if(!V_BOOL(&varAsync)) { | |
| FIXME("Synchronous request is not supported yet\n"); | |
| return E_FAIL; | |
| } | |
| hres = variant_to_nsastr(varUser, &user); | |
| if(FAILED(hres)) | |
| return hres; | |
| hres = variant_to_nsastr(varPassword, &password); | |
| if(FAILED(hres)) { | |
| nsAString_Finish(&user); | |
| return hres; | |
| } | |
| hres = bstr_to_nsacstr(bstrMethod, &method); | |
| if(FAILED(hres)) { | |
| nsAString_Finish(&user); | |
| nsAString_Finish(&password); | |
| return hres; | |
| } | |
| hres = bstr_to_nsacstr(bstrUrl, &url); | |
| if(FAILED(hres)) { | |
| nsAString_Finish(&user); | |
| nsAString_Finish(&password); | |
| nsACString_Finish(&method); | |
| return hres; | |
| } | |
| nsres = nsIXMLHttpRequest_Open(This->nsxhr, &method, &url, TRUE, | |
| &user, &password, 0); | |
| nsACString_Finish(&method); | |
| nsACString_Finish(&url); | |
| nsAString_Finish(&user); | |
| nsAString_Finish(&password); | |
| if(NS_FAILED(nsres)) { | |
| ERR("nsIXMLHttpRequest_Open failed: %08x\n", nsres); | |
| return E_FAIL; | |
| } | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_send(IHTMLXMLHttpRequest *iface, VARIANT varBody) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| nsIWritableVariant *nsbody = NULL; | |
| nsresult nsres = NS_OK; | |
| TRACE("(%p)->(%s)\n", This, debugstr_variant(&varBody)); | |
| switch(V_VT(&varBody)) { | |
| case VT_NULL: | |
| case VT_EMPTY: | |
| case VT_ERROR: | |
| break; | |
| case VT_BSTR: { | |
| nsAString nsstr; | |
| nsbody = create_nsvariant(); | |
| if(!nsbody) | |
| return E_OUTOFMEMORY; | |
| nsAString_InitDepend(&nsstr, V_BSTR(&varBody)); | |
| nsres = nsIWritableVariant_SetAsAString(nsbody, &nsstr); | |
| nsAString_Finish(&nsstr); | |
| break; | |
| } | |
| default: | |
| FIXME("unsupported body type %s\n", debugstr_variant(&varBody)); | |
| return E_NOTIMPL; | |
| } | |
| if(NS_SUCCEEDED(nsres)) | |
| nsres = nsIXMLHttpRequest_Send(This->nsxhr, (nsIVariant*)nsbody); | |
| if(nsbody) | |
| nsIWritableVariant_Release(nsbody); | |
| if(NS_FAILED(nsres)) { | |
| ERR("nsIXMLHttpRequest_Send failed: %08x\n", nsres); | |
| return E_FAIL; | |
| } | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_getAllResponseHeaders(IHTMLXMLHttpRequest *iface, BSTR *p) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| nsACString nscstr; | |
| nsresult nsres; | |
| HRESULT hres; | |
| LONG state; | |
| TRACE("(%p)->(%p)\n", This, p); | |
| if(!p) | |
| return E_POINTER; | |
| hres = IHTMLXMLHttpRequest_get_readyState(iface, &state); | |
| if(FAILED(hres)) | |
| return hres; | |
| if(state < 2) { | |
| *p = NULL; | |
| return E_FAIL; | |
| } | |
| nsACString_Init(&nscstr, NULL); | |
| nsres = nsIXMLHttpRequest_GetAllResponseHeaders(This->nsxhr, &nscstr); | |
| return return_nscstr(nsres, &nscstr, p); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_getResponseHeader(IHTMLXMLHttpRequest *iface, BSTR bstrHeader, BSTR *p) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| nsACString header, ret; | |
| char *cstr; | |
| nsresult nsres; | |
| HRESULT hres; | |
| LONG state; | |
| TRACE("(%p)->(%s %p)\n", This, debugstr_w(bstrHeader), p); | |
| if(!p) | |
| return E_POINTER; | |
| if(!bstrHeader) | |
| return E_INVALIDARG; | |
| hres = IHTMLXMLHttpRequest_get_readyState(iface, &state); | |
| if(FAILED(hres)) | |
| return hres; | |
| if(state < 2) { | |
| *p = NULL; | |
| return E_FAIL; | |
| } | |
| cstr = heap_strdupWtoU(bstrHeader); | |
| nsACString_InitDepend(&header, cstr); | |
| nsACString_Init(&ret, NULL); | |
| nsres = nsIXMLHttpRequest_GetResponseHeader(This->nsxhr, &header, &ret); | |
| nsACString_Finish(&header); | |
| heap_free(cstr); | |
| return return_nscstr(nsres, &ret, p); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequest_setRequestHeader(IHTMLXMLHttpRequest *iface, BSTR bstrHeader, BSTR bstrValue) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); | |
| char *header_u, *value_u; | |
| nsACString header, value; | |
| nsresult nsres; | |
| TRACE("(%p)->(%s %s)\n", This, debugstr_w(bstrHeader), debugstr_w(bstrValue)); | |
| header_u = heap_strdupWtoU(bstrHeader); | |
| if(bstrHeader && !header_u) | |
| return E_OUTOFMEMORY; | |
| value_u = heap_strdupWtoU(bstrValue); | |
| if(bstrValue && !value_u) { | |
| heap_free(header_u); | |
| return E_OUTOFMEMORY; | |
| } | |
| nsACString_InitDepend(&header, header_u); | |
| nsACString_InitDepend(&value, value_u); | |
| nsres = nsIXMLHttpRequest_SetRequestHeader(This->nsxhr, &header, &value); | |
| nsACString_Finish(&header); | |
| nsACString_Finish(&value); | |
| heap_free(header_u); | |
| heap_free(value_u); | |
| if(NS_FAILED(nsres)) { | |
| ERR("SetRequestHeader failed: %08x\n", nsres); | |
| return E_FAIL; | |
| } | |
| return S_OK; | |
| } | |
| static const IHTMLXMLHttpRequestVtbl HTMLXMLHttpRequestVtbl = { | |
| HTMLXMLHttpRequest_QueryInterface, | |
| HTMLXMLHttpRequest_AddRef, | |
| HTMLXMLHttpRequest_Release, | |
| HTMLXMLHttpRequest_GetTypeInfoCount, | |
| HTMLXMLHttpRequest_GetTypeInfo, | |
| HTMLXMLHttpRequest_GetIDsOfNames, | |
| HTMLXMLHttpRequest_Invoke, | |
| HTMLXMLHttpRequest_get_readyState, | |
| HTMLXMLHttpRequest_get_responseBody, | |
| HTMLXMLHttpRequest_get_responseText, | |
| HTMLXMLHttpRequest_get_responseXML, | |
| HTMLXMLHttpRequest_get_status, | |
| HTMLXMLHttpRequest_get_statusText, | |
| HTMLXMLHttpRequest_put_onreadystatechange, | |
| HTMLXMLHttpRequest_get_onreadystatechange, | |
| HTMLXMLHttpRequest_abort, | |
| HTMLXMLHttpRequest_open, | |
| HTMLXMLHttpRequest_send, | |
| HTMLXMLHttpRequest_getAllResponseHeaders, | |
| HTMLXMLHttpRequest_getResponseHeader, | |
| HTMLXMLHttpRequest_setRequestHeader | |
| }; | |
| static inline HTMLXMLHttpRequest *impl_from_IProvideClassInfo2(IProvideClassInfo2 *iface) | |
| { | |
| return CONTAINING_RECORD(iface, HTMLXMLHttpRequest, IProvideClassInfo2_iface); | |
| } | |
| static HRESULT WINAPI ProvideClassInfo_QueryInterface(IProvideClassInfo2 *iface, REFIID riid, void **ppv) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IProvideClassInfo2(iface); | |
| return IHTMLXMLHttpRequest_QueryInterface(&This->IHTMLXMLHttpRequest_iface, riid, ppv); | |
| } | |
| static ULONG WINAPI ProvideClassInfo_AddRef(IProvideClassInfo2 *iface) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IProvideClassInfo2(iface); | |
| return IHTMLXMLHttpRequest_AddRef(&This->IHTMLXMLHttpRequest_iface); | |
| } | |
| static ULONG WINAPI ProvideClassInfo_Release(IProvideClassInfo2 *iface) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IProvideClassInfo2(iface); | |
| return IHTMLXMLHttpRequest_Release(&This->IHTMLXMLHttpRequest_iface); | |
| } | |
| static HRESULT WINAPI ProvideClassInfo_GetClassInfo(IProvideClassInfo2 *iface, ITypeInfo **ppTI) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IProvideClassInfo2(iface); | |
| TRACE("(%p)->(%p)\n", This, ppTI); | |
| return get_class_typeinfo(&CLSID_HTMLXMLHttpRequest, ppTI); | |
| } | |
| static HRESULT WINAPI ProvideClassInfo2_GetGUID(IProvideClassInfo2 *iface, DWORD dwGuidKind, GUID *pGUID) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_IProvideClassInfo2(iface); | |
| FIXME("(%p)->(%u %p)\n", This, dwGuidKind, pGUID); | |
| return E_NOTIMPL; | |
| } | |
| static const IProvideClassInfo2Vtbl ProvideClassInfo2Vtbl = { | |
| ProvideClassInfo_QueryInterface, | |
| ProvideClassInfo_AddRef, | |
| ProvideClassInfo_Release, | |
| ProvideClassInfo_GetClassInfo, | |
| ProvideClassInfo2_GetGUID, | |
| }; | |
| static inline HTMLXMLHttpRequest *impl_from_DispatchEx(DispatchEx *iface) | |
| { | |
| return CONTAINING_RECORD(iface, HTMLXMLHttpRequest, event_target.dispex); | |
| } | |
| static void HTMLXMLHttpRequest_bind_event(DispatchEx *dispex, int eid) | |
| { | |
| HTMLXMLHttpRequest *This = impl_from_DispatchEx(dispex); | |
| nsIDOMEventTarget *nstarget; | |
| nsAString type_str; | |
| nsresult nsres; | |
| static const WCHAR readystatechangeW[] = {'r','e','a','d','y','s','t','a','t','e','c','h','a','n','g','e',0}; | |
| TRACE("(%p)\n", This); | |
| assert(eid == EVENTID_READYSTATECHANGE); | |
| if(This->event_listener) | |
| return; | |
| This->event_listener = heap_alloc(sizeof(*This->event_listener)); | |
| if(!This->event_listener) | |
| return; | |
| This->event_listener->nsIDOMEventListener_iface.lpVtbl = &XMLHttpReqEventListenerVtbl; | |
| This->event_listener->ref = 1; | |
| This->event_listener->xhr = This; | |
| nsres = nsIXMLHttpRequest_QueryInterface(This->nsxhr, &IID_nsIDOMEventTarget, (void**)&nstarget); | |
| assert(nsres == NS_OK); | |
| nsAString_InitDepend(&type_str, readystatechangeW); | |
| nsres = nsIDOMEventTarget_AddEventListener(nstarget, &type_str, &This->event_listener->nsIDOMEventListener_iface, FALSE, TRUE, 2); | |
| nsAString_Finish(&type_str); | |
| nsIDOMEventTarget_Release(nstarget); | |
| if(NS_FAILED(nsres)) | |
| ERR("AddEventListener failed: %08x\n", nsres); | |
| } | |
| static dispex_static_data_vtbl_t HTMLXMLHttpRequest_dispex_vtbl = { | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| HTMLXMLHttpRequest_bind_event | |
| }; | |
| static const tid_t HTMLXMLHttpRequest_iface_tids[] = { | |
| IHTMLXMLHttpRequest_tid, | |
| 0 | |
| }; | |
| static dispex_static_data_t HTMLXMLHttpRequest_dispex = { | |
| &HTMLXMLHttpRequest_dispex_vtbl, | |
| DispHTMLXMLHttpRequest_tid, | |
| HTMLXMLHttpRequest_iface_tids | |
| }; | |
| /* IHTMLXMLHttpRequestFactory */ | |
| static inline HTMLXMLHttpRequestFactory *impl_from_IHTMLXMLHttpRequestFactory(IHTMLXMLHttpRequestFactory *iface) | |
| { | |
| return CONTAINING_RECORD(iface, HTMLXMLHttpRequestFactory, IHTMLXMLHttpRequestFactory_iface); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequestFactory_QueryInterface(IHTMLXMLHttpRequestFactory *iface, REFIID riid, void **ppv) | |
| { | |
| HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); | |
| TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); | |
| if(IsEqualGUID(&IID_IUnknown, riid)) { | |
| *ppv = &This->IHTMLXMLHttpRequestFactory_iface; | |
| }else if(IsEqualGUID(&IID_IDispatch, riid)) { | |
| *ppv = &This->IHTMLXMLHttpRequestFactory_iface; | |
| }else if(IsEqualGUID(&IID_IHTMLXMLHttpRequestFactory, riid)) { | |
| *ppv = &This->IHTMLXMLHttpRequestFactory_iface; | |
| }else if(dispex_query_interface(&This->dispex, riid, ppv)) { | |
| return *ppv ? S_OK : E_NOINTERFACE; | |
| }else { | |
| *ppv = NULL; | |
| WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); | |
| return E_NOINTERFACE; | |
| } | |
| IUnknown_AddRef((IUnknown*)*ppv); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI HTMLXMLHttpRequestFactory_AddRef(IHTMLXMLHttpRequestFactory *iface) | |
| { | |
| HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); | |
| LONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p) ref=%d\n", This, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI HTMLXMLHttpRequestFactory_Release(IHTMLXMLHttpRequestFactory *iface) | |
| { | |
| HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); | |
| LONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p) ref=%d\n", This, ref); | |
| if(!ref) { | |
| release_dispex(&This->dispex); | |
| heap_free(This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequestFactory_GetTypeInfoCount(IHTMLXMLHttpRequestFactory *iface, UINT *pctinfo) | |
| { | |
| HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); | |
| return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequestFactory_GetTypeInfo(IHTMLXMLHttpRequestFactory *iface, UINT iTInfo, | |
| LCID lcid, ITypeInfo **ppTInfo) | |
| { | |
| HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); | |
| return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequestFactory_GetIDsOfNames(IHTMLXMLHttpRequestFactory *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames, | |
| LCID lcid, DISPID *rgDispId) | |
| { | |
| HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); | |
| return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, | |
| lcid, rgDispId); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequestFactory_Invoke(IHTMLXMLHttpRequestFactory *iface, DISPID dispIdMember, REFIID riid, LCID lcid, | |
| WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) | |
| { | |
| HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); | |
| return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, | |
| pDispParams, pVarResult, pExcepInfo, puArgErr); | |
| } | |
| static HRESULT WINAPI HTMLXMLHttpRequestFactory_create(IHTMLXMLHttpRequestFactory *iface, IHTMLXMLHttpRequest **p) | |
| { | |
| HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); | |
| HTMLXMLHttpRequest *ret; | |
| nsIXMLHttpRequest *nsxhr; | |
| TRACE("(%p)->(%p)\n", This, p); | |
| nsxhr = create_nsxhr(This->window->base.outer_window->nswindow); | |
| if(!nsxhr) | |
| return E_FAIL; | |
| ret = heap_alloc_zero(sizeof(*ret)); | |
| if(!ret) { | |
| nsIXMLHttpRequest_Release(nsxhr); | |
| return E_OUTOFMEMORY; | |
| } | |
| ret->nsxhr = nsxhr; | |
| ret->IHTMLXMLHttpRequest_iface.lpVtbl = &HTMLXMLHttpRequestVtbl; | |
| ret->IProvideClassInfo2_iface.lpVtbl = &ProvideClassInfo2Vtbl; | |
| EventTarget_Init(&ret->event_target, (IUnknown*)&ret->IHTMLXMLHttpRequest_iface, | |
| &HTMLXMLHttpRequest_dispex, COMPAT_MODE_NONE); | |
| ret->ref = 1; | |
| *p = &ret->IHTMLXMLHttpRequest_iface; | |
| return S_OK; | |
| } | |
| static const IHTMLXMLHttpRequestFactoryVtbl HTMLXMLHttpRequestFactoryVtbl = { | |
| HTMLXMLHttpRequestFactory_QueryInterface, | |
| HTMLXMLHttpRequestFactory_AddRef, | |
| HTMLXMLHttpRequestFactory_Release, | |
| HTMLXMLHttpRequestFactory_GetTypeInfoCount, | |
| HTMLXMLHttpRequestFactory_GetTypeInfo, | |
| HTMLXMLHttpRequestFactory_GetIDsOfNames, | |
| HTMLXMLHttpRequestFactory_Invoke, | |
| HTMLXMLHttpRequestFactory_create | |
| }; | |
| static inline HTMLXMLHttpRequestFactory *factory_from_DispatchEx(DispatchEx *iface) | |
| { | |
| return CONTAINING_RECORD(iface, HTMLXMLHttpRequestFactory, dispex); | |
| } | |
| static HRESULT HTMLXMLHttpRequestFactory_value(DispatchEx *iface, LCID lcid, WORD flags, DISPPARAMS *params, | |
| VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) | |
| { | |
| HTMLXMLHttpRequestFactory *This = factory_from_DispatchEx(iface); | |
| IHTMLXMLHttpRequest *xhr; | |
| HRESULT hres; | |
| TRACE("\n"); | |
| if(flags != DISPATCH_CONSTRUCT) { | |
| FIXME("flags %x not supported\n", flags); | |
| return E_NOTIMPL; | |
| } | |
| hres = IHTMLXMLHttpRequestFactory_create(&This->IHTMLXMLHttpRequestFactory_iface, &xhr); | |
| if(FAILED(hres)) | |
| return hres; | |
| V_VT(res) = VT_DISPATCH; | |
| V_DISPATCH(res) = (IDispatch*)xhr; | |
| return S_OK; | |
| } | |
| static const dispex_static_data_vtbl_t HTMLXMLHttpRequestFactory_dispex_vtbl = { | |
| HTMLXMLHttpRequestFactory_value | |
| }; | |
| static const tid_t HTMLXMLHttpRequestFactory_iface_tids[] = { | |
| IHTMLXMLHttpRequestFactory_tid, | |
| 0 | |
| }; | |
| static dispex_static_data_t HTMLXMLHttpRequestFactory_dispex = { | |
| &HTMLXMLHttpRequestFactory_dispex_vtbl, | |
| IHTMLXMLHttpRequestFactory_tid, | |
| HTMLXMLHttpRequestFactory_iface_tids | |
| }; | |
| HRESULT HTMLXMLHttpRequestFactory_Create(HTMLInnerWindow* window, HTMLXMLHttpRequestFactory **ret_ptr) | |
| { | |
| HTMLXMLHttpRequestFactory *ret; | |
| ret = heap_alloc(sizeof(*ret)); | |
| if(!ret) | |
| return E_OUTOFMEMORY; | |
| ret->IHTMLXMLHttpRequestFactory_iface.lpVtbl = &HTMLXMLHttpRequestFactoryVtbl; | |
| ret->ref = 1; | |
| ret->window = window; | |
| init_dispex(&ret->dispex, (IUnknown*)&ret->IHTMLXMLHttpRequestFactory_iface, | |
| &HTMLXMLHttpRequestFactory_dispex); | |
| *ret_ptr = ret; | |
| return S_OK; | |
| } |