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
34 #include "msxml_private.h"
36 #include "wine/debug.h"
37 #include "wine/list.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msxml
);
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
;
63 const struct IXMLHTTPRequestVtbl
*lpVtbl
;
73 struct list reqheaders
;
74 /* cached resulting custom request headers string length in WCHARs */
82 BindStatusCallback
*bsc
;
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
;
97 if (This
->sink
&& last
!= state
)
101 memset(¶ms
, 0, sizeof(params
));
102 IDispatch_Invoke(This
->sink
, 0, &IID_NULL
, LOCALE_SYSTEM_DEFAULT
, DISPATCH_METHOD
, ¶ms
, 0, 0, 0);
106 struct BindStatusCallback
108 const IBindStatusCallbackVtbl
*lpBindStatusCallbackVtbl
;
109 const IHttpNegotiateVtbl
*lpHttpNegotiateVtbl
;
113 httprequest
*request
;
118 /* request body data */
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
)
136 if (bsc
->binding
) IBinding_Abort(bsc
->binding
);
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
);
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
;
170 IBindStatusCallback_AddRef(iface
);
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
);
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
);
198 if (This
->binding
) IBinding_Release(This
->binding
);
199 if (This
->stream
) IStream_Release(This
->stream
);
200 if (This
->body
) GlobalFree(This
->body
);
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
);
233 static HRESULT WINAPI
BindStatusCallback_OnLowResource(IBindStatusCallback
*iface
, DWORD reserved
)
235 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
237 TRACE("(%p)->(%d)\n", This
, reserved
);
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
));
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
));
262 IBinding_Release(This
->binding
);
263 This
->binding
= NULL
;
267 httprequest_setreadystate(This
->request
, READYSTATE_COMPLETE
);
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
);
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
;
296 static HRESULT WINAPI
BindStatusCallback_OnDataAvailable(IBindStatusCallback
*iface
,
297 DWORD flags
, DWORD size
, FORMATETC
*format
, STGMEDIUM
*stgmed
)
299 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
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
);
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
);
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
;
369 TRACE("(%p)->(%s %s %d %p)\n", This
, debugstr_w(url
), debugstr_w(headers
), reserved
, add_headers
);
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
;
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;
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
;
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
;
426 hr
= CreateBindCtx(0, &pbc
);
427 if (hr
!= S_OK
) return hr
;
429 bsc
= heap_alloc(sizeof(*bsc
));
432 IBindCtx_Release(pbc
);
433 return E_OUTOFMEMORY
;
436 bsc
->lpBindStatusCallbackVtbl
= &BindStatusCallbackVtbl
;
437 bsc
->lpHttpNegotiateVtbl
= &BSCHttpNegotiateVtbl
;
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
);
453 bsc
->body
= GlobalAlloc(GMEM_FIXED
, size
);
457 return E_OUTOFMEMORY
;
460 ptr
= GlobalLock(bsc
->body
);
461 memcpy(ptr
, V_BSTR(body
), size
);
462 GlobalUnlock(bsc
->body
);
465 FIXME("unsupported body data type %d\n", V_VT(body
));
468 hr
= RegisterBindStatusCallback(pbc
, (IBindStatusCallback
*)bsc
, NULL
, 0);
473 hr
= CreateURLMoniker(NULL
, This
->url
, &moniker
);
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
);
487 IBindStatusCallback_Release((IBindStatusCallback
*)bsc
);
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
) )
508 FIXME("Unsupported interface %s\n", debugstr_guid(riid
));
509 return E_NOINTERFACE
;
512 IXMLHTTPRequest_AddRef( iface
);
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
);
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
);
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
);
559 static HRESULT WINAPI
httprequest_GetTypeInfoCount(IXMLHTTPRequest
*iface
, UINT
*pctinfo
)
561 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
563 TRACE("(%p)->(%p)\n", This
, pctinfo
);
570 static HRESULT WINAPI
httprequest_GetTypeInfo(IXMLHTTPRequest
*iface
, UINT iTInfo
,
571 LCID lcid
, ITypeInfo
**ppTInfo
)
573 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
576 TRACE("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
578 hr
= get_typeinfo(IXMLHTTPRequest_tid
, ppTInfo
);
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
);
590 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
593 if(!rgszNames
|| cNames
== 0 || !rgDispId
)
596 hr
= get_typeinfo(IXMLHTTPRequest_tid
, &typeinfo
);
599 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
600 ITypeInfo_Release(typeinfo
);
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
);
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
);
620 hr
= ITypeInfo_Invoke(typeinfo
, &(This
->lpVtbl
), dispIdMember
, wFlags
, pDispParams
,
621 pVarResult
, pExcepInfo
, puArgErr
);
622 ITypeInfo_Release(typeinfo
);
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
);
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
;
659 FIXME("unsupported request type %s\n", debugstr_w(method
));
664 This
->url
= SysAllocString(url
);
666 hr
= VariantChangeType(&async
, &async
, 0, VT_BOOL
);
667 This
->async
= hr
== S_OK
&& V_BOOL(&async
) == VARIANT_TRUE
;
670 hr
= VariantChangeType(&str
, &user
, 0, VT_BSTR
);
672 This
->user
= V_BSTR(&str
);
674 hr
= VariantChangeType(&str
, &password
, 0, VT_BSTR
);
676 This
->password
= V_BSTR(&str
);
678 httprequest_setreadystate(This
, READYSTATE_LOADING
);
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
);
702 hr
= SysReAllocString(&entry
->value
, value
) ? S_OK
: E_OUTOFMEMORY
;
705 This
->reqheader_size
+= (SysStringLen(entry
->value
) - length
);
711 entry
= heap_alloc(sizeof(*entry
));
712 if (!entry
) return E_OUTOFMEMORY
;
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
);
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
);
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
);
745 static HRESULT WINAPI
httprequest_send(IXMLHTTPRequest
*iface
, VARIANT body
)
747 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
748 BindStatusCallback
*bsc
= NULL
;
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
);
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
);
773 httprequest_setreadystate(This
, READYSTATE_UNINITIALIZED
);
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
;
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
);
801 static HRESULT WINAPI
httprequest_get_responseXML(IXMLHTTPRequest
*iface
, IDispatch
**body
)
803 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
804 IXMLDOMDocument3
*doc
;
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
);
821 hr
= IXMLDOMDocument3_loadXML(doc
, str
, &ok
);
825 IXMLDOMDocument3_QueryInterface(doc
, &IID_IDispatch
, (void**)body
);
826 IXMLDOMDocument3_Release(doc
);
831 static HRESULT WINAPI
httprequest_get_responseText(IXMLHTTPRequest
*iface
, BSTR
*body
)
833 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
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
);
845 xmlChar
*ptr
= GlobalLock(hglobal
);
846 DWORD size
= GlobalSize(hglobal
);
847 xmlCharEncoding encoding
= XML_CHAR_ENCODING_UTF8
;
849 /* try to determine data encoding */
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
);
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
);
872 MultiByteToWideChar( CP_UTF8
, 0, (LPCSTR
)ptr
, size
, *body
, length
);
875 *body
= SysAllocStringByteLen((LPCSTR
)ptr
, size
);
877 if (!*body
) hr
= E_OUTOFMEMORY
;
878 GlobalUnlock(hglobal
);
884 static HRESULT WINAPI
httprequest_get_responseBody(IXMLHTTPRequest
*iface
, VARIANT
*body
)
886 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
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
);
898 void *ptr
= GlobalLock(hglobal
);
899 DWORD size
= GlobalSize(hglobal
);
901 SAFEARRAYBOUND bound
;
905 bound
.cElements
= size
;
906 array
= SafeArrayCreate(VT_UI1
, 1, &bound
);
912 V_VT(body
) = VT_ARRAY
| VT_UI1
;
913 V_ARRAY(body
) = array
;
915 hr
= SafeArrayAccessData(array
, &dest
);
918 memcpy(dest
, ptr
, size
);
919 SafeArrayUnaccessData(array
);
929 GlobalUnlock(hglobal
);
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
);
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
;
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
);
968 static const struct IXMLHTTPRequestVtbl dimimpl_vtbl
=
970 httprequest_QueryInterface
,
973 httprequest_GetTypeInfoCount
,
974 httprequest_GetTypeInfo
,
975 httprequest_GetIDsOfNames
,
978 httprequest_setRequestHeader
,
979 httprequest_getResponseHeader
,
980 httprequest_getAllResponseHeaders
,
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
)
998 TRACE("(%p,%p)\n", pUnkOuter
, ppObj
);
1000 req
= heap_alloc( sizeof (*req
) );
1002 return E_OUTOFMEMORY
;
1004 req
->lpVtbl
= &dimimpl_vtbl
;
1009 req
->url
= req
->user
= req
->password
= NULL
;
1011 req
->state
= READYSTATE_UNINITIALIZED
;
1016 req
->reqheader_size
= 0;
1017 list_init(&req
->reqheaders
);
1019 *ppObj
= &req
->lpVtbl
;
1021 TRACE("returning iface %p\n", *ppObj
);
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");