msxml3: Implement ::abort().
[wine.git] / dlls / msxml3 / httprequest.c
blobe347096446b4193e8197956eb5a665600c22a24e
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 This->state = state;
95 if (This->sink)
97 DISPPARAMS params;
99 memset(&params, 0, sizeof(params));
100 IDispatch_Invoke(This->sink, 0, &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &params, 0, 0, 0);
104 struct BindStatusCallback
106 const IBindStatusCallbackVtbl *lpBindStatusCallbackVtbl;
107 const IHttpNegotiateVtbl *lpHttpNegotiateVtbl;
108 LONG ref;
110 IBinding *binding;
111 httprequest *request;
113 /* response data */
114 IStream *stream;
117 static inline BindStatusCallback *impl_from_IBindStatusCallback( IBindStatusCallback *iface )
119 return (BindStatusCallback *)((char*)iface - FIELD_OFFSET(BindStatusCallback, lpBindStatusCallbackVtbl));
122 static inline BindStatusCallback *impl_from_IHttpNegotiate( IHttpNegotiate *iface )
124 return (BindStatusCallback *)((char*)iface - FIELD_OFFSET(BindStatusCallback, lpHttpNegotiateVtbl));
127 void BindStatusCallback_Detach(BindStatusCallback *bsc)
129 if (bsc)
131 if (bsc->binding) IBinding_Abort(bsc->binding);
132 bsc->request = NULL;
133 IBindStatusCallback_Release((IBindStatusCallback*)bsc);
137 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
138 REFIID riid, void **ppv)
140 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
142 *ppv = NULL;
144 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
146 if (IsEqualGUID(&IID_IUnknown, riid) ||
147 IsEqualGUID(&IID_IBindStatusCallback, riid))
149 *ppv = &This->lpBindStatusCallbackVtbl;
151 else if (IsEqualGUID(&IID_IHttpNegotiate, riid))
153 *ppv = &This->lpHttpNegotiateVtbl;
155 else if (IsEqualGUID(&IID_IServiceProvider, riid) ||
156 IsEqualGUID(&IID_IBindStatusCallbackEx, riid) ||
157 IsEqualGUID(&IID_IInternetProtocol, riid) ||
158 IsEqualGUID(&IID_IHttpNegotiate2, riid))
160 return E_NOINTERFACE;
163 if (*ppv)
165 IBindStatusCallback_AddRef(iface);
166 return S_OK;
169 FIXME("Unsupported riid = %s\n", debugstr_guid(riid));
171 return E_NOINTERFACE;
174 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
176 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
177 LONG ref = InterlockedIncrement(&This->ref);
179 TRACE("(%p) ref = %d\n", This, ref);
181 return ref;
184 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
186 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
187 LONG ref = InterlockedDecrement(&This->ref);
189 TRACE("(%p) ref = %d\n", This, ref);
191 if (!ref)
193 if (This->binding) IBinding_Release(This->binding);
194 if (This->stream) IStream_Release(This->stream);
195 heap_free(This);
198 return ref;
201 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
202 DWORD reserved, IBinding *pbind)
204 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
206 TRACE("(%p)->(%d %p)\n", This, reserved, pbind);
208 if (!pbind) return E_INVALIDARG;
210 This->binding = pbind;
211 IBinding_AddRef(pbind);
213 httprequest_setreadystate(This->request, READYSTATE_LOADED);
215 return CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
218 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pPriority)
220 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
222 TRACE("(%p)->(%p)\n", This, pPriority);
224 return E_NOTIMPL;
227 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
229 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
231 TRACE("(%p)->(%d)\n", This, reserved);
233 return E_NOTIMPL;
236 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
237 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
239 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
241 TRACE("%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
242 debugstr_w(szStatusText));
244 return S_OK;
247 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
248 HRESULT hr, LPCWSTR error)
250 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
252 TRACE("(%p)->(0x%08x %s)\n", This, hr, debugstr_w(error));
254 if (This->binding)
256 IBinding_Release(This->binding);
257 This->binding = NULL;
260 if (hr == S_OK)
261 httprequest_setreadystate(This->request, READYSTATE_COMPLETE);
263 return S_OK;
266 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
267 DWORD *bind_flags, BINDINFO *pbindinfo)
269 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
271 TRACE("(%p)->(%p %p)\n", This, bind_flags, pbindinfo);
273 *bind_flags = 0;
274 if (This->request->async) *bind_flags |= BINDF_ASYNCHRONOUS;
276 if (This->request->verb != BINDVERB_GET)
278 FIXME("only GET verb supported. Got %d\n", This->request->verb);
279 return E_FAIL;
282 pbindinfo->dwBindVerb = This->request->verb;
284 return S_OK;
287 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
288 DWORD flags, DWORD size, FORMATETC *format, STGMEDIUM *stgmed)
290 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
291 DWORD read, written;
292 BYTE buf[4096];
293 HRESULT hr;
295 TRACE("(%p)->(%08x %d %p %p)\n", This, flags, size, format, stgmed);
299 hr = IStream_Read(stgmed->u.pstm, buf, sizeof(buf), &read);
300 if (hr != S_OK) break;
302 hr = IStream_Write(This->stream, buf, read, &written);
303 } while((hr == S_OK) && written != 0 && read != 0);
305 httprequest_setreadystate(This->request, READYSTATE_INTERACTIVE);
307 return S_OK;
310 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
311 REFIID riid, IUnknown *punk)
313 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
315 FIXME("(%p)->(%s %p): stub\n", This, debugstr_guid(riid), punk);
317 return E_NOTIMPL;
320 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
321 BindStatusCallback_QueryInterface,
322 BindStatusCallback_AddRef,
323 BindStatusCallback_Release,
324 BindStatusCallback_OnStartBinding,
325 BindStatusCallback_GetPriority,
326 BindStatusCallback_OnLowResource,
327 BindStatusCallback_OnProgress,
328 BindStatusCallback_OnStopBinding,
329 BindStatusCallback_GetBindInfo,
330 BindStatusCallback_OnDataAvailable,
331 BindStatusCallback_OnObjectAvailable
334 static HRESULT WINAPI BSCHttpNegotiate_QueryInterface(IHttpNegotiate *iface,
335 REFIID riid, void **ppv)
337 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
338 return IBindStatusCallback_QueryInterface((IBindStatusCallback*)This, riid, ppv);
341 static ULONG WINAPI BSCHttpNegotiate_AddRef(IHttpNegotiate *iface)
343 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
344 return IBindStatusCallback_AddRef((IBindStatusCallback*)This);
347 static ULONG WINAPI BSCHttpNegotiate_Release(IHttpNegotiate *iface)
349 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
350 return IBindStatusCallback_Release((IBindStatusCallback*)This);
353 static HRESULT WINAPI BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate *iface,
354 LPCWSTR url, LPCWSTR headers, DWORD reserved, LPWSTR *add_headers)
356 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
357 const struct reqheader *entry;
358 WCHAR *buff, *ptr;
360 TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(url), debugstr_w(headers), reserved, add_headers);
362 *add_headers = NULL;
364 if (list_empty(&This->request->reqheaders)) return S_OK;
366 buff = CoTaskMemAlloc(This->request->reqheader_size*sizeof(WCHAR));
367 if (!buff) return E_OUTOFMEMORY;
369 ptr = buff;
370 LIST_FOR_EACH_ENTRY(entry, &This->request->reqheaders, struct reqheader, entry)
372 lstrcpyW(ptr, entry->header);
373 ptr += SysStringLen(entry->header);
375 lstrcpyW(ptr, colspaceW);
376 ptr += sizeof(colspaceW)/sizeof(WCHAR)-1;
378 lstrcpyW(ptr, entry->value);
379 ptr += SysStringLen(entry->value);
381 lstrcpyW(ptr, crlfW);
382 ptr += sizeof(crlfW)/sizeof(WCHAR)-1;
385 *add_headers = buff;
387 return S_OK;
390 static HRESULT WINAPI BSCHttpNegotiate_OnResponse(IHttpNegotiate *iface, DWORD code,
391 LPCWSTR resp_headers, LPCWSTR req_headers, LPWSTR *add_reqheaders)
393 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
395 TRACE("(%p)->(%d %s %s %p)\n", This, code, debugstr_w(resp_headers),
396 debugstr_w(req_headers), add_reqheaders);
398 This->request->status = code;
400 return S_OK;
403 static const IHttpNegotiateVtbl BSCHttpNegotiateVtbl = {
404 BSCHttpNegotiate_QueryInterface,
405 BSCHttpNegotiate_AddRef,
406 BSCHttpNegotiate_Release,
407 BSCHttpNegotiate_BeginningTransaction,
408 BSCHttpNegotiate_OnResponse
411 static HRESULT BindStatusCallback_create(httprequest* This, BindStatusCallback **obj)
413 BindStatusCallback *bsc;
414 IBindCtx *pbc;
415 HRESULT hr;
417 hr = CreateBindCtx(0, &pbc);
418 if (hr != S_OK) return hr;
420 bsc = heap_alloc(sizeof(*bsc));
421 if (!bsc)
423 IBindCtx_Release(pbc);
424 return E_OUTOFMEMORY;
427 bsc->lpBindStatusCallbackVtbl = &BindStatusCallbackVtbl;
428 bsc->lpHttpNegotiateVtbl = &BSCHttpNegotiateVtbl;
429 bsc->ref = 1;
430 bsc->request = This;
431 bsc->binding = NULL;
432 bsc->stream = NULL;
434 hr = RegisterBindStatusCallback(pbc, (IBindStatusCallback*)bsc, NULL, 0);
435 if (hr == S_OK)
437 IMoniker *moniker;
439 hr = CreateURLMoniker(NULL, This->url, &moniker);
440 if (hr == S_OK)
442 IStream *stream;
444 hr = IMoniker_BindToStorage(moniker, pbc, NULL, &IID_IStream, (void**)&stream);
445 IMoniker_Release(moniker);
446 if (stream) IStream_Release(stream);
448 IBindCtx_Release(pbc);
451 if (FAILED(hr))
453 IBindStatusCallback_Release((IBindStatusCallback*)bsc);
454 bsc = NULL;
457 *obj = bsc;
458 return hr;
461 static HRESULT WINAPI httprequest_QueryInterface(IXMLHTTPRequest *iface, REFIID riid, void **ppvObject)
463 httprequest *This = impl_from_IXMLHTTPRequest( iface );
464 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
466 if ( IsEqualGUID( riid, &IID_IXMLHTTPRequest) ||
467 IsEqualGUID( riid, &IID_IDispatch) ||
468 IsEqualGUID( riid, &IID_IUnknown) )
470 *ppvObject = iface;
472 else
474 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
475 return E_NOINTERFACE;
478 IXMLHTTPRequest_AddRef( iface );
480 return S_OK;
483 static ULONG WINAPI httprequest_AddRef(IXMLHTTPRequest *iface)
485 httprequest *This = impl_from_IXMLHTTPRequest( iface );
486 ULONG ref = InterlockedIncrement( &This->ref );
487 TRACE("(%p)->(%u)\n", This, ref );
488 return ref;
491 static ULONG WINAPI httprequest_Release(IXMLHTTPRequest *iface)
493 httprequest *This = impl_from_IXMLHTTPRequest( iface );
494 ULONG ref = InterlockedDecrement( &This->ref );
496 TRACE("(%p)->(%u)\n", This, ref );
498 if ( ref == 0 )
500 struct reqheader *header, *header2;
502 SysFreeString(This->url);
503 SysFreeString(This->user);
504 SysFreeString(This->password);
506 /* request headers */
507 LIST_FOR_EACH_ENTRY_SAFE(header, header2, &This->reqheaders, struct reqheader, entry)
509 list_remove(&header->entry);
510 SysFreeString(header->header);
511 SysFreeString(header->value);
514 /* detach callback object */
515 BindStatusCallback_Detach(This->bsc);
517 if (This->sink) IDispatch_Release(This->sink);
519 heap_free( This );
522 return ref;
525 static HRESULT WINAPI httprequest_GetTypeInfoCount(IXMLHTTPRequest *iface, UINT *pctinfo)
527 httprequest *This = impl_from_IXMLHTTPRequest( iface );
529 TRACE("(%p)->(%p)\n", This, pctinfo);
531 *pctinfo = 1;
533 return S_OK;
536 static HRESULT WINAPI httprequest_GetTypeInfo(IXMLHTTPRequest *iface, UINT iTInfo,
537 LCID lcid, ITypeInfo **ppTInfo)
539 httprequest *This = impl_from_IXMLHTTPRequest( iface );
540 HRESULT hr;
542 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
544 hr = get_typeinfo(IXMLHTTPRequest_tid, ppTInfo);
546 return hr;
549 static HRESULT WINAPI httprequest_GetIDsOfNames(IXMLHTTPRequest *iface, REFIID riid,
550 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
552 httprequest *This = impl_from_IXMLHTTPRequest( iface );
553 ITypeInfo *typeinfo;
554 HRESULT hr;
556 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
557 lcid, rgDispId);
559 if(!rgszNames || cNames == 0 || !rgDispId)
560 return E_INVALIDARG;
562 hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
563 if(SUCCEEDED(hr))
565 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
566 ITypeInfo_Release(typeinfo);
569 return hr;
572 static HRESULT WINAPI httprequest_Invoke(IXMLHTTPRequest *iface, DISPID dispIdMember, REFIID riid,
573 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
574 EXCEPINFO *pExcepInfo, UINT *puArgErr)
576 httprequest *This = impl_from_IXMLHTTPRequest( iface );
577 ITypeInfo *typeinfo;
578 HRESULT hr;
580 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
581 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
583 hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
584 if(SUCCEEDED(hr))
586 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
587 pVarResult, pExcepInfo, puArgErr);
588 ITypeInfo_Release(typeinfo);
591 return hr;
594 static HRESULT WINAPI httprequest_open(IXMLHTTPRequest *iface, BSTR method, BSTR url,
595 VARIANT async, VARIANT user, VARIANT password)
597 httprequest *This = impl_from_IXMLHTTPRequest( iface );
598 HRESULT hr;
599 VARIANT str;
601 TRACE("(%p)->(%s %s)\n", This, debugstr_w(method), debugstr_w(url));
603 if (!method || !url) return E_INVALIDARG;
605 /* free previously set data */
606 SysFreeString(This->url);
607 SysFreeString(This->user);
608 SysFreeString(This->password);
609 This->url = This->user = This->password = NULL;
611 if (lstrcmpiW(method, MethodGetW) == 0)
613 This->verb = BINDVERB_GET;
615 else if (lstrcmpiW(method, MethodPutW) == 0)
617 This->verb = BINDVERB_PUT;
619 else if (lstrcmpiW(method, MethodPostW) == 0)
621 This->verb = BINDVERB_POST;
623 else
625 FIXME("unsupported request type %s\n", debugstr_w(method));
626 This->verb = -1;
627 return E_FAIL;
630 This->url = SysAllocString(url);
632 hr = VariantChangeType(&async, &async, 0, VT_BOOL);
633 This->async = hr == S_OK && V_BOOL(&async) == VARIANT_TRUE;
635 VariantInit(&str);
636 hr = VariantChangeType(&str, &user, 0, VT_BSTR);
637 if (hr == S_OK)
638 This->user = V_BSTR(&str);
640 hr = VariantChangeType(&str, &password, 0, VT_BSTR);
641 if (hr == S_OK)
642 This->password = V_BSTR(&str);
644 httprequest_setreadystate(This, READYSTATE_LOADING);
646 return S_OK;
649 static HRESULT WINAPI httprequest_setRequestHeader(IXMLHTTPRequest *iface, BSTR header, BSTR value)
651 httprequest *This = impl_from_IXMLHTTPRequest( iface );
652 struct reqheader *entry;
654 TRACE("(%p)->(%s %s)\n", This, debugstr_w(header), debugstr_w(value));
656 if (!header || !*header) return E_INVALIDARG;
657 if (This->state != READYSTATE_LOADING) return E_FAIL;
658 if (!value) return E_INVALIDARG;
660 /* replace existing header value if already added */
661 LIST_FOR_EACH_ENTRY(entry, &This->reqheaders, struct reqheader, entry)
663 if (lstrcmpW(entry->header, header) == 0)
665 LONG length = SysStringLen(entry->value);
666 HRESULT hr;
668 hr = SysReAllocString(&entry->value, value) ? S_OK : E_OUTOFMEMORY;
670 if (hr == S_OK)
671 This->reqheader_size += (SysStringLen(entry->value) - length);
673 return hr;
677 entry = heap_alloc(sizeof(*entry));
678 if (!entry) return E_OUTOFMEMORY;
680 /* new header */
681 entry->header = SysAllocString(header);
682 entry->value = SysAllocString(value);
684 /* header length including null terminator */
685 This->reqheader_size += SysStringLen(entry->header) + sizeof(colspaceW)/sizeof(WCHAR) +
686 SysStringLen(entry->value) + sizeof(crlfW)/sizeof(WCHAR) - 1;
688 list_add_head(&This->reqheaders, &entry->entry);
690 return S_OK;
693 static HRESULT WINAPI httprequest_getResponseHeader(IXMLHTTPRequest *iface, BSTR bstrHeader, BSTR *pbstrValue)
695 httprequest *This = impl_from_IXMLHTTPRequest( iface );
697 FIXME("stub (%p) %s %p\n", This, debugstr_w(bstrHeader), pbstrValue);
699 return E_NOTIMPL;
702 static HRESULT WINAPI httprequest_getAllResponseHeaders(IXMLHTTPRequest *iface, BSTR *pbstrHeaders)
704 httprequest *This = impl_from_IXMLHTTPRequest( iface );
706 FIXME("stub (%p) %p\n", This, pbstrHeaders);
708 return E_NOTIMPL;
711 static HRESULT WINAPI httprequest_send(IXMLHTTPRequest *iface, VARIANT varBody)
713 httprequest *This = impl_from_IXMLHTTPRequest( iface );
714 BindStatusCallback *bsc = NULL;
715 HRESULT hr;
717 TRACE("(%p)\n", This);
719 if (This->state != READYSTATE_LOADING) return E_FAIL;
721 hr = BindStatusCallback_create(This, &bsc);
722 if (FAILED(hr)) return hr;
724 BindStatusCallback_Detach(This->bsc);
725 This->bsc = bsc;
727 return hr;
730 static HRESULT WINAPI httprequest_abort(IXMLHTTPRequest *iface)
732 httprequest *This = impl_from_IXMLHTTPRequest( iface );
734 TRACE("(%p)\n", This);
736 BindStatusCallback_Detach(This->bsc);
737 This->bsc = NULL;
739 httprequest_setreadystate(This, READYSTATE_UNINITIALIZED);
741 return S_OK;
744 static HRESULT WINAPI httprequest_get_status(IXMLHTTPRequest *iface, LONG *status)
746 httprequest *This = impl_from_IXMLHTTPRequest( iface );
748 TRACE("(%p)->(%p)\n", This, status);
750 if (!status) return E_INVALIDARG;
751 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
753 *status = This->status;
755 return S_OK;
758 static HRESULT WINAPI httprequest_get_statusText(IXMLHTTPRequest *iface, BSTR *pbstrStatus)
760 httprequest *This = impl_from_IXMLHTTPRequest( iface );
762 FIXME("stub %p %p\n", This, pbstrStatus);
764 return E_NOTIMPL;
767 static HRESULT WINAPI httprequest_get_responseXML(IXMLHTTPRequest *iface, IDispatch **ppBody)
769 httprequest *This = impl_from_IXMLHTTPRequest( iface );
771 FIXME("stub %p %p\n", This, ppBody);
773 return E_NOTIMPL;
776 static HRESULT WINAPI httprequest_get_responseText(IXMLHTTPRequest *iface, BSTR *body)
778 httprequest *This = impl_from_IXMLHTTPRequest( iface );
779 HGLOBAL hglobal;
780 HRESULT hr;
782 TRACE("(%p)->(%p)\n", This, body);
784 if (!body) return E_INVALIDARG;
785 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
787 hr = GetHGlobalFromStream(This->bsc->stream, &hglobal);
788 if (hr == S_OK)
790 xmlChar *ptr = GlobalLock(hglobal);
791 DWORD size = GlobalSize(hglobal);
792 xmlCharEncoding encoding = XML_CHAR_ENCODING_UTF8;
794 /* try to determine data encoding */
795 if (size >= 4)
797 encoding = xmlDetectCharEncoding(ptr, 4);
798 TRACE("detected encoding: %s\n", xmlGetCharEncodingName(encoding));
799 if ( encoding != XML_CHAR_ENCODING_UTF8 &&
800 encoding != XML_CHAR_ENCODING_UTF16LE &&
801 encoding != XML_CHAR_ENCODING_NONE )
803 FIXME("unsupported encoding: %s\n", xmlGetCharEncodingName(encoding));
804 GlobalUnlock(hglobal);
805 return E_FAIL;
809 /* without BOM assume UTF-8 */
810 if (encoding == XML_CHAR_ENCODING_UTF8 ||
811 encoding == XML_CHAR_ENCODING_NONE )
813 *body = bstr_from_xmlChar(ptr);
815 else
816 *body = SysAllocStringByteLen((LPCSTR)ptr, size);
818 if (!*body) hr = E_OUTOFMEMORY;
819 GlobalUnlock(hglobal);
822 return hr;
825 static HRESULT WINAPI httprequest_get_responseBody(IXMLHTTPRequest *iface, VARIANT *pvarBody)
827 httprequest *This = impl_from_IXMLHTTPRequest( iface );
829 FIXME("stub %p %p\n", This, pvarBody);
831 return E_NOTIMPL;
834 static HRESULT WINAPI httprequest_get_responseStream(IXMLHTTPRequest *iface, VARIANT *pvarBody)
836 httprequest *This = impl_from_IXMLHTTPRequest( iface );
838 FIXME("stub %p %p\n", This, pvarBody);
840 return E_NOTIMPL;
843 static HRESULT WINAPI httprequest_get_readyState(IXMLHTTPRequest *iface, LONG *state)
845 httprequest *This = impl_from_IXMLHTTPRequest( iface );
847 TRACE("(%p)->(%p)\n", This, state);
849 if (!state) return E_INVALIDARG;
851 *state = This->state;
852 return S_OK;
855 static HRESULT WINAPI httprequest_put_onreadystatechange(IXMLHTTPRequest *iface, IDispatch *sink)
857 httprequest *This = impl_from_IXMLHTTPRequest( iface );
859 TRACE("(%p)->(%p)\n", This, sink);
861 if (This->sink) IDispatch_Release(This->sink);
862 if ((This->sink = sink)) IDispatch_AddRef(This->sink);
864 return S_OK;
867 static const struct IXMLHTTPRequestVtbl dimimpl_vtbl =
869 httprequest_QueryInterface,
870 httprequest_AddRef,
871 httprequest_Release,
872 httprequest_GetTypeInfoCount,
873 httprequest_GetTypeInfo,
874 httprequest_GetIDsOfNames,
875 httprequest_Invoke,
876 httprequest_open,
877 httprequest_setRequestHeader,
878 httprequest_getResponseHeader,
879 httprequest_getAllResponseHeaders,
880 httprequest_send,
881 httprequest_abort,
882 httprequest_get_status,
883 httprequest_get_statusText,
884 httprequest_get_responseXML,
885 httprequest_get_responseText,
886 httprequest_get_responseBody,
887 httprequest_get_responseStream,
888 httprequest_get_readyState,
889 httprequest_put_onreadystatechange
892 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
894 httprequest *req;
895 HRESULT hr = S_OK;
897 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
899 req = heap_alloc( sizeof (*req) );
900 if( !req )
901 return E_OUTOFMEMORY;
903 req->lpVtbl = &dimimpl_vtbl;
904 req->ref = 1;
906 req->async = FALSE;
907 req->verb = -1;
908 req->url = req->user = req->password = NULL;
910 req->state = READYSTATE_UNINITIALIZED;
911 req->sink = NULL;
913 req->bsc = NULL;
914 req->status = 0;
915 req->reqheader_size = 0;
916 list_init(&req->reqheaders);
918 *ppObj = &req->lpVtbl;
920 TRACE("returning iface %p\n", *ppObj);
922 return hr;
925 #else
927 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
929 MESSAGE("This program tried to use a XMLHTTPRequest object, but\n"
930 "libxml2 support was not present at compile time.\n");
931 return E_NOTIMPL;
934 #endif