kernelbase: Ignore URL_PARTFLAG_KEEPSCHEME when used with URL_PART_SCHEME or URL_PART...
[wine.git] / dlls / mshtml / xmlhttprequest.c
blobcd8ba65b5b8b935052a80616eeb14bbc60aa82ea
1 /*
2 * Copyright 2015 Zhenbo Li
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
21 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
28 #include "wine/debug.h"
30 #include "mshtml_private.h"
31 #include "htmlevent.h"
32 #include "mshtmdid.h"
33 #include "initguid.h"
34 #include "msxml6.h"
35 #include "objsafe.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
39 #define MSHTML_DISPID_HTMLXMLHTTPREQUEST_ONLOAD MSHTML_DISPID_CUSTOM_MIN
41 static HRESULT bstr_to_nsacstr(BSTR bstr, nsACString *str)
43 char *cstr = heap_strdupWtoU(bstr);
44 if(!cstr)
45 return E_OUTOFMEMORY;
46 nsACString_Init(str, cstr);
47 heap_free(cstr);
48 return S_OK;
51 static HRESULT variant_to_nsastr(VARIANT var, nsAString *ret)
53 switch(V_VT(&var)) {
54 case VT_NULL:
55 case VT_ERROR:
56 case VT_EMPTY:
57 nsAString_Init(ret, NULL);
58 return S_OK;
59 case VT_BSTR:
60 nsAString_InitDepend(ret, V_BSTR(&var));
61 return S_OK;
62 default:
63 FIXME("Unsupported VARIANT: %s\n", debugstr_variant(&var));
64 return E_INVALIDARG;
68 static HRESULT return_nscstr(nsresult nsres, nsACString *nscstr, BSTR *p)
70 const char *str;
71 int len;
73 if(NS_FAILED(nsres)) {
74 ERR("failed: %08x\n", nsres);
75 nsACString_Finish(nscstr);
76 return E_FAIL;
79 nsACString_GetData(nscstr, &str);
81 if(*str) {
82 len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
83 *p = SysAllocStringLen(NULL, len - 1);
84 if(!*p) {
85 nsACString_Finish(nscstr);
86 return E_OUTOFMEMORY;
88 MultiByteToWideChar(CP_UTF8, 0, str, -1, *p, len);
89 }else {
90 *p = NULL;
93 nsACString_Finish(nscstr);
94 return S_OK;
97 typedef struct {
98 nsIDOMEventListener nsIDOMEventListener_iface;
99 LONG ref;
100 HTMLXMLHttpRequest *xhr;
101 BOOL readystatechange_event;
102 BOOL load_event;
103 } XMLHttpReqEventListener;
105 struct HTMLXMLHttpRequest {
106 EventTarget event_target;
107 IHTMLXMLHttpRequest IHTMLXMLHttpRequest_iface;
108 IProvideClassInfo2 IProvideClassInfo2_iface;
109 LONG ref;
110 nsIXMLHttpRequest *nsxhr;
111 XMLHttpReqEventListener *event_listener;
114 static void detach_xhr_event_listener(XMLHttpReqEventListener *event_listener)
116 nsIDOMEventTarget *event_target;
117 nsAString str;
118 nsresult nsres;
120 nsres = nsIXMLHttpRequest_QueryInterface(event_listener->xhr->nsxhr, &IID_nsIDOMEventTarget, (void**)&event_target);
121 assert(nsres == NS_OK);
123 if(event_listener->readystatechange_event) {
124 nsAString_InitDepend(&str, L"onreadystatechange");
125 nsres = nsIDOMEventTarget_RemoveEventListener(event_target, &str, &event_listener->nsIDOMEventListener_iface, FALSE);
126 nsAString_Finish(&str);
127 assert(nsres == NS_OK);
130 if(event_listener->load_event) {
131 nsAString_InitDepend(&str, L"load");
132 nsres = nsIDOMEventTarget_RemoveEventListener(event_target, &str, &event_listener->nsIDOMEventListener_iface, FALSE);
133 nsAString_Finish(&str);
134 assert(nsres == NS_OK);
137 nsIDOMEventTarget_Release(event_target);
139 event_listener->xhr->event_listener = NULL;
140 event_listener->xhr = NULL;
141 nsIDOMEventListener_Release(&event_listener->nsIDOMEventListener_iface);
145 static inline XMLHttpReqEventListener *impl_from_nsIDOMEventListener(nsIDOMEventListener *iface)
147 return CONTAINING_RECORD(iface, XMLHttpReqEventListener, nsIDOMEventListener_iface);
150 static nsresult NSAPI XMLHttpReqEventListener_QueryInterface(nsIDOMEventListener *iface,
151 nsIIDRef riid, void **result)
153 XMLHttpReqEventListener *This = impl_from_nsIDOMEventListener(iface);
155 if(IsEqualGUID(&IID_nsISupports, riid)) {
156 TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
157 *result = &This->nsIDOMEventListener_iface;
158 }else if(IsEqualGUID(&IID_nsIDOMEventListener, riid)) {
159 TRACE("(%p)->(IID_nsIDOMEventListener %p)\n", This, result);
160 *result = &This->nsIDOMEventListener_iface;
161 }else {
162 *result = NULL;
163 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
164 return NS_NOINTERFACE;
167 nsIDOMEventListener_AddRef(&This->nsIDOMEventListener_iface);
168 return NS_OK;
171 static nsrefcnt NSAPI XMLHttpReqEventListener_AddRef(nsIDOMEventListener *iface)
173 XMLHttpReqEventListener *This = impl_from_nsIDOMEventListener(iface);
174 LONG ref = InterlockedIncrement(&This->ref);
176 TRACE("(%p) ref=%d\n", This, ref);
178 return ref;
181 static nsrefcnt NSAPI XMLHttpReqEventListener_Release(nsIDOMEventListener *iface)
183 XMLHttpReqEventListener *This = impl_from_nsIDOMEventListener(iface);
184 LONG ref = InterlockedDecrement(&This->ref);
186 TRACE("(%p) ref=%d\n", This, ref);
188 if(!ref) {
189 assert(!This->xhr);
190 heap_free(This);
193 return ref;
196 static nsresult NSAPI XMLHttpReqEventListener_HandleEvent(nsIDOMEventListener *iface, nsIDOMEvent *nsevent)
198 XMLHttpReqEventListener *This = impl_from_nsIDOMEventListener(iface);
199 DOMEvent *event;
200 HRESULT hres;
202 TRACE("(%p)\n", This);
204 if(!This->xhr)
205 return NS_OK;
207 hres = create_event_from_nsevent(nsevent, dispex_compat_mode(&This->xhr->event_target.dispex), &event);
208 if(SUCCEEDED(hres) ){
209 dispatch_event(&This->xhr->event_target, event);
210 IDOMEvent_Release(&event->IDOMEvent_iface);
212 return NS_OK;
215 static const nsIDOMEventListenerVtbl XMLHttpReqEventListenerVtbl = {
216 XMLHttpReqEventListener_QueryInterface,
217 XMLHttpReqEventListener_AddRef,
218 XMLHttpReqEventListener_Release,
219 XMLHttpReqEventListener_HandleEvent
222 static inline HTMLXMLHttpRequest *impl_from_IHTMLXMLHttpRequest(IHTMLXMLHttpRequest *iface)
224 return CONTAINING_RECORD(iface, HTMLXMLHttpRequest, IHTMLXMLHttpRequest_iface);
227 static HRESULT WINAPI HTMLXMLHttpRequest_QueryInterface(IHTMLXMLHttpRequest *iface, REFIID riid, void **ppv)
229 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
231 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
233 if(IsEqualGUID(&IID_IUnknown, riid)) {
234 *ppv = &This->IHTMLXMLHttpRequest_iface;
235 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
236 *ppv = &This->IHTMLXMLHttpRequest_iface;
237 }else if(IsEqualGUID(&IID_IHTMLXMLHttpRequest, riid)) {
238 *ppv = &This->IHTMLXMLHttpRequest_iface;
239 }else if(IsEqualGUID(&IID_IProvideClassInfo, riid)) {
240 *ppv = &This->IProvideClassInfo2_iface;
241 }else if(IsEqualGUID(&IID_IProvideClassInfo2, riid)) {
242 *ppv = &This->IProvideClassInfo2_iface;
243 }else {
244 return EventTarget_QI(&This->event_target, riid, ppv);
247 IUnknown_AddRef((IUnknown*)*ppv);
248 return S_OK;
251 static ULONG WINAPI HTMLXMLHttpRequest_AddRef(IHTMLXMLHttpRequest *iface)
253 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
254 LONG ref = InterlockedIncrement(&This->ref);
256 TRACE("(%p) ref=%d\n", This, ref);
258 return ref;
261 static ULONG WINAPI HTMLXMLHttpRequest_Release(IHTMLXMLHttpRequest *iface)
263 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
264 LONG ref = InterlockedDecrement(&This->ref);
266 TRACE("(%p) ref=%d\n", This, ref);
268 if(!ref) {
269 if(This->event_listener)
270 detach_xhr_event_listener(This->event_listener);
271 release_event_target(&This->event_target);
272 release_dispex(&This->event_target.dispex);
273 nsIXMLHttpRequest_Release(This->nsxhr);
274 heap_free(This);
277 return ref;
280 static HRESULT WINAPI HTMLXMLHttpRequest_GetTypeInfoCount(IHTMLXMLHttpRequest *iface, UINT *pctinfo)
282 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
283 return IDispatchEx_GetTypeInfoCount(&This->event_target.dispex.IDispatchEx_iface, pctinfo);
286 static HRESULT WINAPI HTMLXMLHttpRequest_GetTypeInfo(IHTMLXMLHttpRequest *iface, UINT iTInfo,
287 LCID lcid, ITypeInfo **ppTInfo)
289 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
291 return IDispatchEx_GetTypeInfo(&This->event_target.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
294 static HRESULT WINAPI HTMLXMLHttpRequest_GetIDsOfNames(IHTMLXMLHttpRequest *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames,
295 LCID lcid, DISPID *rgDispId)
297 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
299 return IDispatchEx_GetIDsOfNames(&This->event_target.dispex.IDispatchEx_iface, riid, rgszNames, cNames,
300 lcid, rgDispId);
303 static HRESULT WINAPI HTMLXMLHttpRequest_Invoke(IHTMLXMLHttpRequest *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
304 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
306 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
308 return IDispatchEx_Invoke(&This->event_target.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags,
309 pDispParams, pVarResult, pExcepInfo, puArgErr);
312 static HRESULT WINAPI HTMLXMLHttpRequest_get_readyState(IHTMLXMLHttpRequest *iface, LONG *p)
314 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
315 UINT16 val;
316 nsresult nsres;
318 TRACE("(%p)->(%p)\n", This, p);
320 if(!p)
321 return E_POINTER;
322 nsres = nsIXMLHttpRequest_GetReadyState(This->nsxhr, &val);
323 if(NS_FAILED(nsres)) {
324 ERR("nsIXMLHttpRequest_GetReadyState failed: %08x\n", nsres);
325 return E_FAIL;
327 *p = val;
328 return S_OK;
331 static HRESULT WINAPI HTMLXMLHttpRequest_get_responseBody(IHTMLXMLHttpRequest *iface, VARIANT *p)
333 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
334 FIXME("(%p)->(%p)\n", This, p);
335 return E_NOTIMPL;
338 static HRESULT WINAPI HTMLXMLHttpRequest_get_responseText(IHTMLXMLHttpRequest *iface, BSTR *p)
340 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
341 nsAString nsstr;
342 nsresult nsres;
344 TRACE("(%p)->(%p)\n", This, p);
346 if(!p)
347 return E_POINTER;
349 nsAString_Init(&nsstr, NULL);
350 nsres = nsIXMLHttpRequest_GetResponseText(This->nsxhr, &nsstr);
351 return return_nsstr(nsres, &nsstr, p);
354 static HRESULT WINAPI HTMLXMLHttpRequest_get_responseXML(IHTMLXMLHttpRequest *iface, IDispatch **p)
356 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
357 IXMLDOMDocument *xmldoc = NULL;
358 BSTR str;
359 HRESULT hres;
360 VARIANT_BOOL vbool;
361 IObjectSafety *safety;
363 TRACE("(%p)->(%p)\n", This, p);
365 hres = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void**)&xmldoc);
366 if(FAILED(hres)) {
367 ERR("CoCreateInstance failed: %08x\n", hres);
368 return hres;
371 hres = IHTMLXMLHttpRequest_get_responseText(iface, &str);
372 if(FAILED(hres)) {
373 IXMLDOMDocument_Release(xmldoc);
374 ERR("get_responseText failed: %08x\n", hres);
375 return hres;
378 hres = IXMLDOMDocument_loadXML(xmldoc, str, &vbool);
379 SysFreeString(str);
380 if(hres != S_OK || vbool != VARIANT_TRUE)
381 WARN("loadXML failed: %08x, returning an empty xmldoc\n", hres);
383 hres = IXMLDOMDocument_QueryInterface(xmldoc, &IID_IObjectSafety, (void**)&safety);
384 assert(SUCCEEDED(hres));
385 hres = IObjectSafety_SetInterfaceSafetyOptions(safety, NULL,
386 INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA | INTERFACE_USES_SECURITY_MANAGER,
387 INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA | INTERFACE_USES_SECURITY_MANAGER);
388 assert(SUCCEEDED(hres));
389 IObjectSafety_Release(safety);
391 *p = (IDispatch*)xmldoc;
392 return S_OK;
395 static HRESULT WINAPI HTMLXMLHttpRequest_get_status(IHTMLXMLHttpRequest *iface, LONG *p)
397 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
398 UINT32 val;
399 nsresult nsres;
400 TRACE("(%p)->(%p)\n", This, p);
402 if(!p)
403 return E_POINTER;
405 nsres = nsIXMLHttpRequest_GetStatus(This->nsxhr, &val);
406 if(NS_FAILED(nsres)) {
407 ERR("nsIXMLHttpRequest_GetStatus failed: %08x\n", nsres);
408 return E_FAIL;
410 *p = val;
411 if(val == 0)
412 return E_FAIL; /* WinAPI thinks this is an error */
414 return S_OK;
417 static HRESULT WINAPI HTMLXMLHttpRequest_get_statusText(IHTMLXMLHttpRequest *iface, BSTR *p)
419 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
420 nsACString nscstr;
421 nsresult nsres;
422 HRESULT hres;
423 LONG state;
425 TRACE("(%p)->(%p)\n", This, p);
427 if(!p)
428 return E_POINTER;
430 hres = IHTMLXMLHttpRequest_get_readyState(iface, &state);
431 if(FAILED(hres))
432 return hres;
434 if(state < 2) {
435 *p = NULL;
436 return E_FAIL;
439 nsACString_Init(&nscstr, NULL);
440 nsres = nsIXMLHttpRequest_GetStatusText(This->nsxhr, &nscstr);
441 return return_nscstr(nsres, &nscstr, p);
444 static HRESULT WINAPI HTMLXMLHttpRequest_put_onreadystatechange(IHTMLXMLHttpRequest *iface, VARIANT v)
446 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
448 TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
450 return set_event_handler(&This->event_target, EVENTID_READYSTATECHANGE, &v);
453 static HRESULT WINAPI HTMLXMLHttpRequest_get_onreadystatechange(IHTMLXMLHttpRequest *iface, VARIANT *p)
455 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
457 TRACE("(%p)->(%p)\n", This, p);
459 return get_event_handler(&This->event_target, EVENTID_READYSTATECHANGE, p);
462 static HRESULT WINAPI HTMLXMLHttpRequest_abort(IHTMLXMLHttpRequest *iface)
464 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
465 nsresult nsres;
467 TRACE("(%p)->()\n", This);
469 nsres = nsIXMLHttpRequest_SlowAbort(This->nsxhr);
470 if(NS_FAILED(nsres)) {
471 ERR("nsIXMLHttpRequest_SlowAbort failed: %08x\n", nsres);
472 return E_FAIL;
475 return S_OK;
478 static HRESULT HTMLXMLHttpRequest_open_hook(DispatchEx *dispex, WORD flags,
479 DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
481 /* If only two arguments were given, implicitly set async to false */
482 if((flags & DISPATCH_METHOD) && dp->cArgs == 2 && !dp->cNamedArgs) {
483 VARIANT args[5];
484 DISPPARAMS new_dp = {args, NULL, ARRAY_SIZE(args), 0};
485 V_VT(args) = VT_EMPTY;
486 V_VT(args+1) = VT_EMPTY;
487 V_VT(args+2) = VT_BOOL;
488 V_BOOL(args+2) = VARIANT_TRUE;
489 args[3] = dp->rgvarg[0];
490 args[4] = dp->rgvarg[1];
492 TRACE("implicit async\n");
494 return dispex_call_builtin(dispex, DISPID_IHTMLXMLHTTPREQUEST_OPEN, &new_dp, res, ei, caller);
497 return S_FALSE; /* fallback to default */
500 static HRESULT WINAPI HTMLXMLHttpRequest_open(IHTMLXMLHttpRequest *iface, BSTR bstrMethod, BSTR bstrUrl, VARIANT varAsync, VARIANT varUser, VARIANT varPassword)
502 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
503 nsACString method, url;
504 nsAString user, password;
505 nsresult nsres;
506 HRESULT hres;
508 TRACE("(%p)->(%s %s %s %s %s)\n", This, debugstr_w(bstrMethod), debugstr_w(bstrUrl), debugstr_variant(&varAsync), debugstr_variant(&varUser), debugstr_variant(&varPassword));
510 if(V_VT(&varAsync) != VT_BOOL) {
511 FIXME("varAsync not supported: %s\n", debugstr_variant(&varAsync));
512 return E_FAIL;
515 /* Note: Starting with Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27),
516 * synchronous requests on the main thread have been deprecated due to the negative
517 * effects to the user experience.
519 if(!V_BOOL(&varAsync)) {
520 FIXME("Synchronous request is not supported yet\n");
521 return E_FAIL;
524 hres = variant_to_nsastr(varUser, &user);
525 if(FAILED(hres))
526 return hres;
527 hres = variant_to_nsastr(varPassword, &password);
528 if(FAILED(hres)) {
529 nsAString_Finish(&user);
530 return hres;
533 hres = bstr_to_nsacstr(bstrMethod, &method);
534 if(FAILED(hres)) {
535 nsAString_Finish(&user);
536 nsAString_Finish(&password);
537 return hres;
539 hres = bstr_to_nsacstr(bstrUrl, &url);
540 if(FAILED(hres)) {
541 nsAString_Finish(&user);
542 nsAString_Finish(&password);
543 nsACString_Finish(&method);
544 return hres;
547 nsres = nsIXMLHttpRequest_Open(This->nsxhr, &method, &url, TRUE,
548 &user, &password, 0);
550 nsACString_Finish(&method);
551 nsACString_Finish(&url);
552 nsAString_Finish(&user);
553 nsAString_Finish(&password);
555 if(NS_FAILED(nsres)) {
556 ERR("nsIXMLHttpRequest_Open failed: %08x\n", nsres);
557 return E_FAIL;
560 return S_OK;
563 static HRESULT WINAPI HTMLXMLHttpRequest_send(IHTMLXMLHttpRequest *iface, VARIANT varBody)
565 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
566 nsIWritableVariant *nsbody = NULL;
567 nsresult nsres = NS_OK;
569 TRACE("(%p)->(%s)\n", This, debugstr_variant(&varBody));
571 switch(V_VT(&varBody)) {
572 case VT_NULL:
573 case VT_EMPTY:
574 case VT_ERROR:
575 break;
576 case VT_BSTR: {
577 nsAString nsstr;
579 nsbody = create_nsvariant();
580 if(!nsbody)
581 return E_OUTOFMEMORY;
583 nsAString_InitDepend(&nsstr, V_BSTR(&varBody));
584 nsres = nsIWritableVariant_SetAsAString(nsbody, &nsstr);
585 nsAString_Finish(&nsstr);
586 break;
588 default:
589 FIXME("unsupported body type %s\n", debugstr_variant(&varBody));
590 return E_NOTIMPL;
593 if(NS_SUCCEEDED(nsres))
594 nsres = nsIXMLHttpRequest_Send(This->nsxhr, (nsIVariant*)nsbody);
595 if(nsbody)
596 nsIWritableVariant_Release(nsbody);
597 if(NS_FAILED(nsres)) {
598 ERR("nsIXMLHttpRequest_Send failed: %08x\n", nsres);
599 return E_FAIL;
602 return S_OK;
605 static HRESULT WINAPI HTMLXMLHttpRequest_getAllResponseHeaders(IHTMLXMLHttpRequest *iface, BSTR *p)
607 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
608 nsACString nscstr;
609 nsresult nsres;
610 HRESULT hres;
611 LONG state;
613 TRACE("(%p)->(%p)\n", This, p);
615 if(!p)
616 return E_POINTER;
618 hres = IHTMLXMLHttpRequest_get_readyState(iface, &state);
619 if(FAILED(hres))
620 return hres;
622 if(state < 2) {
623 *p = NULL;
624 return E_FAIL;
627 nsACString_Init(&nscstr, NULL);
628 nsres = nsIXMLHttpRequest_GetAllResponseHeaders(This->nsxhr, &nscstr);
629 return return_nscstr(nsres, &nscstr, p);
632 static HRESULT WINAPI HTMLXMLHttpRequest_getResponseHeader(IHTMLXMLHttpRequest *iface, BSTR bstrHeader, BSTR *p)
634 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
635 nsACString header, ret;
636 char *cstr;
637 nsresult nsres;
638 HRESULT hres;
639 LONG state;
640 TRACE("(%p)->(%s %p)\n", This, debugstr_w(bstrHeader), p);
642 if(!p)
643 return E_POINTER;
644 if(!bstrHeader)
645 return E_INVALIDARG;
647 hres = IHTMLXMLHttpRequest_get_readyState(iface, &state);
648 if(FAILED(hres))
649 return hres;
651 if(state < 2) {
652 *p = NULL;
653 return E_FAIL;
656 cstr = heap_strdupWtoU(bstrHeader);
657 nsACString_InitDepend(&header, cstr);
658 nsACString_Init(&ret, NULL);
660 nsres = nsIXMLHttpRequest_GetResponseHeader(This->nsxhr, &header, &ret);
662 nsACString_Finish(&header);
663 heap_free(cstr);
664 return return_nscstr(nsres, &ret, p);
667 static HRESULT WINAPI HTMLXMLHttpRequest_setRequestHeader(IHTMLXMLHttpRequest *iface, BSTR bstrHeader, BSTR bstrValue)
669 HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface);
670 char *header_u, *value_u;
671 nsACString header, value;
672 nsresult nsres;
674 TRACE("(%p)->(%s %s)\n", This, debugstr_w(bstrHeader), debugstr_w(bstrValue));
676 header_u = heap_strdupWtoU(bstrHeader);
677 if(bstrHeader && !header_u)
678 return E_OUTOFMEMORY;
680 value_u = heap_strdupWtoU(bstrValue);
681 if(bstrValue && !value_u) {
682 heap_free(header_u);
683 return E_OUTOFMEMORY;
686 nsACString_InitDepend(&header, header_u);
687 nsACString_InitDepend(&value, value_u);
688 nsres = nsIXMLHttpRequest_SetRequestHeader(This->nsxhr, &header, &value);
689 nsACString_Finish(&header);
690 nsACString_Finish(&value);
691 heap_free(header_u);
692 heap_free(value_u);
693 if(NS_FAILED(nsres)) {
694 ERR("SetRequestHeader failed: %08x\n", nsres);
695 return E_FAIL;
698 return S_OK;
701 static const IHTMLXMLHttpRequestVtbl HTMLXMLHttpRequestVtbl = {
702 HTMLXMLHttpRequest_QueryInterface,
703 HTMLXMLHttpRequest_AddRef,
704 HTMLXMLHttpRequest_Release,
705 HTMLXMLHttpRequest_GetTypeInfoCount,
706 HTMLXMLHttpRequest_GetTypeInfo,
707 HTMLXMLHttpRequest_GetIDsOfNames,
708 HTMLXMLHttpRequest_Invoke,
709 HTMLXMLHttpRequest_get_readyState,
710 HTMLXMLHttpRequest_get_responseBody,
711 HTMLXMLHttpRequest_get_responseText,
712 HTMLXMLHttpRequest_get_responseXML,
713 HTMLXMLHttpRequest_get_status,
714 HTMLXMLHttpRequest_get_statusText,
715 HTMLXMLHttpRequest_put_onreadystatechange,
716 HTMLXMLHttpRequest_get_onreadystatechange,
717 HTMLXMLHttpRequest_abort,
718 HTMLXMLHttpRequest_open,
719 HTMLXMLHttpRequest_send,
720 HTMLXMLHttpRequest_getAllResponseHeaders,
721 HTMLXMLHttpRequest_getResponseHeader,
722 HTMLXMLHttpRequest_setRequestHeader
725 static inline HTMLXMLHttpRequest *impl_from_IProvideClassInfo2(IProvideClassInfo2 *iface)
727 return CONTAINING_RECORD(iface, HTMLXMLHttpRequest, IProvideClassInfo2_iface);
730 static HRESULT WINAPI ProvideClassInfo_QueryInterface(IProvideClassInfo2 *iface, REFIID riid, void **ppv)
732 HTMLXMLHttpRequest *This = impl_from_IProvideClassInfo2(iface);
733 return IHTMLXMLHttpRequest_QueryInterface(&This->IHTMLXMLHttpRequest_iface, riid, ppv);
736 static ULONG WINAPI ProvideClassInfo_AddRef(IProvideClassInfo2 *iface)
738 HTMLXMLHttpRequest *This = impl_from_IProvideClassInfo2(iface);
739 return IHTMLXMLHttpRequest_AddRef(&This->IHTMLXMLHttpRequest_iface);
742 static ULONG WINAPI ProvideClassInfo_Release(IProvideClassInfo2 *iface)
744 HTMLXMLHttpRequest *This = impl_from_IProvideClassInfo2(iface);
745 return IHTMLXMLHttpRequest_Release(&This->IHTMLXMLHttpRequest_iface);
748 static HRESULT WINAPI ProvideClassInfo_GetClassInfo(IProvideClassInfo2 *iface, ITypeInfo **ppTI)
750 HTMLXMLHttpRequest *This = impl_from_IProvideClassInfo2(iface);
751 TRACE("(%p)->(%p)\n", This, ppTI);
752 return get_class_typeinfo(&CLSID_HTMLXMLHttpRequest, ppTI);
755 static HRESULT WINAPI ProvideClassInfo2_GetGUID(IProvideClassInfo2 *iface, DWORD dwGuidKind, GUID *pGUID)
757 HTMLXMLHttpRequest *This = impl_from_IProvideClassInfo2(iface);
758 FIXME("(%p)->(%u %p)\n", This, dwGuidKind, pGUID);
759 return E_NOTIMPL;
762 static const IProvideClassInfo2Vtbl ProvideClassInfo2Vtbl = {
763 ProvideClassInfo_QueryInterface,
764 ProvideClassInfo_AddRef,
765 ProvideClassInfo_Release,
766 ProvideClassInfo_GetClassInfo,
767 ProvideClassInfo2_GetGUID,
770 static inline HTMLXMLHttpRequest *impl_from_DispatchEx(DispatchEx *iface)
772 return CONTAINING_RECORD(iface, HTMLXMLHttpRequest, event_target.dispex);
775 static HRESULT HTMLXMLHttpRequest_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid)
777 /* onload event handler property is supported, but not exposed by any interface. We implement as a custom property. */
778 if(!wcscmp(L"onload", name)) {
779 *dispid = MSHTML_DISPID_HTMLXMLHTTPREQUEST_ONLOAD;
780 return S_OK;
783 return DISP_E_UNKNOWNNAME;
786 static HRESULT HTMLXMLHttpRequest_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
787 VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
789 HTMLXMLHttpRequest *This = impl_from_DispatchEx(dispex);
791 if(id == MSHTML_DISPID_HTMLXMLHTTPREQUEST_ONLOAD) {
792 switch(flags) {
793 case DISPATCH_PROPERTYGET:
794 TRACE("(%p) get onload\n", This);
795 return get_event_handler(&This->event_target, EVENTID_LOAD, res);
797 case DISPATCH_PROPERTYPUT:
798 if(params->cArgs != 1 || (params->cNamedArgs == 1 && *params->rgdispidNamedArgs != DISPID_PROPERTYPUT)
799 || params->cNamedArgs > 1) {
800 FIXME("invalid args\n");
801 return E_INVALIDARG;
804 TRACE("(%p)->(%p) set onload\n", This, params->rgvarg);
805 return set_event_handler(&This->event_target, EVENTID_LOAD, params->rgvarg);
807 default:
808 FIXME("Unimplemented flags %x\n", flags);
809 return E_NOTIMPL;
813 return DISP_E_UNKNOWNNAME;
816 static nsISupports *HTMLXMLHttpRequest_get_gecko_target(DispatchEx *dispex)
818 HTMLXMLHttpRequest *This = impl_from_DispatchEx(dispex);
819 return (nsISupports*)This->nsxhr;
822 static void HTMLXMLHttpRequest_bind_event(DispatchEx *dispex, eventid_t eid)
824 HTMLXMLHttpRequest *This = impl_from_DispatchEx(dispex);
825 nsIDOMEventTarget *nstarget;
826 const WCHAR *type_name;
827 nsAString type_str;
828 nsresult nsres;
830 TRACE("(%p)\n", This);
832 switch(eid) {
833 case EVENTID_READYSTATECHANGE:
834 type_name = L"readystatechange";
835 break;
836 case EVENTID_LOAD:
837 type_name = L"load";
838 break;
839 default:
840 return;
843 if(!This->event_listener) {
844 This->event_listener = heap_alloc(sizeof(*This->event_listener));
845 if(!This->event_listener)
846 return;
848 This->event_listener->nsIDOMEventListener_iface.lpVtbl = &XMLHttpReqEventListenerVtbl;
849 This->event_listener->ref = 1;
850 This->event_listener->xhr = This;
851 This->event_listener->readystatechange_event = FALSE;
852 This->event_listener->load_event = FALSE;
855 nsres = nsIXMLHttpRequest_QueryInterface(This->nsxhr, &IID_nsIDOMEventTarget, (void**)&nstarget);
856 assert(nsres == NS_OK);
858 nsAString_InitDepend(&type_str, type_name);
859 nsres = nsIDOMEventTarget_AddEventListener(nstarget, &type_str, &This->event_listener->nsIDOMEventListener_iface, FALSE, TRUE, 2);
860 nsAString_Finish(&type_str);
861 if(NS_FAILED(nsres))
862 ERR("AddEventListener(%s) failed: %08x\n", debugstr_w(type_name), nsres);
864 nsIDOMEventTarget_Release(nstarget);
866 if(eid == EVENTID_READYSTATECHANGE)
867 This->event_listener->readystatechange_event = TRUE;
868 else
869 This->event_listener->load_event = TRUE;
872 static void HTMLXMLHttpRequest_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode)
874 static const dispex_hook_t xhr_hooks[] = {
875 {DISPID_IHTMLXMLHTTPREQUEST_OPEN, HTMLXMLHttpRequest_open_hook},
876 {DISPID_UNKNOWN}
879 EventTarget_init_dispex_info(info, compat_mode);
880 dispex_info_add_interface(info, IHTMLXMLHttpRequest_tid, compat_mode >= COMPAT_MODE_IE10 ? xhr_hooks : NULL);
883 static event_target_vtbl_t HTMLXMLHttpRequest_event_target_vtbl = {
885 NULL,
886 HTMLXMLHttpRequest_get_dispid,
887 HTMLXMLHttpRequest_invoke
889 HTMLXMLHttpRequest_get_gecko_target,
890 HTMLXMLHttpRequest_bind_event
893 static const tid_t HTMLXMLHttpRequest_iface_tids[] = {
896 static dispex_static_data_t HTMLXMLHttpRequest_dispex = {
897 L"XMLHttpRequest",
898 &HTMLXMLHttpRequest_event_target_vtbl.dispex_vtbl,
899 DispHTMLXMLHttpRequest_tid,
900 HTMLXMLHttpRequest_iface_tids,
901 HTMLXMLHttpRequest_init_dispex_info
905 /* IHTMLXMLHttpRequestFactory */
906 static inline HTMLXMLHttpRequestFactory *impl_from_IHTMLXMLHttpRequestFactory(IHTMLXMLHttpRequestFactory *iface)
908 return CONTAINING_RECORD(iface, HTMLXMLHttpRequestFactory, IHTMLXMLHttpRequestFactory_iface);
911 static HRESULT WINAPI HTMLXMLHttpRequestFactory_QueryInterface(IHTMLXMLHttpRequestFactory *iface, REFIID riid, void **ppv)
913 HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface);
915 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
917 if(IsEqualGUID(&IID_IUnknown, riid)) {
918 *ppv = &This->IHTMLXMLHttpRequestFactory_iface;
919 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
920 *ppv = &This->IHTMLXMLHttpRequestFactory_iface;
921 }else if(IsEqualGUID(&IID_IHTMLXMLHttpRequestFactory, riid)) {
922 *ppv = &This->IHTMLXMLHttpRequestFactory_iface;
923 }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
924 return *ppv ? S_OK : E_NOINTERFACE;
925 }else {
926 *ppv = NULL;
927 WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
928 return E_NOINTERFACE;
931 IUnknown_AddRef((IUnknown*)*ppv);
932 return S_OK;
935 static ULONG WINAPI HTMLXMLHttpRequestFactory_AddRef(IHTMLXMLHttpRequestFactory *iface)
937 HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface);
938 LONG ref = InterlockedIncrement(&This->ref);
940 TRACE("(%p) ref=%d\n", This, ref);
942 return ref;
945 static ULONG WINAPI HTMLXMLHttpRequestFactory_Release(IHTMLXMLHttpRequestFactory *iface)
947 HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface);
948 LONG ref = InterlockedDecrement(&This->ref);
950 TRACE("(%p) ref=%d\n", This, ref);
952 if(!ref) {
953 release_dispex(&This->dispex);
954 heap_free(This);
957 return ref;
960 static HRESULT WINAPI HTMLXMLHttpRequestFactory_GetTypeInfoCount(IHTMLXMLHttpRequestFactory *iface, UINT *pctinfo)
962 HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface);
963 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
966 static HRESULT WINAPI HTMLXMLHttpRequestFactory_GetTypeInfo(IHTMLXMLHttpRequestFactory *iface, UINT iTInfo,
967 LCID lcid, ITypeInfo **ppTInfo)
969 HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface);
971 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
974 static HRESULT WINAPI HTMLXMLHttpRequestFactory_GetIDsOfNames(IHTMLXMLHttpRequestFactory *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames,
975 LCID lcid, DISPID *rgDispId)
977 HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface);
979 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
980 lcid, rgDispId);
983 static HRESULT WINAPI HTMLXMLHttpRequestFactory_Invoke(IHTMLXMLHttpRequestFactory *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
984 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
986 HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface);
988 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags,
989 pDispParams, pVarResult, pExcepInfo, puArgErr);
992 static HRESULT WINAPI HTMLXMLHttpRequestFactory_create(IHTMLXMLHttpRequestFactory *iface, IHTMLXMLHttpRequest **p)
994 HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface);
995 HTMLXMLHttpRequest *ret;
996 nsIXMLHttpRequest *nsxhr;
998 TRACE("(%p)->(%p)\n", This, p);
1000 nsxhr = create_nsxhr(This->window->base.outer_window->nswindow);
1001 if(!nsxhr)
1002 return E_FAIL;
1004 ret = heap_alloc_zero(sizeof(*ret));
1005 if(!ret) {
1006 nsIXMLHttpRequest_Release(nsxhr);
1007 return E_OUTOFMEMORY;
1009 ret->nsxhr = nsxhr;
1011 ret->IHTMLXMLHttpRequest_iface.lpVtbl = &HTMLXMLHttpRequestVtbl;
1012 ret->IProvideClassInfo2_iface.lpVtbl = &ProvideClassInfo2Vtbl;
1013 EventTarget_Init(&ret->event_target, (IUnknown*)&ret->IHTMLXMLHttpRequest_iface,
1014 &HTMLXMLHttpRequest_dispex, This->window->doc->document_mode);
1015 ret->ref = 1;
1017 *p = &ret->IHTMLXMLHttpRequest_iface;
1018 return S_OK;
1021 static const IHTMLXMLHttpRequestFactoryVtbl HTMLXMLHttpRequestFactoryVtbl = {
1022 HTMLXMLHttpRequestFactory_QueryInterface,
1023 HTMLXMLHttpRequestFactory_AddRef,
1024 HTMLXMLHttpRequestFactory_Release,
1025 HTMLXMLHttpRequestFactory_GetTypeInfoCount,
1026 HTMLXMLHttpRequestFactory_GetTypeInfo,
1027 HTMLXMLHttpRequestFactory_GetIDsOfNames,
1028 HTMLXMLHttpRequestFactory_Invoke,
1029 HTMLXMLHttpRequestFactory_create
1032 static inline HTMLXMLHttpRequestFactory *factory_from_DispatchEx(DispatchEx *iface)
1034 return CONTAINING_RECORD(iface, HTMLXMLHttpRequestFactory, dispex);
1037 static HRESULT HTMLXMLHttpRequestFactory_value(DispatchEx *iface, LCID lcid, WORD flags, DISPPARAMS *params,
1038 VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
1040 HTMLXMLHttpRequestFactory *This = factory_from_DispatchEx(iface);
1041 IHTMLXMLHttpRequest *xhr;
1042 HRESULT hres;
1044 TRACE("\n");
1046 if(flags != DISPATCH_CONSTRUCT) {
1047 FIXME("flags %x not supported\n", flags);
1048 return E_NOTIMPL;
1051 hres = IHTMLXMLHttpRequestFactory_create(&This->IHTMLXMLHttpRequestFactory_iface, &xhr);
1052 if(FAILED(hres))
1053 return hres;
1055 V_VT(res) = VT_DISPATCH;
1056 V_DISPATCH(res) = (IDispatch*)xhr;
1057 return S_OK;
1060 static const dispex_static_data_vtbl_t HTMLXMLHttpRequestFactory_dispex_vtbl = {
1061 HTMLXMLHttpRequestFactory_value
1064 static const tid_t HTMLXMLHttpRequestFactory_iface_tids[] = {
1065 IHTMLXMLHttpRequestFactory_tid,
1068 static dispex_static_data_t HTMLXMLHttpRequestFactory_dispex = {
1069 L"Function",
1070 &HTMLXMLHttpRequestFactory_dispex_vtbl,
1071 IHTMLXMLHttpRequestFactory_tid,
1072 HTMLXMLHttpRequestFactory_iface_tids
1075 HRESULT HTMLXMLHttpRequestFactory_Create(HTMLInnerWindow* window, HTMLXMLHttpRequestFactory **ret_ptr)
1077 HTMLXMLHttpRequestFactory *ret;
1079 ret = heap_alloc(sizeof(*ret));
1080 if(!ret)
1081 return E_OUTOFMEMORY;
1083 ret->IHTMLXMLHttpRequestFactory_iface.lpVtbl = &HTMLXMLHttpRequestFactoryVtbl;
1084 ret->ref = 1;
1085 ret->window = window;
1087 init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLXMLHttpRequestFactory_iface,
1088 &HTMLXMLHttpRequestFactory_dispex, dispex_compat_mode(&window->event_target.dispex));
1090 *ret_ptr = ret;
1091 return S_OK;