2 * IXMLHTTPRequest implementation
4 * Copyright 2008 Alistair Leslie-Hughes
5 * Copyright 2010 Nikolay Sivov for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define NONAMELESSUNION
35 #include "msxml_private.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
44 #include <libxml/encoding.h>
46 static const WCHAR MethodGetW[] = {'G','E','T',0};
47 static const WCHAR MethodPutW[] = {'P','U','T',0};
48 static const WCHAR MethodPostW[] = {'P','O','S','T',0};
50 static const WCHAR colspaceW[] = {':',' ',0};
51 static const WCHAR crlfW[] = {'\r','\n',0};
53 typedef struct BindStatusCallback BindStatusCallback;
64 IXMLHTTPRequest IXMLHTTPRequest_iface;
65 IObjectWithSite IObjectWithSite_iface;
66 IObjectSafety IObjectSafety_iface;
76 struct list reqheaders;
77 /* cached resulting custom request headers string length in WCHARs */
85 BindStatusCallback *bsc;
95 static inline httprequest *impl_from_IXMLHTTPRequest( IXMLHTTPRequest *iface )
97 return CONTAINING_RECORD(iface, httprequest, IXMLHTTPRequest_iface);
100 static inline httprequest *impl_from_IObjectWithSite(IObjectWithSite *iface)
102 return CONTAINING_RECORD(iface, httprequest, IObjectWithSite_iface);
105 static inline httprequest *impl_from_IObjectSafety(IObjectSafety *iface)
107 return CONTAINING_RECORD(iface, httprequest, IObjectSafety_iface);
110 static void httprequest_setreadystate(httprequest *This, READYSTATE state)
112 READYSTATE last = This->state;
116 if (This->sink && last != state)
120 memset(¶ms, 0, sizeof(params));
121 IDispatch_Invoke(This->sink, 0, &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, ¶ms, 0, 0, 0);
125 struct BindStatusCallback
127 IBindStatusCallback IBindStatusCallback_iface;
128 IHttpNegotiate IHttpNegotiate_iface;
132 httprequest *request;
137 /* request body data */
141 static inline BindStatusCallback *impl_from_IBindStatusCallback( IBindStatusCallback *iface )
143 return CONTAINING_RECORD(iface, BindStatusCallback, IBindStatusCallback_iface);
146 static inline BindStatusCallback *impl_from_IHttpNegotiate( IHttpNegotiate *iface )
148 return CONTAINING_RECORD(iface, BindStatusCallback, IHttpNegotiate_iface);
151 void BindStatusCallback_Detach(BindStatusCallback *bsc)
155 if (bsc->binding) IBinding_Abort(bsc->binding);
157 IBindStatusCallback_Release(&bsc->IBindStatusCallback_iface);
161 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
162 REFIID riid, void **ppv)
164 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
168 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
170 if (IsEqualGUID(&IID_IUnknown, riid) ||
171 IsEqualGUID(&IID_IBindStatusCallback, riid))
173 *ppv = &This->IBindStatusCallback_iface;
175 else if (IsEqualGUID(&IID_IHttpNegotiate, riid))
177 *ppv = &This->IHttpNegotiate_iface;
179 else if (IsEqualGUID(&IID_IServiceProvider, riid) ||
180 IsEqualGUID(&IID_IBindStatusCallbackEx, riid) ||
181 IsEqualGUID(&IID_IInternetProtocol, riid) ||
182 IsEqualGUID(&IID_IHttpNegotiate2, riid))
184 return E_NOINTERFACE;
189 IBindStatusCallback_AddRef(iface);
193 FIXME("Unsupported riid = %s\n", debugstr_guid(riid));
195 return E_NOINTERFACE;
198 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
200 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
201 LONG ref = InterlockedIncrement(&This->ref);
203 TRACE("(%p) ref = %d\n", This, ref);
208 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
210 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
211 LONG ref = InterlockedDecrement(&This->ref);
213 TRACE("(%p) ref = %d\n", This, ref);
217 if (This->binding) IBinding_Release(This->binding);
218 if (This->stream) IStream_Release(This->stream);
219 if (This->body) GlobalFree(This->body);
226 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
227 DWORD reserved, IBinding *pbind)
229 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
231 TRACE("(%p)->(%d %p)\n", This, reserved, pbind);
233 if (!pbind) return E_INVALIDARG;
235 This->binding = pbind;
236 IBinding_AddRef(pbind);
238 httprequest_setreadystate(This->request, READYSTATE_LOADED);
240 return CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
243 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pPriority)
245 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
247 TRACE("(%p)->(%p)\n", This, pPriority);
252 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
254 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
256 TRACE("(%p)->(%d)\n", This, reserved);
261 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
262 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
264 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
266 TRACE("(%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
267 debugstr_w(szStatusText));
272 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
273 HRESULT hr, LPCWSTR error)
275 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
277 TRACE("(%p)->(0x%08x %s)\n", This, hr, debugstr_w(error));
281 IBinding_Release(This->binding);
282 This->binding = NULL;
286 httprequest_setreadystate(This->request, READYSTATE_COMPLETE);
291 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
292 DWORD *bind_flags, BINDINFO *pbindinfo)
294 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
296 TRACE("(%p)->(%p %p)\n", This, bind_flags, pbindinfo);
299 if (This->request->async) *bind_flags |= BINDF_ASYNCHRONOUS;
301 if (This->request->verb != BINDVERB_GET && This->body)
303 pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
304 pbindinfo->stgmedData.u.hGlobal = This->body;
305 pbindinfo->cbstgmedData = GlobalSize(This->body);
306 /* callback owns passed body pointer */
307 IBindStatusCallback_QueryInterface(iface, &IID_IUnknown, (void**)&pbindinfo->stgmedData.pUnkForRelease);
310 pbindinfo->dwBindVerb = This->request->verb;
315 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
316 DWORD flags, DWORD size, FORMATETC *format, STGMEDIUM *stgmed)
318 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
323 TRACE("(%p)->(%08x %d %p %p)\n", This, flags, size, format, stgmed);
327 hr = IStream_Read(stgmed->u.pstm, buf, sizeof(buf), &read);
328 if (hr != S_OK) break;
330 hr = IStream_Write(This->stream, buf, read, &written);
331 } while((hr == S_OK) && written != 0 && read != 0);
333 httprequest_setreadystate(This->request, READYSTATE_INTERACTIVE);
338 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
339 REFIID riid, IUnknown *punk)
341 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
343 FIXME("(%p)->(%s %p): stub\n", This, debugstr_guid(riid), punk);
348 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
349 BindStatusCallback_QueryInterface,
350 BindStatusCallback_AddRef,
351 BindStatusCallback_Release,
352 BindStatusCallback_OnStartBinding,
353 BindStatusCallback_GetPriority,
354 BindStatusCallback_OnLowResource,
355 BindStatusCallback_OnProgress,
356 BindStatusCallback_OnStopBinding,
357 BindStatusCallback_GetBindInfo,
358 BindStatusCallback_OnDataAvailable,
359 BindStatusCallback_OnObjectAvailable
362 static HRESULT WINAPI BSCHttpNegotiate_QueryInterface(IHttpNegotiate *iface,
363 REFIID riid, void **ppv)
365 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
366 return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
369 static ULONG WINAPI BSCHttpNegotiate_AddRef(IHttpNegotiate *iface)
371 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
372 return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
375 static ULONG WINAPI BSCHttpNegotiate_Release(IHttpNegotiate *iface)
377 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
378 return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
381 static HRESULT WINAPI BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate *iface,
382 LPCWSTR url, LPCWSTR headers, DWORD reserved, LPWSTR *add_headers)
384 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
385 const struct reqheader *entry;
388 TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(url), debugstr_w(headers), reserved, add_headers);
392 if (list_empty(&This->request->reqheaders)) return S_OK;
394 buff = CoTaskMemAlloc(This->request->reqheader_size*sizeof(WCHAR));
395 if (!buff) return E_OUTOFMEMORY;
398 LIST_FOR_EACH_ENTRY(entry, &This->request->reqheaders, struct reqheader, entry)
400 lstrcpyW(ptr, entry->header);
401 ptr += SysStringLen(entry->header);
403 lstrcpyW(ptr, colspaceW);
404 ptr += sizeof(colspaceW)/sizeof(WCHAR)-1;
406 lstrcpyW(ptr, entry->value);
407 ptr += SysStringLen(entry->value);
409 lstrcpyW(ptr, crlfW);
410 ptr += sizeof(crlfW)/sizeof(WCHAR)-1;
418 static HRESULT WINAPI BSCHttpNegotiate_OnResponse(IHttpNegotiate *iface, DWORD code,
419 LPCWSTR resp_headers, LPCWSTR req_headers, LPWSTR *add_reqheaders)
421 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
423 TRACE("(%p)->(%d %s %s %p)\n", This, code, debugstr_w(resp_headers),
424 debugstr_w(req_headers), add_reqheaders);
426 This->request->status = code;
431 static const IHttpNegotiateVtbl BSCHttpNegotiateVtbl = {
432 BSCHttpNegotiate_QueryInterface,
433 BSCHttpNegotiate_AddRef,
434 BSCHttpNegotiate_Release,
435 BSCHttpNegotiate_BeginningTransaction,
436 BSCHttpNegotiate_OnResponse
439 static HRESULT BindStatusCallback_create(httprequest* This, BindStatusCallback **obj, const VARIANT *body)
441 BindStatusCallback *bsc;
445 hr = CreateBindCtx(0, &pbc);
446 if (hr != S_OK) return hr;
448 bsc = heap_alloc(sizeof(*bsc));
451 IBindCtx_Release(pbc);
452 return E_OUTOFMEMORY;
455 bsc->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl;
456 bsc->IHttpNegotiate_iface.lpVtbl = &BSCHttpNegotiateVtbl;
463 TRACE("created callback %p\n", bsc);
465 if (This->verb != BINDVERB_GET)
467 if (V_VT(body) == VT_BSTR)
469 LONG size = SysStringLen(V_BSTR(body)) * sizeof(WCHAR);
472 bsc->body = GlobalAlloc(GMEM_FIXED, size);
476 return E_OUTOFMEMORY;
479 ptr = GlobalLock(bsc->body);
480 memcpy(ptr, V_BSTR(body), size);
481 GlobalUnlock(bsc->body);
484 FIXME("unsupported body data type %d\n", V_VT(body));
487 hr = RegisterBindStatusCallback(pbc, &bsc->IBindStatusCallback_iface, NULL, 0);
492 hr = CreateURLMoniker(NULL, This->url, &moniker);
497 hr = IMoniker_BindToStorage(moniker, pbc, NULL, &IID_IStream, (void**)&stream);
498 IMoniker_Release(moniker);
499 if (stream) IStream_Release(stream);
501 IBindCtx_Release(pbc);
506 IBindStatusCallback_Release(&bsc->IBindStatusCallback_iface);
514 static HRESULT WINAPI httprequest_QueryInterface(IXMLHTTPRequest *iface, REFIID riid, void **ppvObject)
516 httprequest *This = impl_from_IXMLHTTPRequest( iface );
517 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
519 if ( IsEqualGUID( riid, &IID_IXMLHTTPRequest) ||
520 IsEqualGUID( riid, &IID_IDispatch) ||
521 IsEqualGUID( riid, &IID_IUnknown) )
525 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
527 *ppvObject = &This->IObjectWithSite_iface;
529 else if (IsEqualGUID(&IID_IObjectSafety, riid))
531 *ppvObject = &This->IObjectSafety_iface;
535 TRACE("Unsupported interface %s\n", debugstr_guid(riid));
537 return E_NOINTERFACE;
540 IXMLHTTPRequest_AddRef( iface );
545 static ULONG WINAPI httprequest_AddRef(IXMLHTTPRequest *iface)
547 httprequest *This = impl_from_IXMLHTTPRequest( iface );
548 ULONG ref = InterlockedIncrement( &This->ref );
549 TRACE("(%p)->(%u)\n", This, ref );
553 static ULONG WINAPI httprequest_Release(IXMLHTTPRequest *iface)
555 httprequest *This = impl_from_IXMLHTTPRequest( iface );
556 ULONG ref = InterlockedDecrement( &This->ref );
558 TRACE("(%p)->(%u)\n", This, ref );
562 struct reqheader *header, *header2;
565 IUnknown_Release( This->site );
567 SysFreeString(This->url);
568 SysFreeString(This->user);
569 SysFreeString(This->password);
571 /* request headers */
572 LIST_FOR_EACH_ENTRY_SAFE(header, header2, &This->reqheaders, struct reqheader, entry)
574 list_remove(&header->entry);
575 SysFreeString(header->header);
576 SysFreeString(header->value);
580 /* detach callback object */
581 BindStatusCallback_Detach(This->bsc);
583 if (This->sink) IDispatch_Release(This->sink);
591 static HRESULT WINAPI httprequest_GetTypeInfoCount(IXMLHTTPRequest *iface, UINT *pctinfo)
593 httprequest *This = impl_from_IXMLHTTPRequest( iface );
595 TRACE("(%p)->(%p)\n", This, pctinfo);
602 static HRESULT WINAPI httprequest_GetTypeInfo(IXMLHTTPRequest *iface, UINT iTInfo,
603 LCID lcid, ITypeInfo **ppTInfo)
605 httprequest *This = impl_from_IXMLHTTPRequest( iface );
608 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
610 hr = get_typeinfo(IXMLHTTPRequest_tid, ppTInfo);
615 static HRESULT WINAPI httprequest_GetIDsOfNames(IXMLHTTPRequest *iface, REFIID riid,
616 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
618 httprequest *This = impl_from_IXMLHTTPRequest( iface );
622 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
625 if(!rgszNames || cNames == 0 || !rgDispId)
628 hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
631 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
632 ITypeInfo_Release(typeinfo);
638 static HRESULT WINAPI httprequest_Invoke(IXMLHTTPRequest *iface, DISPID dispIdMember, REFIID riid,
639 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
640 EXCEPINFO *pExcepInfo, UINT *puArgErr)
642 httprequest *This = impl_from_IXMLHTTPRequest( iface );
646 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
647 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
649 hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
652 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLHTTPRequest_iface, dispIdMember, wFlags,
653 pDispParams, pVarResult, pExcepInfo, puArgErr);
654 ITypeInfo_Release(typeinfo);
660 static HRESULT WINAPI httprequest_open(IXMLHTTPRequest *iface, BSTR method, BSTR url,
661 VARIANT async, VARIANT user, VARIANT password)
663 httprequest *This = impl_from_IXMLHTTPRequest( iface );
667 TRACE("(%p)->(%s %s %s)\n", This, debugstr_w(method), debugstr_w(url),
668 debugstr_variant(&async));
670 if (!method || !url) return E_INVALIDARG;
672 /* free previously set data */
673 SysFreeString(This->url);
674 SysFreeString(This->user);
675 SysFreeString(This->password);
676 This->url = This->user = This->password = NULL;
678 if (lstrcmpiW(method, MethodGetW) == 0)
680 This->verb = BINDVERB_GET;
682 else if (lstrcmpiW(method, MethodPutW) == 0)
684 This->verb = BINDVERB_PUT;
686 else if (lstrcmpiW(method, MethodPostW) == 0)
688 This->verb = BINDVERB_POST;
692 FIXME("unsupported request type %s\n", debugstr_w(method));
697 This->url = SysAllocString(url);
699 hr = VariantChangeType(&async, &async, 0, VT_BOOL);
700 This->async = hr == S_OK && V_BOOL(&async) == VARIANT_TRUE;
703 hr = VariantChangeType(&str, &user, 0, VT_BSTR);
705 This->user = V_BSTR(&str);
707 hr = VariantChangeType(&str, &password, 0, VT_BSTR);
709 This->password = V_BSTR(&str);
711 httprequest_setreadystate(This, READYSTATE_LOADING);
716 static HRESULT WINAPI httprequest_setRequestHeader(IXMLHTTPRequest *iface, BSTR header, BSTR value)
718 httprequest *This = impl_from_IXMLHTTPRequest( iface );
719 struct reqheader *entry;
721 TRACE("(%p)->(%s %s)\n", This, debugstr_w(header), debugstr_w(value));
723 if (!header || !*header) return E_INVALIDARG;
724 if (This->state != READYSTATE_LOADING) return E_FAIL;
725 if (!value) return E_INVALIDARG;
727 /* replace existing header value if already added */
728 LIST_FOR_EACH_ENTRY(entry, &This->reqheaders, struct reqheader, entry)
730 if (lstrcmpW(entry->header, header) == 0)
732 LONG length = SysStringLen(entry->value);
735 hr = SysReAllocString(&entry->value, value) ? S_OK : E_OUTOFMEMORY;
738 This->reqheader_size += (SysStringLen(entry->value) - length);
744 entry = heap_alloc(sizeof(*entry));
745 if (!entry) return E_OUTOFMEMORY;
748 entry->header = SysAllocString(header);
749 entry->value = SysAllocString(value);
751 /* header length including null terminator */
752 This->reqheader_size += SysStringLen(entry->header) + sizeof(colspaceW)/sizeof(WCHAR) +
753 SysStringLen(entry->value) + sizeof(crlfW)/sizeof(WCHAR) - 1;
755 list_add_head(&This->reqheaders, &entry->entry);
760 static HRESULT WINAPI httprequest_getResponseHeader(IXMLHTTPRequest *iface, BSTR bstrHeader, BSTR *pbstrValue)
762 httprequest *This = impl_from_IXMLHTTPRequest( iface );
764 FIXME("stub (%p) %s %p\n", This, debugstr_w(bstrHeader), pbstrValue);
769 static HRESULT WINAPI httprequest_getAllResponseHeaders(IXMLHTTPRequest *iface, BSTR *pbstrHeaders)
771 httprequest *This = impl_from_IXMLHTTPRequest( iface );
773 FIXME("stub (%p) %p\n", This, pbstrHeaders);
778 static HRESULT WINAPI httprequest_send(IXMLHTTPRequest *iface, VARIANT body)
780 httprequest *This = impl_from_IXMLHTTPRequest( iface );
781 BindStatusCallback *bsc = NULL;
784 TRACE("(%p)->(%s)\n", This, debugstr_variant(&body));
786 if (This->state != READYSTATE_LOADING) return E_FAIL;
788 hr = BindStatusCallback_create(This, &bsc, &body);
789 if (FAILED(hr)) return hr;
791 BindStatusCallback_Detach(This->bsc);
797 static HRESULT WINAPI httprequest_abort(IXMLHTTPRequest *iface)
799 httprequest *This = impl_from_IXMLHTTPRequest( iface );
801 TRACE("(%p)\n", This);
803 BindStatusCallback_Detach(This->bsc);
806 httprequest_setreadystate(This, READYSTATE_UNINITIALIZED);
811 static HRESULT WINAPI httprequest_get_status(IXMLHTTPRequest *iface, LONG *status)
813 httprequest *This = impl_from_IXMLHTTPRequest( iface );
815 TRACE("(%p)->(%p)\n", This, status);
817 if (!status) return E_INVALIDARG;
818 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
820 *status = This->status;
825 static HRESULT WINAPI httprequest_get_statusText(IXMLHTTPRequest *iface, BSTR *pbstrStatus)
827 httprequest *This = impl_from_IXMLHTTPRequest( iface );
829 FIXME("stub %p %p\n", This, pbstrStatus);
834 static HRESULT WINAPI httprequest_get_responseXML(IXMLHTTPRequest *iface, IDispatch **body)
836 httprequest *This = impl_from_IXMLHTTPRequest( iface );
837 IXMLDOMDocument3 *doc;
841 TRACE("(%p)->(%p)\n", This, body);
843 if (!body) return E_INVALIDARG;
844 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
846 hr = DOMDocument_create(&CLSID_DOMDocument, NULL, (void**)&doc);
847 if (hr != S_OK) return hr;
849 hr = IXMLHTTPRequest_get_responseText(iface, &str);
854 hr = IXMLDOMDocument3_loadXML(doc, str, &ok);
858 IXMLDOMDocument3_QueryInterface(doc, &IID_IDispatch, (void**)body);
859 IXMLDOMDocument3_Release(doc);
864 static HRESULT WINAPI httprequest_get_responseText(IXMLHTTPRequest *iface, BSTR *body)
866 httprequest *This = impl_from_IXMLHTTPRequest( iface );
870 TRACE("(%p)->(%p)\n", This, body);
872 if (!body) return E_INVALIDARG;
873 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
875 hr = GetHGlobalFromStream(This->bsc->stream, &hglobal);
878 xmlChar *ptr = GlobalLock(hglobal);
879 DWORD size = GlobalSize(hglobal);
880 xmlCharEncoding encoding = XML_CHAR_ENCODING_UTF8;
882 /* try to determine data encoding */
885 encoding = xmlDetectCharEncoding(ptr, 4);
886 TRACE("detected encoding: %s\n", xmlGetCharEncodingName(encoding));
887 if ( encoding != XML_CHAR_ENCODING_UTF8 &&
888 encoding != XML_CHAR_ENCODING_UTF16LE &&
889 encoding != XML_CHAR_ENCODING_NONE )
891 FIXME("unsupported encoding: %s\n", xmlGetCharEncodingName(encoding));
892 GlobalUnlock(hglobal);
897 /* without BOM assume UTF-8 */
898 if (encoding == XML_CHAR_ENCODING_UTF8 ||
899 encoding == XML_CHAR_ENCODING_NONE )
901 DWORD length = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)ptr, size, NULL, 0);
903 *body = SysAllocStringLen(NULL, length);
905 MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)ptr, size, *body, length);
908 *body = SysAllocStringByteLen((LPCSTR)ptr, size);
910 if (!*body) hr = E_OUTOFMEMORY;
911 GlobalUnlock(hglobal);
917 static HRESULT WINAPI httprequest_get_responseBody(IXMLHTTPRequest *iface, VARIANT *body)
919 httprequest *This = impl_from_IXMLHTTPRequest( iface );
923 TRACE("(%p)->(%p)\n", This, body);
925 if (!body) return E_INVALIDARG;
926 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
928 hr = GetHGlobalFromStream(This->bsc->stream, &hglobal);
931 void *ptr = GlobalLock(hglobal);
932 DWORD size = GlobalSize(hglobal);
934 SAFEARRAYBOUND bound;
938 bound.cElements = size;
939 array = SafeArrayCreate(VT_UI1, 1, &bound);
945 V_VT(body) = VT_ARRAY | VT_UI1;
946 V_ARRAY(body) = array;
948 hr = SafeArrayAccessData(array, &dest);
951 memcpy(dest, ptr, size);
952 SafeArrayUnaccessData(array);
962 GlobalUnlock(hglobal);
968 static HRESULT WINAPI httprequest_get_responseStream(IXMLHTTPRequest *iface, VARIANT *pvarBody)
970 httprequest *This = impl_from_IXMLHTTPRequest( iface );
972 FIXME("stub %p %p\n", This, pvarBody);
977 static HRESULT WINAPI httprequest_get_readyState(IXMLHTTPRequest *iface, LONG *state)
979 httprequest *This = impl_from_IXMLHTTPRequest( iface );
981 TRACE("(%p)->(%p)\n", This, state);
983 if (!state) return E_INVALIDARG;
985 *state = This->state;
989 static HRESULT WINAPI httprequest_put_onreadystatechange(IXMLHTTPRequest *iface, IDispatch *sink)
991 httprequest *This = impl_from_IXMLHTTPRequest( iface );
993 TRACE("(%p)->(%p)\n", This, sink);
995 if (This->sink) IDispatch_Release(This->sink);
996 if ((This->sink = sink)) IDispatch_AddRef(This->sink);
1001 static const struct IXMLHTTPRequestVtbl dimimpl_vtbl =
1003 httprequest_QueryInterface,
1005 httprequest_Release,
1006 httprequest_GetTypeInfoCount,
1007 httprequest_GetTypeInfo,
1008 httprequest_GetIDsOfNames,
1011 httprequest_setRequestHeader,
1012 httprequest_getResponseHeader,
1013 httprequest_getAllResponseHeaders,
1016 httprequest_get_status,
1017 httprequest_get_statusText,
1018 httprequest_get_responseXML,
1019 httprequest_get_responseText,
1020 httprequest_get_responseBody,
1021 httprequest_get_responseStream,
1022 httprequest_get_readyState,
1023 httprequest_put_onreadystatechange
1026 /* IObjectWithSite */
1027 static HRESULT WINAPI
1028 httprequest_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
1030 httprequest *This = impl_from_IObjectWithSite(iface);
1031 return IXMLHTTPRequest_QueryInterface( (IXMLHTTPRequest *)This, riid, ppvObject );
1034 static ULONG WINAPI httprequest_ObjectWithSite_AddRef( IObjectWithSite* iface )
1036 httprequest *This = impl_from_IObjectWithSite(iface);
1037 return IXMLHTTPRequest_AddRef((IXMLHTTPRequest *)This);
1040 static ULONG WINAPI httprequest_ObjectWithSite_Release( IObjectWithSite* iface )
1042 httprequest *This = impl_from_IObjectWithSite(iface);
1043 return IXMLHTTPRequest_Release((IXMLHTTPRequest *)This);
1046 static HRESULT WINAPI httprequest_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
1048 httprequest *This = impl_from_IObjectWithSite(iface);
1050 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
1055 return IUnknown_QueryInterface( This->site, iid, ppvSite );
1058 static HRESULT WINAPI httprequest_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
1060 httprequest *This = impl_from_IObjectWithSite(iface);
1062 TRACE("(%p)->(%p)\n", iface, punk);
1065 IUnknown_AddRef( punk );
1068 IUnknown_Release( This->site );
1075 static const IObjectWithSiteVtbl httprequestObjectSite =
1077 httprequest_ObjectWithSite_QueryInterface,
1078 httprequest_ObjectWithSite_AddRef,
1079 httprequest_ObjectWithSite_Release,
1080 httprequest_ObjectWithSite_SetSite,
1081 httprequest_ObjectWithSite_GetSite
1085 static HRESULT WINAPI httprequest_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
1087 httprequest *This = impl_from_IObjectSafety(iface);
1088 return IXMLHTTPRequest_QueryInterface( (IXMLHTTPRequest *)This, riid, ppv );
1091 static ULONG WINAPI httprequest_Safety_AddRef(IObjectSafety *iface)
1093 httprequest *This = impl_from_IObjectSafety(iface);
1094 return IXMLHTTPRequest_AddRef((IXMLHTTPRequest *)This);
1097 static ULONG WINAPI httprequest_Safety_Release(IObjectSafety *iface)
1099 httprequest *This = impl_from_IObjectSafety(iface);
1100 return IXMLHTTPRequest_Release((IXMLHTTPRequest *)This);
1103 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
1105 static HRESULT WINAPI httprequest_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
1106 DWORD *supported, DWORD *enabled)
1108 httprequest *This = impl_from_IObjectSafety(iface);
1110 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
1112 if(!supported || !enabled) return E_POINTER;
1114 *supported = SAFETY_SUPPORTED_OPTIONS;
1115 *enabled = This->safeopt;
1120 static HRESULT WINAPI httprequest_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
1121 DWORD mask, DWORD enabled)
1123 httprequest *This = impl_from_IObjectSafety(iface);
1124 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
1126 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
1129 This->safeopt = enabled & mask & SAFETY_SUPPORTED_OPTIONS;
1133 #undef SAFETY_SUPPORTED_OPTIONS
1135 static const IObjectSafetyVtbl httprequestObjectSafety = {
1136 httprequest_Safety_QueryInterface,
1137 httprequest_Safety_AddRef,
1138 httprequest_Safety_Release,
1139 httprequest_Safety_GetInterfaceSafetyOptions,
1140 httprequest_Safety_SetInterfaceSafetyOptions
1143 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
1148 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
1150 req = heap_alloc( sizeof (*req) );
1152 return E_OUTOFMEMORY;
1154 req->IXMLHTTPRequest_iface.lpVtbl = &dimimpl_vtbl;
1155 req->IObjectWithSite_iface.lpVtbl = &httprequestObjectSite;
1156 req->IObjectSafety_iface.lpVtbl = &httprequestObjectSafety;
1161 req->url = req->user = req->password = NULL;
1163 req->state = READYSTATE_UNINITIALIZED;
1168 req->reqheader_size = 0;
1169 list_init(&req->reqheaders);
1173 *ppObj = &req->IXMLHTTPRequest_iface;
1175 TRACE("returning iface %p\n", *ppObj);
1182 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
1184 MESSAGE("This program tried to use a XMLHTTPRequest object, but\n"
1185 "libxml2 support was not present at compile time.\n");