msxml3: Fix response text conversion to WCHAR string.
[wine.git] / dlls / msxml3 / httprequest.c
blobb01601681ddda83447aec105fffcd2af6424fa97
1 /*
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
22 #define COBJMACROS
23 #define NONAMELESSUNION
25 #include "config.h"
27 #include <stdarg.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "ole2.h"
32 #include "msxml6.h"
34 #include "msxml_private.h"
36 #include "wine/debug.h"
37 #include "wine/list.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
41 #ifdef HAVE_LIBXML2
43 #include <libxml/encoding.h>
45 static const WCHAR MethodGetW[] = {'G','E','T',0};
46 static const WCHAR MethodPutW[] = {'P','U','T',0};
47 static const WCHAR MethodPostW[] = {'P','O','S','T',0};
49 static const WCHAR colspaceW[] = {':',' ',0};
50 static const WCHAR crlfW[] = {'\r','\n',0};
52 typedef struct BindStatusCallback BindStatusCallback;
54 struct reqheader
56 struct list entry;
57 BSTR header;
58 BSTR value;
61 typedef struct
63 const struct IXMLHTTPRequestVtbl *lpVtbl;
64 LONG ref;
66 READYSTATE state;
67 IDispatch *sink;
69 /* request */
70 BINDVERB verb;
71 BSTR url;
72 BOOL async;
73 struct list reqheaders;
74 /* cached resulting custom request headers string length in WCHARs */
75 LONG reqheader_size;
77 /* credentials */
78 BSTR user;
79 BSTR password;
81 /* bind callback */
82 BindStatusCallback *bsc;
83 LONG status;
84 } httprequest;
86 static inline httprequest *impl_from_IXMLHTTPRequest( IXMLHTTPRequest *iface )
88 return (httprequest *)((char*)iface - FIELD_OFFSET(httprequest, lpVtbl));
91 static void httprequest_setreadystate(httprequest *This, READYSTATE state)
93 READYSTATE last = This->state;
95 This->state = state;
97 if (This->sink && last != state)
99 DISPPARAMS params;
101 memset(&params, 0, sizeof(params));
102 IDispatch_Invoke(This->sink, 0, &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &params, 0, 0, 0);
106 struct BindStatusCallback
108 const IBindStatusCallbackVtbl *lpBindStatusCallbackVtbl;
109 const IHttpNegotiateVtbl *lpHttpNegotiateVtbl;
110 LONG ref;
112 IBinding *binding;
113 httprequest *request;
115 /* response data */
116 IStream *stream;
118 /* request body data */
119 HGLOBAL body;
122 static inline BindStatusCallback *impl_from_IBindStatusCallback( IBindStatusCallback *iface )
124 return (BindStatusCallback *)((char*)iface - FIELD_OFFSET(BindStatusCallback, lpBindStatusCallbackVtbl));
127 static inline BindStatusCallback *impl_from_IHttpNegotiate( IHttpNegotiate *iface )
129 return (BindStatusCallback *)((char*)iface - FIELD_OFFSET(BindStatusCallback, lpHttpNegotiateVtbl));
132 void BindStatusCallback_Detach(BindStatusCallback *bsc)
134 if (bsc)
136 if (bsc->binding) IBinding_Abort(bsc->binding);
137 bsc->request = NULL;
138 IBindStatusCallback_Release((IBindStatusCallback*)bsc);
142 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
143 REFIID riid, void **ppv)
145 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
147 *ppv = NULL;
149 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
151 if (IsEqualGUID(&IID_IUnknown, riid) ||
152 IsEqualGUID(&IID_IBindStatusCallback, riid))
154 *ppv = &This->lpBindStatusCallbackVtbl;
156 else if (IsEqualGUID(&IID_IHttpNegotiate, riid))
158 *ppv = &This->lpHttpNegotiateVtbl;
160 else if (IsEqualGUID(&IID_IServiceProvider, riid) ||
161 IsEqualGUID(&IID_IBindStatusCallbackEx, riid) ||
162 IsEqualGUID(&IID_IInternetProtocol, riid) ||
163 IsEqualGUID(&IID_IHttpNegotiate2, riid))
165 return E_NOINTERFACE;
168 if (*ppv)
170 IBindStatusCallback_AddRef(iface);
171 return S_OK;
174 FIXME("Unsupported riid = %s\n", debugstr_guid(riid));
176 return E_NOINTERFACE;
179 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
181 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
182 LONG ref = InterlockedIncrement(&This->ref);
184 TRACE("(%p) ref = %d\n", This, ref);
186 return ref;
189 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
191 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
192 LONG ref = InterlockedDecrement(&This->ref);
194 TRACE("(%p) ref = %d\n", This, ref);
196 if (!ref)
198 if (This->binding) IBinding_Release(This->binding);
199 if (This->stream) IStream_Release(This->stream);
200 if (This->body) GlobalFree(This->body);
201 heap_free(This);
204 return ref;
207 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
208 DWORD reserved, IBinding *pbind)
210 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
212 TRACE("(%p)->(%d %p)\n", This, reserved, pbind);
214 if (!pbind) return E_INVALIDARG;
216 This->binding = pbind;
217 IBinding_AddRef(pbind);
219 httprequest_setreadystate(This->request, READYSTATE_LOADED);
221 return CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
224 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pPriority)
226 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
228 TRACE("(%p)->(%p)\n", This, pPriority);
230 return E_NOTIMPL;
233 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
235 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
237 TRACE("(%p)->(%d)\n", This, reserved);
239 return E_NOTIMPL;
242 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
243 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
245 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
247 TRACE("(%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
248 debugstr_w(szStatusText));
250 return S_OK;
253 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
254 HRESULT hr, LPCWSTR error)
256 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
258 TRACE("(%p)->(0x%08x %s)\n", This, hr, debugstr_w(error));
260 if (This->binding)
262 IBinding_Release(This->binding);
263 This->binding = NULL;
266 if (hr == S_OK)
267 httprequest_setreadystate(This->request, READYSTATE_COMPLETE);
269 return S_OK;
272 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
273 DWORD *bind_flags, BINDINFO *pbindinfo)
275 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
277 TRACE("(%p)->(%p %p)\n", This, bind_flags, pbindinfo);
279 *bind_flags = 0;
280 if (This->request->async) *bind_flags |= BINDF_ASYNCHRONOUS;
282 if (This->request->verb != BINDVERB_GET && This->body)
284 pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
285 pbindinfo->stgmedData.u.hGlobal = This->body;
286 pbindinfo->cbstgmedData = GlobalSize(This->body);
287 /* callback owns passed body pointer */
288 IBindStatusCallback_QueryInterface(iface, &IID_IUnknown, (void**)&pbindinfo->stgmedData.pUnkForRelease);
291 pbindinfo->dwBindVerb = This->request->verb;
293 return S_OK;
296 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
297 DWORD flags, DWORD size, FORMATETC *format, STGMEDIUM *stgmed)
299 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
300 DWORD read, written;
301 BYTE buf[4096];
302 HRESULT hr;
304 TRACE("(%p)->(%08x %d %p %p)\n", This, flags, size, format, stgmed);
308 hr = IStream_Read(stgmed->u.pstm, buf, sizeof(buf), &read);
309 if (hr != S_OK) break;
311 hr = IStream_Write(This->stream, buf, read, &written);
312 } while((hr == S_OK) && written != 0 && read != 0);
314 httprequest_setreadystate(This->request, READYSTATE_INTERACTIVE);
316 return S_OK;
319 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
320 REFIID riid, IUnknown *punk)
322 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
324 FIXME("(%p)->(%s %p): stub\n", This, debugstr_guid(riid), punk);
326 return E_NOTIMPL;
329 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
330 BindStatusCallback_QueryInterface,
331 BindStatusCallback_AddRef,
332 BindStatusCallback_Release,
333 BindStatusCallback_OnStartBinding,
334 BindStatusCallback_GetPriority,
335 BindStatusCallback_OnLowResource,
336 BindStatusCallback_OnProgress,
337 BindStatusCallback_OnStopBinding,
338 BindStatusCallback_GetBindInfo,
339 BindStatusCallback_OnDataAvailable,
340 BindStatusCallback_OnObjectAvailable
343 static HRESULT WINAPI BSCHttpNegotiate_QueryInterface(IHttpNegotiate *iface,
344 REFIID riid, void **ppv)
346 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
347 return IBindStatusCallback_QueryInterface((IBindStatusCallback*)This, riid, ppv);
350 static ULONG WINAPI BSCHttpNegotiate_AddRef(IHttpNegotiate *iface)
352 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
353 return IBindStatusCallback_AddRef((IBindStatusCallback*)This);
356 static ULONG WINAPI BSCHttpNegotiate_Release(IHttpNegotiate *iface)
358 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
359 return IBindStatusCallback_Release((IBindStatusCallback*)This);
362 static HRESULT WINAPI BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate *iface,
363 LPCWSTR url, LPCWSTR headers, DWORD reserved, LPWSTR *add_headers)
365 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
366 const struct reqheader *entry;
367 WCHAR *buff, *ptr;
369 TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(url), debugstr_w(headers), reserved, add_headers);
371 *add_headers = NULL;
373 if (list_empty(&This->request->reqheaders)) return S_OK;
375 buff = CoTaskMemAlloc(This->request->reqheader_size*sizeof(WCHAR));
376 if (!buff) return E_OUTOFMEMORY;
378 ptr = buff;
379 LIST_FOR_EACH_ENTRY(entry, &This->request->reqheaders, struct reqheader, entry)
381 lstrcpyW(ptr, entry->header);
382 ptr += SysStringLen(entry->header);
384 lstrcpyW(ptr, colspaceW);
385 ptr += sizeof(colspaceW)/sizeof(WCHAR)-1;
387 lstrcpyW(ptr, entry->value);
388 ptr += SysStringLen(entry->value);
390 lstrcpyW(ptr, crlfW);
391 ptr += sizeof(crlfW)/sizeof(WCHAR)-1;
394 *add_headers = buff;
396 return S_OK;
399 static HRESULT WINAPI BSCHttpNegotiate_OnResponse(IHttpNegotiate *iface, DWORD code,
400 LPCWSTR resp_headers, LPCWSTR req_headers, LPWSTR *add_reqheaders)
402 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
404 TRACE("(%p)->(%d %s %s %p)\n", This, code, debugstr_w(resp_headers),
405 debugstr_w(req_headers), add_reqheaders);
407 This->request->status = code;
409 return S_OK;
412 static const IHttpNegotiateVtbl BSCHttpNegotiateVtbl = {
413 BSCHttpNegotiate_QueryInterface,
414 BSCHttpNegotiate_AddRef,
415 BSCHttpNegotiate_Release,
416 BSCHttpNegotiate_BeginningTransaction,
417 BSCHttpNegotiate_OnResponse
420 static HRESULT BindStatusCallback_create(httprequest* This, BindStatusCallback **obj, const VARIANT *body)
422 BindStatusCallback *bsc;
423 IBindCtx *pbc;
424 HRESULT hr;
426 hr = CreateBindCtx(0, &pbc);
427 if (hr != S_OK) return hr;
429 bsc = heap_alloc(sizeof(*bsc));
430 if (!bsc)
432 IBindCtx_Release(pbc);
433 return E_OUTOFMEMORY;
436 bsc->lpBindStatusCallbackVtbl = &BindStatusCallbackVtbl;
437 bsc->lpHttpNegotiateVtbl = &BSCHttpNegotiateVtbl;
438 bsc->ref = 1;
439 bsc->request = This;
440 bsc->binding = NULL;
441 bsc->stream = NULL;
442 bsc->body = NULL;
444 TRACE("created callback %p\n", bsc);
446 if (This->verb != BINDVERB_GET)
448 if (V_VT(body) == VT_BSTR)
450 LONG size = SysStringLen(V_BSTR(body)) * sizeof(WCHAR);
451 void *ptr;
453 bsc->body = GlobalAlloc(GMEM_FIXED, size);
454 if (!bsc->body)
456 heap_free(bsc);
457 return E_OUTOFMEMORY;
460 ptr = GlobalLock(bsc->body);
461 memcpy(ptr, V_BSTR(body), size);
462 GlobalUnlock(bsc->body);
464 else
465 FIXME("unsupported body data type %d\n", V_VT(body));
468 hr = RegisterBindStatusCallback(pbc, (IBindStatusCallback*)bsc, NULL, 0);
469 if (hr == S_OK)
471 IMoniker *moniker;
473 hr = CreateURLMoniker(NULL, This->url, &moniker);
474 if (hr == S_OK)
476 IStream *stream;
478 hr = IMoniker_BindToStorage(moniker, pbc, NULL, &IID_IStream, (void**)&stream);
479 IMoniker_Release(moniker);
480 if (stream) IStream_Release(stream);
482 IBindCtx_Release(pbc);
485 if (FAILED(hr))
487 IBindStatusCallback_Release((IBindStatusCallback*)bsc);
488 bsc = NULL;
491 *obj = bsc;
492 return hr;
495 static HRESULT WINAPI httprequest_QueryInterface(IXMLHTTPRequest *iface, REFIID riid, void **ppvObject)
497 httprequest *This = impl_from_IXMLHTTPRequest( iface );
498 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
500 if ( IsEqualGUID( riid, &IID_IXMLHTTPRequest) ||
501 IsEqualGUID( riid, &IID_IDispatch) ||
502 IsEqualGUID( riid, &IID_IUnknown) )
504 *ppvObject = iface;
506 else
508 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
509 return E_NOINTERFACE;
512 IXMLHTTPRequest_AddRef( iface );
514 return S_OK;
517 static ULONG WINAPI httprequest_AddRef(IXMLHTTPRequest *iface)
519 httprequest *This = impl_from_IXMLHTTPRequest( iface );
520 ULONG ref = InterlockedIncrement( &This->ref );
521 TRACE("(%p)->(%u)\n", This, ref );
522 return ref;
525 static ULONG WINAPI httprequest_Release(IXMLHTTPRequest *iface)
527 httprequest *This = impl_from_IXMLHTTPRequest( iface );
528 ULONG ref = InterlockedDecrement( &This->ref );
530 TRACE("(%p)->(%u)\n", This, ref );
532 if ( ref == 0 )
534 struct reqheader *header, *header2;
536 SysFreeString(This->url);
537 SysFreeString(This->user);
538 SysFreeString(This->password);
540 /* request headers */
541 LIST_FOR_EACH_ENTRY_SAFE(header, header2, &This->reqheaders, struct reqheader, entry)
543 list_remove(&header->entry);
544 SysFreeString(header->header);
545 SysFreeString(header->value);
548 /* detach callback object */
549 BindStatusCallback_Detach(This->bsc);
551 if (This->sink) IDispatch_Release(This->sink);
553 heap_free( This );
556 return ref;
559 static HRESULT WINAPI httprequest_GetTypeInfoCount(IXMLHTTPRequest *iface, UINT *pctinfo)
561 httprequest *This = impl_from_IXMLHTTPRequest( iface );
563 TRACE("(%p)->(%p)\n", This, pctinfo);
565 *pctinfo = 1;
567 return S_OK;
570 static HRESULT WINAPI httprequest_GetTypeInfo(IXMLHTTPRequest *iface, UINT iTInfo,
571 LCID lcid, ITypeInfo **ppTInfo)
573 httprequest *This = impl_from_IXMLHTTPRequest( iface );
574 HRESULT hr;
576 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
578 hr = get_typeinfo(IXMLHTTPRequest_tid, ppTInfo);
580 return hr;
583 static HRESULT WINAPI httprequest_GetIDsOfNames(IXMLHTTPRequest *iface, REFIID riid,
584 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
586 httprequest *This = impl_from_IXMLHTTPRequest( iface );
587 ITypeInfo *typeinfo;
588 HRESULT hr;
590 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
591 lcid, rgDispId);
593 if(!rgszNames || cNames == 0 || !rgDispId)
594 return E_INVALIDARG;
596 hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
597 if(SUCCEEDED(hr))
599 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
600 ITypeInfo_Release(typeinfo);
603 return hr;
606 static HRESULT WINAPI httprequest_Invoke(IXMLHTTPRequest *iface, DISPID dispIdMember, REFIID riid,
607 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
608 EXCEPINFO *pExcepInfo, UINT *puArgErr)
610 httprequest *This = impl_from_IXMLHTTPRequest( iface );
611 ITypeInfo *typeinfo;
612 HRESULT hr;
614 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
615 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
617 hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
618 if(SUCCEEDED(hr))
620 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
621 pVarResult, pExcepInfo, puArgErr);
622 ITypeInfo_Release(typeinfo);
625 return hr;
628 static HRESULT WINAPI httprequest_open(IXMLHTTPRequest *iface, BSTR method, BSTR url,
629 VARIANT async, VARIANT user, VARIANT password)
631 httprequest *This = impl_from_IXMLHTTPRequest( iface );
632 HRESULT hr;
633 VARIANT str;
635 TRACE("(%p)->(%s %s)\n", This, debugstr_w(method), debugstr_w(url));
637 if (!method || !url) return E_INVALIDARG;
639 /* free previously set data */
640 SysFreeString(This->url);
641 SysFreeString(This->user);
642 SysFreeString(This->password);
643 This->url = This->user = This->password = NULL;
645 if (lstrcmpiW(method, MethodGetW) == 0)
647 This->verb = BINDVERB_GET;
649 else if (lstrcmpiW(method, MethodPutW) == 0)
651 This->verb = BINDVERB_PUT;
653 else if (lstrcmpiW(method, MethodPostW) == 0)
655 This->verb = BINDVERB_POST;
657 else
659 FIXME("unsupported request type %s\n", debugstr_w(method));
660 This->verb = -1;
661 return E_FAIL;
664 This->url = SysAllocString(url);
666 hr = VariantChangeType(&async, &async, 0, VT_BOOL);
667 This->async = hr == S_OK && V_BOOL(&async) == VARIANT_TRUE;
669 VariantInit(&str);
670 hr = VariantChangeType(&str, &user, 0, VT_BSTR);
671 if (hr == S_OK)
672 This->user = V_BSTR(&str);
674 hr = VariantChangeType(&str, &password, 0, VT_BSTR);
675 if (hr == S_OK)
676 This->password = V_BSTR(&str);
678 httprequest_setreadystate(This, READYSTATE_LOADING);
680 return S_OK;
683 static HRESULT WINAPI httprequest_setRequestHeader(IXMLHTTPRequest *iface, BSTR header, BSTR value)
685 httprequest *This = impl_from_IXMLHTTPRequest( iface );
686 struct reqheader *entry;
688 TRACE("(%p)->(%s %s)\n", This, debugstr_w(header), debugstr_w(value));
690 if (!header || !*header) return E_INVALIDARG;
691 if (This->state != READYSTATE_LOADING) return E_FAIL;
692 if (!value) return E_INVALIDARG;
694 /* replace existing header value if already added */
695 LIST_FOR_EACH_ENTRY(entry, &This->reqheaders, struct reqheader, entry)
697 if (lstrcmpW(entry->header, header) == 0)
699 LONG length = SysStringLen(entry->value);
700 HRESULT hr;
702 hr = SysReAllocString(&entry->value, value) ? S_OK : E_OUTOFMEMORY;
704 if (hr == S_OK)
705 This->reqheader_size += (SysStringLen(entry->value) - length);
707 return hr;
711 entry = heap_alloc(sizeof(*entry));
712 if (!entry) return E_OUTOFMEMORY;
714 /* new header */
715 entry->header = SysAllocString(header);
716 entry->value = SysAllocString(value);
718 /* header length including null terminator */
719 This->reqheader_size += SysStringLen(entry->header) + sizeof(colspaceW)/sizeof(WCHAR) +
720 SysStringLen(entry->value) + sizeof(crlfW)/sizeof(WCHAR) - 1;
722 list_add_head(&This->reqheaders, &entry->entry);
724 return S_OK;
727 static HRESULT WINAPI httprequest_getResponseHeader(IXMLHTTPRequest *iface, BSTR bstrHeader, BSTR *pbstrValue)
729 httprequest *This = impl_from_IXMLHTTPRequest( iface );
731 FIXME("stub (%p) %s %p\n", This, debugstr_w(bstrHeader), pbstrValue);
733 return E_NOTIMPL;
736 static HRESULT WINAPI httprequest_getAllResponseHeaders(IXMLHTTPRequest *iface, BSTR *pbstrHeaders)
738 httprequest *This = impl_from_IXMLHTTPRequest( iface );
740 FIXME("stub (%p) %p\n", This, pbstrHeaders);
742 return E_NOTIMPL;
745 static HRESULT WINAPI httprequest_send(IXMLHTTPRequest *iface, VARIANT body)
747 httprequest *This = impl_from_IXMLHTTPRequest( iface );
748 BindStatusCallback *bsc = NULL;
749 HRESULT hr;
751 TRACE("(%p)\n", This);
753 if (This->state != READYSTATE_LOADING) return E_FAIL;
755 hr = BindStatusCallback_create(This, &bsc, &body);
756 if (FAILED(hr)) return hr;
758 BindStatusCallback_Detach(This->bsc);
759 This->bsc = bsc;
761 return hr;
764 static HRESULT WINAPI httprequest_abort(IXMLHTTPRequest *iface)
766 httprequest *This = impl_from_IXMLHTTPRequest( iface );
768 TRACE("(%p)\n", This);
770 BindStatusCallback_Detach(This->bsc);
771 This->bsc = NULL;
773 httprequest_setreadystate(This, READYSTATE_UNINITIALIZED);
775 return S_OK;
778 static HRESULT WINAPI httprequest_get_status(IXMLHTTPRequest *iface, LONG *status)
780 httprequest *This = impl_from_IXMLHTTPRequest( iface );
782 TRACE("(%p)->(%p)\n", This, status);
784 if (!status) return E_INVALIDARG;
785 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
787 *status = This->status;
789 return S_OK;
792 static HRESULT WINAPI httprequest_get_statusText(IXMLHTTPRequest *iface, BSTR *pbstrStatus)
794 httprequest *This = impl_from_IXMLHTTPRequest( iface );
796 FIXME("stub %p %p\n", This, pbstrStatus);
798 return E_NOTIMPL;
801 static HRESULT WINAPI httprequest_get_responseXML(IXMLHTTPRequest *iface, IDispatch **body)
803 httprequest *This = impl_from_IXMLHTTPRequest( iface );
804 IXMLDOMDocument3 *doc;
805 HRESULT hr;
806 BSTR str;
808 TRACE("(%p)->(%p)\n", This, body);
810 if (!body) return E_INVALIDARG;
811 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
813 hr = DOMDocument_create(&CLSID_DOMDocument, NULL, (void**)&doc);
814 if (hr != S_OK) return hr;
816 hr = IXMLHTTPRequest_get_responseText(iface, &str);
817 if (hr == S_OK)
819 VARIANT_BOOL ok;
821 hr = IXMLDOMDocument3_loadXML(doc, str, &ok);
822 SysFreeString(str);
825 IXMLDOMDocument3_QueryInterface(doc, &IID_IDispatch, (void**)body);
826 IXMLDOMDocument3_Release(doc);
828 return hr;
831 static HRESULT WINAPI httprequest_get_responseText(IXMLHTTPRequest *iface, BSTR *body)
833 httprequest *This = impl_from_IXMLHTTPRequest( iface );
834 HGLOBAL hglobal;
835 HRESULT hr;
837 TRACE("(%p)->(%p)\n", This, body);
839 if (!body) return E_INVALIDARG;
840 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
842 hr = GetHGlobalFromStream(This->bsc->stream, &hglobal);
843 if (hr == S_OK)
845 xmlChar *ptr = GlobalLock(hglobal);
846 DWORD size = GlobalSize(hglobal);
847 xmlCharEncoding encoding = XML_CHAR_ENCODING_UTF8;
849 /* try to determine data encoding */
850 if (size >= 4)
852 encoding = xmlDetectCharEncoding(ptr, 4);
853 TRACE("detected encoding: %s\n", xmlGetCharEncodingName(encoding));
854 if ( encoding != XML_CHAR_ENCODING_UTF8 &&
855 encoding != XML_CHAR_ENCODING_UTF16LE &&
856 encoding != XML_CHAR_ENCODING_NONE )
858 FIXME("unsupported encoding: %s\n", xmlGetCharEncodingName(encoding));
859 GlobalUnlock(hglobal);
860 return E_FAIL;
864 /* without BOM assume UTF-8 */
865 if (encoding == XML_CHAR_ENCODING_UTF8 ||
866 encoding == XML_CHAR_ENCODING_NONE )
868 DWORD length = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)ptr, size, NULL, 0);
870 *body = SysAllocStringLen(NULL, length);
871 if (*body)
872 MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)ptr, size, *body, length);
874 else
875 *body = SysAllocStringByteLen((LPCSTR)ptr, size);
877 if (!*body) hr = E_OUTOFMEMORY;
878 GlobalUnlock(hglobal);
881 return hr;
884 static HRESULT WINAPI httprequest_get_responseBody(IXMLHTTPRequest *iface, VARIANT *body)
886 httprequest *This = impl_from_IXMLHTTPRequest( iface );
887 HGLOBAL hglobal;
888 HRESULT hr;
890 TRACE("(%p)->(%p)\n", This, body);
892 if (!body) return E_INVALIDARG;
893 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
895 hr = GetHGlobalFromStream(This->bsc->stream, &hglobal);
896 if (hr == S_OK)
898 void *ptr = GlobalLock(hglobal);
899 DWORD size = GlobalSize(hglobal);
901 SAFEARRAYBOUND bound;
902 SAFEARRAY *array;
904 bound.lLbound = 0;
905 bound.cElements = size;
906 array = SafeArrayCreate(VT_UI1, 1, &bound);
908 if (array)
910 void *dest;
912 V_VT(body) = VT_ARRAY | VT_UI1;
913 V_ARRAY(body) = array;
915 hr = SafeArrayAccessData(array, &dest);
916 if (hr == S_OK)
918 memcpy(dest, ptr, size);
919 SafeArrayUnaccessData(array);
921 else
923 VariantClear(body);
926 else
927 hr = E_FAIL;
929 GlobalUnlock(hglobal);
932 return hr;
935 static HRESULT WINAPI httprequest_get_responseStream(IXMLHTTPRequest *iface, VARIANT *pvarBody)
937 httprequest *This = impl_from_IXMLHTTPRequest( iface );
939 FIXME("stub %p %p\n", This, pvarBody);
941 return E_NOTIMPL;
944 static HRESULT WINAPI httprequest_get_readyState(IXMLHTTPRequest *iface, LONG *state)
946 httprequest *This = impl_from_IXMLHTTPRequest( iface );
948 TRACE("(%p)->(%p)\n", This, state);
950 if (!state) return E_INVALIDARG;
952 *state = This->state;
953 return S_OK;
956 static HRESULT WINAPI httprequest_put_onreadystatechange(IXMLHTTPRequest *iface, IDispatch *sink)
958 httprequest *This = impl_from_IXMLHTTPRequest( iface );
960 TRACE("(%p)->(%p)\n", This, sink);
962 if (This->sink) IDispatch_Release(This->sink);
963 if ((This->sink = sink)) IDispatch_AddRef(This->sink);
965 return S_OK;
968 static const struct IXMLHTTPRequestVtbl dimimpl_vtbl =
970 httprequest_QueryInterface,
971 httprequest_AddRef,
972 httprequest_Release,
973 httprequest_GetTypeInfoCount,
974 httprequest_GetTypeInfo,
975 httprequest_GetIDsOfNames,
976 httprequest_Invoke,
977 httprequest_open,
978 httprequest_setRequestHeader,
979 httprequest_getResponseHeader,
980 httprequest_getAllResponseHeaders,
981 httprequest_send,
982 httprequest_abort,
983 httprequest_get_status,
984 httprequest_get_statusText,
985 httprequest_get_responseXML,
986 httprequest_get_responseText,
987 httprequest_get_responseBody,
988 httprequest_get_responseStream,
989 httprequest_get_readyState,
990 httprequest_put_onreadystatechange
993 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
995 httprequest *req;
996 HRESULT hr = S_OK;
998 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
1000 req = heap_alloc( sizeof (*req) );
1001 if( !req )
1002 return E_OUTOFMEMORY;
1004 req->lpVtbl = &dimimpl_vtbl;
1005 req->ref = 1;
1007 req->async = FALSE;
1008 req->verb = -1;
1009 req->url = req->user = req->password = NULL;
1011 req->state = READYSTATE_UNINITIALIZED;
1012 req->sink = NULL;
1014 req->bsc = NULL;
1015 req->status = 0;
1016 req->reqheader_size = 0;
1017 list_init(&req->reqheaders);
1019 *ppObj = &req->lpVtbl;
1021 TRACE("returning iface %p\n", *ppObj);
1023 return hr;
1026 #else
1028 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
1030 MESSAGE("This program tried to use a XMLHTTPRequest object, but\n"
1031 "libxml2 support was not present at compile time.\n");
1032 return E_NOTIMPL;
1035 #endif