2 * IXMLHTTPRequest implementation
4 * Copyright 2008 Alistair Leslie-Hughes
5 * Copyright 2010-2012 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
29 # include <libxml/parser.h>
30 # include <libxml/xmlerror.h>
31 # include <libxml/encoding.h>
47 #include "msxml_private.h"
49 #include "wine/debug.h"
50 #include "wine/list.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(msxml
);
56 static const WCHAR colspaceW
[] = {':',' ',0};
57 static const WCHAR crlfW
[] = {'\r','\n',0};
59 typedef struct BindStatusCallback BindStatusCallback
;
70 IXMLHTTPRequest IXMLHTTPRequest_iface
;
71 IObjectWithSite IObjectWithSite_iface
;
72 IObjectSafety IObjectSafety_iface
;
84 struct list reqheaders
;
85 /* cached resulting custom request headers string length in WCHARs */
87 /* use UTF-8 content type */
88 BOOL use_utf8_content
;
90 /* response headers */
91 struct list respheaders
;
99 BindStatusCallback
*bsc
;
109 static inline httprequest
*impl_from_IXMLHTTPRequest( IXMLHTTPRequest
*iface
)
111 return CONTAINING_RECORD(iface
, httprequest
, IXMLHTTPRequest_iface
);
114 static inline httprequest
*impl_from_IObjectWithSite(IObjectWithSite
*iface
)
116 return CONTAINING_RECORD(iface
, httprequest
, IObjectWithSite_iface
);
119 static inline httprequest
*impl_from_IObjectSafety(IObjectSafety
*iface
)
121 return CONTAINING_RECORD(iface
, httprequest
, IObjectSafety_iface
);
124 static void httprequest_setreadystate(httprequest
*This
, READYSTATE state
)
126 READYSTATE last
= This
->state
;
130 if (This
->sink
&& last
!= state
)
134 memset(¶ms
, 0, sizeof(params
));
135 IDispatch_Invoke(This
->sink
, 0, &IID_NULL
, LOCALE_SYSTEM_DEFAULT
, DISPATCH_METHOD
, ¶ms
, 0, 0, 0);
139 static void free_response_headers(httprequest
*This
)
141 struct httpheader
*header
, *header2
;
143 LIST_FOR_EACH_ENTRY_SAFE(header
, header2
, &This
->respheaders
, struct httpheader
, entry
)
145 list_remove(&header
->entry
);
146 SysFreeString(header
->header
);
147 SysFreeString(header
->value
);
151 SysFreeString(This
->raw_respheaders
);
152 This
->raw_respheaders
= NULL
;
155 struct BindStatusCallback
157 IBindStatusCallback IBindStatusCallback_iface
;
158 IHttpNegotiate IHttpNegotiate_iface
;
159 IAuthenticate IAuthenticate_iface
;
163 httprequest
*request
;
168 /* request body data */
172 static inline BindStatusCallback
*impl_from_IBindStatusCallback( IBindStatusCallback
*iface
)
174 return CONTAINING_RECORD(iface
, BindStatusCallback
, IBindStatusCallback_iface
);
177 static inline BindStatusCallback
*impl_from_IHttpNegotiate( IHttpNegotiate
*iface
)
179 return CONTAINING_RECORD(iface
, BindStatusCallback
, IHttpNegotiate_iface
);
182 static inline BindStatusCallback
*impl_from_IAuthenticate( IAuthenticate
*iface
)
184 return CONTAINING_RECORD(iface
, BindStatusCallback
, IAuthenticate_iface
);
187 static void BindStatusCallback_Detach(BindStatusCallback
*bsc
)
191 if (bsc
->binding
) IBinding_Abort(bsc
->binding
);
193 IBindStatusCallback_Release(&bsc
->IBindStatusCallback_iface
);
197 static HRESULT WINAPI
BindStatusCallback_QueryInterface(IBindStatusCallback
*iface
,
198 REFIID riid
, void **ppv
)
200 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
204 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
206 if (IsEqualGUID(&IID_IUnknown
, riid
) ||
207 IsEqualGUID(&IID_IBindStatusCallback
, riid
))
209 *ppv
= &This
->IBindStatusCallback_iface
;
211 else if (IsEqualGUID(&IID_IHttpNegotiate
, riid
))
213 *ppv
= &This
->IHttpNegotiate_iface
;
215 else if (IsEqualGUID(&IID_IAuthenticate
, riid
))
217 *ppv
= &This
->IAuthenticate_iface
;
219 else if (IsEqualGUID(&IID_IServiceProvider
, riid
) ||
220 IsEqualGUID(&IID_IBindStatusCallbackEx
, riid
) ||
221 IsEqualGUID(&IID_IInternetProtocol
, riid
) ||
222 IsEqualGUID(&IID_IHttpNegotiate2
, riid
))
224 return E_NOINTERFACE
;
229 IBindStatusCallback_AddRef(iface
);
233 FIXME("Unsupported riid = %s\n", debugstr_guid(riid
));
235 return E_NOINTERFACE
;
238 static ULONG WINAPI
BindStatusCallback_AddRef(IBindStatusCallback
*iface
)
240 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
241 LONG ref
= InterlockedIncrement(&This
->ref
);
243 TRACE("(%p) ref = %d\n", This
, ref
);
248 static ULONG WINAPI
BindStatusCallback_Release(IBindStatusCallback
*iface
)
250 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
251 LONG ref
= InterlockedDecrement(&This
->ref
);
253 TRACE("(%p) ref = %d\n", This
, ref
);
257 if (This
->binding
) IBinding_Release(This
->binding
);
258 if (This
->stream
) IStream_Release(This
->stream
);
259 if (This
->body
) GlobalFree(This
->body
);
266 static HRESULT WINAPI
BindStatusCallback_OnStartBinding(IBindStatusCallback
*iface
,
267 DWORD reserved
, IBinding
*pbind
)
269 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
271 TRACE("(%p)->(%d %p)\n", This
, reserved
, pbind
);
273 if (!pbind
) return E_INVALIDARG
;
275 This
->binding
= pbind
;
276 IBinding_AddRef(pbind
);
278 httprequest_setreadystate(This
->request
, READYSTATE_LOADED
);
280 return CreateStreamOnHGlobal(NULL
, TRUE
, &This
->stream
);
283 static HRESULT WINAPI
BindStatusCallback_GetPriority(IBindStatusCallback
*iface
, LONG
*pPriority
)
285 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
287 TRACE("(%p)->(%p)\n", This
, pPriority
);
292 static HRESULT WINAPI
BindStatusCallback_OnLowResource(IBindStatusCallback
*iface
, DWORD reserved
)
294 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
296 TRACE("(%p)->(%d)\n", This
, reserved
);
301 static HRESULT WINAPI
BindStatusCallback_OnProgress(IBindStatusCallback
*iface
, ULONG ulProgress
,
302 ULONG ulProgressMax
, ULONG ulStatusCode
, LPCWSTR szStatusText
)
304 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
306 TRACE("(%p)->(%u %u %u %s)\n", This
, ulProgress
, ulProgressMax
, ulStatusCode
,
307 debugstr_w(szStatusText
));
312 static HRESULT WINAPI
BindStatusCallback_OnStopBinding(IBindStatusCallback
*iface
,
313 HRESULT hr
, LPCWSTR error
)
315 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
317 TRACE("(%p)->(0x%08x %s)\n", This
, hr
, debugstr_w(error
));
321 IBinding_Release(This
->binding
);
322 This
->binding
= NULL
;
326 httprequest_setreadystate(This
->request
, READYSTATE_COMPLETE
);
331 static HRESULT WINAPI
BindStatusCallback_GetBindInfo(IBindStatusCallback
*iface
,
332 DWORD
*bind_flags
, BINDINFO
*pbindinfo
)
334 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
336 TRACE("(%p)->(%p %p)\n", This
, bind_flags
, pbindinfo
);
339 if (This
->request
->async
) *bind_flags
|= BINDF_ASYNCHRONOUS
;
341 if (This
->request
->verb
!= BINDVERB_GET
&& This
->body
)
343 pbindinfo
->stgmedData
.tymed
= TYMED_HGLOBAL
;
344 pbindinfo
->stgmedData
.u
.hGlobal
= This
->body
;
345 pbindinfo
->cbstgmedData
= GlobalSize(This
->body
);
346 /* callback owns passed body pointer */
347 IBindStatusCallback_QueryInterface(iface
, &IID_IUnknown
, (void**)&pbindinfo
->stgmedData
.pUnkForRelease
);
350 pbindinfo
->dwBindVerb
= This
->request
->verb
;
351 if (This
->request
->verb
== BINDVERB_CUSTOM
)
353 pbindinfo
->szCustomVerb
= CoTaskMemAlloc(SysStringByteLen(This
->request
->custom
));
354 strcpyW(pbindinfo
->szCustomVerb
, This
->request
->custom
);
360 static HRESULT WINAPI
BindStatusCallback_OnDataAvailable(IBindStatusCallback
*iface
,
361 DWORD flags
, DWORD size
, FORMATETC
*format
, STGMEDIUM
*stgmed
)
363 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
368 TRACE("(%p)->(%08x %d %p %p)\n", This
, flags
, size
, format
, stgmed
);
372 hr
= IStream_Read(stgmed
->u
.pstm
, buf
, sizeof(buf
), &read
);
373 if (hr
!= S_OK
) break;
375 hr
= IStream_Write(This
->stream
, buf
, read
, &written
);
376 } while((hr
== S_OK
) && written
!= 0 && read
!= 0);
378 httprequest_setreadystate(This
->request
, READYSTATE_INTERACTIVE
);
383 static HRESULT WINAPI
BindStatusCallback_OnObjectAvailable(IBindStatusCallback
*iface
,
384 REFIID riid
, IUnknown
*punk
)
386 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
388 FIXME("(%p)->(%s %p): stub\n", This
, debugstr_guid(riid
), punk
);
393 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl
= {
394 BindStatusCallback_QueryInterface
,
395 BindStatusCallback_AddRef
,
396 BindStatusCallback_Release
,
397 BindStatusCallback_OnStartBinding
,
398 BindStatusCallback_GetPriority
,
399 BindStatusCallback_OnLowResource
,
400 BindStatusCallback_OnProgress
,
401 BindStatusCallback_OnStopBinding
,
402 BindStatusCallback_GetBindInfo
,
403 BindStatusCallback_OnDataAvailable
,
404 BindStatusCallback_OnObjectAvailable
407 static HRESULT WINAPI
BSCHttpNegotiate_QueryInterface(IHttpNegotiate
*iface
,
408 REFIID riid
, void **ppv
)
410 BindStatusCallback
*This
= impl_from_IHttpNegotiate(iface
);
411 return IBindStatusCallback_QueryInterface(&This
->IBindStatusCallback_iface
, riid
, ppv
);
414 static ULONG WINAPI
BSCHttpNegotiate_AddRef(IHttpNegotiate
*iface
)
416 BindStatusCallback
*This
= impl_from_IHttpNegotiate(iface
);
417 return IBindStatusCallback_AddRef(&This
->IBindStatusCallback_iface
);
420 static ULONG WINAPI
BSCHttpNegotiate_Release(IHttpNegotiate
*iface
)
422 BindStatusCallback
*This
= impl_from_IHttpNegotiate(iface
);
423 return IBindStatusCallback_Release(&This
->IBindStatusCallback_iface
);
426 static HRESULT WINAPI
BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate
*iface
,
427 LPCWSTR url
, LPCWSTR headers
, DWORD reserved
, LPWSTR
*add_headers
)
429 static const WCHAR content_type_utf8W
[] = {'C','o','n','t','e','n','t','-','T','y','p','e',':',' ',
430 't','e','x','t','/','p','l','a','i','n',';','c','h','a','r','s','e','t','=','u','t','f','-','8','\r','\n',0};
432 BindStatusCallback
*This
= impl_from_IHttpNegotiate(iface
);
433 const struct httpheader
*entry
;
437 TRACE("(%p)->(%s %s %d %p)\n", This
, debugstr_w(url
), debugstr_w(headers
), reserved
, add_headers
);
441 if (This
->request
->use_utf8_content
)
442 size
= sizeof(content_type_utf8W
);
444 if (!list_empty(&This
->request
->reqheaders
))
445 size
+= This
->request
->reqheader_size
*sizeof(WCHAR
);
447 if (!size
) return S_OK
;
449 buff
= CoTaskMemAlloc(size
);
450 if (!buff
) return E_OUTOFMEMORY
;
453 if (This
->request
->use_utf8_content
)
455 lstrcpyW(ptr
, content_type_utf8W
);
456 ptr
+= sizeof(content_type_utf8W
)/sizeof(WCHAR
)-1;
460 LIST_FOR_EACH_ENTRY(entry
, &This
->request
->reqheaders
, struct httpheader
, entry
)
462 lstrcpyW(ptr
, entry
->header
);
463 ptr
+= SysStringLen(entry
->header
);
465 lstrcpyW(ptr
, colspaceW
);
466 ptr
+= sizeof(colspaceW
)/sizeof(WCHAR
)-1;
468 lstrcpyW(ptr
, entry
->value
);
469 ptr
+= SysStringLen(entry
->value
);
471 lstrcpyW(ptr
, crlfW
);
472 ptr
+= sizeof(crlfW
)/sizeof(WCHAR
)-1;
480 static void add_response_header(httprequest
*This
, const WCHAR
*data
, int len
)
482 struct httpheader
*entry
;
483 const WCHAR
*ptr
= data
;
490 header
= SysAllocStringLen(data
, ptr
-data
);
491 /* skip leading spaces for a value */
492 while (*++ptr
== ' ')
494 value
= SysAllocStringLen(ptr
, len
-(ptr
-data
));
503 TRACE("got header %s:%s\n", debugstr_w(header
), debugstr_w(value
));
505 entry
= heap_alloc(sizeof(*header
));
506 entry
->header
= header
;
507 entry
->value
= value
;
508 list_add_head(&This
->respheaders
, &entry
->entry
);
511 static HRESULT WINAPI
BSCHttpNegotiate_OnResponse(IHttpNegotiate
*iface
, DWORD code
,
512 LPCWSTR resp_headers
, LPCWSTR req_headers
, LPWSTR
*add_reqheaders
)
514 BindStatusCallback
*This
= impl_from_IHttpNegotiate(iface
);
516 TRACE("(%p)->(%d %s %s %p)\n", This
, code
, debugstr_w(resp_headers
),
517 debugstr_w(req_headers
), add_reqheaders
);
519 This
->request
->status
= code
;
521 free_response_headers(This
->request
);
524 const WCHAR
*ptr
, *line
;
526 ptr
= line
= resp_headers
;
528 /* skip status line */
531 if (*ptr
== '\r' && *(ptr
+1) == '\n')
539 /* store as unparsed string for now */
540 This
->request
->raw_respheaders
= SysAllocString(line
);
546 static const IHttpNegotiateVtbl BSCHttpNegotiateVtbl
= {
547 BSCHttpNegotiate_QueryInterface
,
548 BSCHttpNegotiate_AddRef
,
549 BSCHttpNegotiate_Release
,
550 BSCHttpNegotiate_BeginningTransaction
,
551 BSCHttpNegotiate_OnResponse
554 static HRESULT WINAPI
Authenticate_QueryInterface(IAuthenticate
*iface
,
555 REFIID riid
, void **ppv
)
557 BindStatusCallback
*This
= impl_from_IAuthenticate(iface
);
558 return IBindStatusCallback_QueryInterface(&This
->IBindStatusCallback_iface
, riid
, ppv
);
561 static ULONG WINAPI
Authenticate_AddRef(IAuthenticate
*iface
)
563 BindStatusCallback
*This
= impl_from_IAuthenticate(iface
);
564 return IBindStatusCallback_AddRef(&This
->IBindStatusCallback_iface
);
567 static ULONG WINAPI
Authenticate_Release(IAuthenticate
*iface
)
569 BindStatusCallback
*This
= impl_from_IAuthenticate(iface
);
570 return IBindStatusCallback_Release(&This
->IBindStatusCallback_iface
);
573 static HRESULT WINAPI
Authenticate_Authenticate(IAuthenticate
*iface
,
574 HWND
*hwnd
, LPWSTR
*username
, LPWSTR
*password
)
576 BindStatusCallback
*This
= impl_from_IAuthenticate(iface
);
577 FIXME("(%p)->(%p %p %p)\n", This
, hwnd
, username
, password
);
581 static const IAuthenticateVtbl AuthenticateVtbl
= {
582 Authenticate_QueryInterface
,
584 Authenticate_Release
,
585 Authenticate_Authenticate
588 static HRESULT
BindStatusCallback_create(httprequest
* This
, BindStatusCallback
**obj
, const VARIANT
*body
)
590 BindStatusCallback
*bsc
;
595 hr
= CreateBindCtx(0, &pbc
);
596 if (hr
!= S_OK
) return hr
;
598 bsc
= heap_alloc(sizeof(*bsc
));
601 IBindCtx_Release(pbc
);
602 return E_OUTOFMEMORY
;
605 bsc
->IBindStatusCallback_iface
.lpVtbl
= &BindStatusCallbackVtbl
;
606 bsc
->IHttpNegotiate_iface
.lpVtbl
= &BSCHttpNegotiateVtbl
;
607 bsc
->IAuthenticate_iface
.lpVtbl
= &AuthenticateVtbl
;
614 TRACE("(%p)->(%p)\n", This
, bsc
);
616 This
->use_utf8_content
= FALSE
;
618 if (This
->verb
!= BINDVERB_GET
)
620 void *send_data
, *ptr
;
621 SAFEARRAY
*sa
= NULL
;
623 if (V_VT(body
) == (VT_VARIANT
|VT_BYREF
))
624 body
= V_VARIANTREF(body
);
630 int len
= SysStringLen(V_BSTR(body
));
631 const WCHAR
*str
= V_BSTR(body
);
634 for (i
= 0; i
< len
; i
++)
643 size
= WideCharToMultiByte(cp
, 0, str
, len
, NULL
, 0, NULL
, NULL
);
644 if (!(ptr
= heap_alloc(size
)))
647 return E_OUTOFMEMORY
;
649 WideCharToMultiByte(cp
, 0, str
, len
, ptr
, size
, NULL
, NULL
);
650 if (cp
== CP_UTF8
) This
->use_utf8_content
= TRUE
;
653 case VT_ARRAY
|VT_UI1
:
656 if ((hr
= SafeArrayAccessData(sa
, (void **)&ptr
)) != S_OK
) return hr
;
657 if ((hr
= SafeArrayGetUBound(sa
, 1, &size
) != S_OK
))
659 SafeArrayUnaccessData(sa
);
670 FIXME("unsupported body data type %d\n", V_VT(body
));
674 bsc
->body
= GlobalAlloc(GMEM_FIXED
, size
);
677 if (V_VT(body
) == VT_BSTR
)
679 else if (V_VT(body
) == (VT_ARRAY
|VT_UI1
))
680 SafeArrayUnaccessData(sa
);
683 return E_OUTOFMEMORY
;
686 send_data
= GlobalLock(bsc
->body
);
687 memcpy(send_data
, ptr
, size
);
688 GlobalUnlock(bsc
->body
);
690 if (V_VT(body
) == VT_BSTR
)
692 else if (V_VT(body
) == (VT_ARRAY
|VT_UI1
))
693 SafeArrayUnaccessData(sa
);
696 hr
= RegisterBindStatusCallback(pbc
, &bsc
->IBindStatusCallback_iface
, NULL
, 0);
701 hr
= CreateURLMoniker(NULL
, This
->url
, &moniker
);
706 hr
= IMoniker_BindToStorage(moniker
, pbc
, NULL
, &IID_IStream
, (void**)&stream
);
707 IMoniker_Release(moniker
);
708 if (stream
) IStream_Release(stream
);
710 IBindCtx_Release(pbc
);
715 IBindStatusCallback_Release(&bsc
->IBindStatusCallback_iface
);
723 static HRESULT WINAPI
httprequest_QueryInterface(IXMLHTTPRequest
*iface
, REFIID riid
, void **ppvObject
)
725 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
726 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
728 if ( IsEqualGUID( riid
, &IID_IXMLHTTPRequest
) ||
729 IsEqualGUID( riid
, &IID_IDispatch
) ||
730 IsEqualGUID( riid
, &IID_IUnknown
) )
734 else if (IsEqualGUID(&IID_IObjectWithSite
, riid
))
736 *ppvObject
= &This
->IObjectWithSite_iface
;
738 else if (IsEqualGUID(&IID_IObjectSafety
, riid
))
740 *ppvObject
= &This
->IObjectSafety_iface
;
744 TRACE("Unsupported interface %s\n", debugstr_guid(riid
));
746 return E_NOINTERFACE
;
749 IXMLHTTPRequest_AddRef( iface
);
754 static ULONG WINAPI
httprequest_AddRef(IXMLHTTPRequest
*iface
)
756 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
757 ULONG ref
= InterlockedIncrement( &This
->ref
);
758 TRACE("(%p)->(%u)\n", This
, ref
);
762 static ULONG WINAPI
httprequest_Release(IXMLHTTPRequest
*iface
)
764 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
765 ULONG ref
= InterlockedDecrement( &This
->ref
);
767 TRACE("(%p)->(%u)\n", This
, ref
);
771 struct httpheader
*header
, *header2
;
774 IUnknown_Release( This
->site
);
776 SysFreeString(This
->custom
);
777 SysFreeString(This
->siteurl
);
778 SysFreeString(This
->url
);
779 SysFreeString(This
->user
);
780 SysFreeString(This
->password
);
782 /* request headers */
783 LIST_FOR_EACH_ENTRY_SAFE(header
, header2
, &This
->reqheaders
, struct httpheader
, entry
)
785 list_remove(&header
->entry
);
786 SysFreeString(header
->header
);
787 SysFreeString(header
->value
);
790 /* response headers */
791 free_response_headers(This
);
793 /* detach callback object */
794 BindStatusCallback_Detach(This
->bsc
);
796 if (This
->sink
) IDispatch_Release(This
->sink
);
804 static HRESULT WINAPI
httprequest_GetTypeInfoCount(IXMLHTTPRequest
*iface
, UINT
*pctinfo
)
806 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
808 TRACE("(%p)->(%p)\n", This
, pctinfo
);
815 static HRESULT WINAPI
httprequest_GetTypeInfo(IXMLHTTPRequest
*iface
, UINT iTInfo
,
816 LCID lcid
, ITypeInfo
**ppTInfo
)
818 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
820 TRACE("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
822 return get_typeinfo(IXMLHTTPRequest_tid
, ppTInfo
);
825 static HRESULT WINAPI
httprequest_GetIDsOfNames(IXMLHTTPRequest
*iface
, REFIID riid
,
826 LPOLESTR
*rgszNames
, UINT cNames
, LCID lcid
, DISPID
*rgDispId
)
828 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
832 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
835 if(!rgszNames
|| cNames
== 0 || !rgDispId
)
838 hr
= get_typeinfo(IXMLHTTPRequest_tid
, &typeinfo
);
841 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
842 ITypeInfo_Release(typeinfo
);
848 static HRESULT WINAPI
httprequest_Invoke(IXMLHTTPRequest
*iface
, DISPID dispIdMember
, REFIID riid
,
849 LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
,
850 EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
852 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
856 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
857 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
859 hr
= get_typeinfo(IXMLHTTPRequest_tid
, &typeinfo
);
862 hr
= ITypeInfo_Invoke(typeinfo
, &This
->IXMLHTTPRequest_iface
, dispIdMember
, wFlags
,
863 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
864 ITypeInfo_Release(typeinfo
);
870 static HRESULT WINAPI
httprequest_open(IXMLHTTPRequest
*iface
, BSTR method
, BSTR url
,
871 VARIANT async
, VARIANT user
, VARIANT password
)
873 static const WCHAR MethodGetW
[] = {'G','E','T',0};
874 static const WCHAR MethodPutW
[] = {'P','U','T',0};
875 static const WCHAR MethodPostW
[] = {'P','O','S','T',0};
876 static const WCHAR MethodDeleteW
[] = {'D','E','L','E','T','E',0};
878 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
879 VARIANT str
, is_async
;
882 TRACE("(%p)->(%s %s %s)\n", This
, debugstr_w(method
), debugstr_w(url
),
883 debugstr_variant(&async
));
885 if (!method
|| !url
) return E_INVALIDARG
;
887 /* free previously set data */
888 SysFreeString(This
->url
);
889 SysFreeString(This
->user
);
890 SysFreeString(This
->password
);
891 This
->url
= This
->user
= This
->password
= NULL
;
893 if (!strcmpiW(method
, MethodGetW
))
895 This
->verb
= BINDVERB_GET
;
897 else if (!strcmpiW(method
, MethodPutW
))
899 This
->verb
= BINDVERB_PUT
;
901 else if (!strcmpiW(method
, MethodPostW
))
903 This
->verb
= BINDVERB_POST
;
905 else if (!strcmpiW(method
, MethodDeleteW
))
907 This
->verb
= BINDVERB_CUSTOM
;
908 SysReAllocString(&This
->custom
, method
);
912 FIXME("unsupported request type %s\n", debugstr_w(method
));
917 /* try to combine with site url */
918 if (This
->siteurl
&& PathIsRelativeW(url
))
920 DWORD len
= INTERNET_MAX_URL_LENGTH
;
921 WCHAR
*fullW
= heap_alloc(len
*sizeof(WCHAR
));
923 hr
= UrlCombineW(This
->siteurl
, url
, fullW
, &len
, 0);
926 TRACE("combined url %s\n", debugstr_w(fullW
));
927 This
->url
= SysAllocString(fullW
);
932 This
->url
= SysAllocString(url
);
934 VariantInit(&is_async
);
935 hr
= VariantChangeType(&is_async
, &async
, 0, VT_BOOL
);
936 This
->async
= hr
== S_OK
&& V_BOOL(&is_async
) == VARIANT_TRUE
;
939 hr
= VariantChangeType(&str
, &user
, 0, VT_BSTR
);
941 This
->user
= V_BSTR(&str
);
944 hr
= VariantChangeType(&str
, &password
, 0, VT_BSTR
);
946 This
->password
= V_BSTR(&str
);
948 httprequest_setreadystate(This
, READYSTATE_LOADING
);
953 static HRESULT WINAPI
httprequest_setRequestHeader(IXMLHTTPRequest
*iface
, BSTR header
, BSTR value
)
955 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
956 struct httpheader
*entry
;
958 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(header
), debugstr_w(value
));
960 if (!header
|| !*header
) return E_INVALIDARG
;
961 if (This
->state
!= READYSTATE_LOADING
) return E_FAIL
;
962 if (!value
) return E_INVALIDARG
;
964 /* replace existing header value if already added */
965 LIST_FOR_EACH_ENTRY(entry
, &This
->reqheaders
, struct httpheader
, entry
)
967 if (lstrcmpW(entry
->header
, header
) == 0)
969 LONG length
= SysStringLen(entry
->value
);
972 hr
= SysReAllocString(&entry
->value
, value
) ? S_OK
: E_OUTOFMEMORY
;
975 This
->reqheader_size
+= (SysStringLen(entry
->value
) - length
);
981 entry
= heap_alloc(sizeof(*entry
));
982 if (!entry
) return E_OUTOFMEMORY
;
985 entry
->header
= SysAllocString(header
);
986 entry
->value
= SysAllocString(value
);
988 /* header length including null terminator */
989 This
->reqheader_size
+= SysStringLen(entry
->header
) + sizeof(colspaceW
)/sizeof(WCHAR
) +
990 SysStringLen(entry
->value
) + sizeof(crlfW
)/sizeof(WCHAR
) - 1;
992 list_add_head(&This
->reqheaders
, &entry
->entry
);
997 static HRESULT WINAPI
httprequest_getResponseHeader(IXMLHTTPRequest
*iface
, BSTR header
, BSTR
*value
)
999 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1000 struct httpheader
*entry
;
1002 TRACE("(%p)->(%s %p)\n", This
, debugstr_w(header
), value
);
1004 if (!header
|| !value
) return E_INVALIDARG
;
1006 if (This
->raw_respheaders
&& list_empty(&This
->respheaders
))
1010 ptr
= line
= This
->raw_respheaders
;
1013 if (*ptr
== '\r' && *(ptr
+1) == '\n')
1015 add_response_header(This
, line
, ptr
-line
);
1016 ptr
++; line
= ++ptr
;
1023 LIST_FOR_EACH_ENTRY(entry
, &This
->respheaders
, struct httpheader
, entry
)
1025 if (!strcmpiW(entry
->header
, header
))
1027 *value
= SysAllocString(entry
->value
);
1028 TRACE("header value %s\n", debugstr_w(*value
));
1036 static HRESULT WINAPI
httprequest_getAllResponseHeaders(IXMLHTTPRequest
*iface
, BSTR
*respheaders
)
1038 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1040 TRACE("(%p)->(%p)\n", This
, respheaders
);
1042 if (!respheaders
) return E_INVALIDARG
;
1044 *respheaders
= SysAllocString(This
->raw_respheaders
);
1049 static HRESULT WINAPI
httprequest_send(IXMLHTTPRequest
*iface
, VARIANT body
)
1051 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1052 BindStatusCallback
*bsc
= NULL
;
1055 TRACE("(%p)->(%s)\n", This
, debugstr_variant(&body
));
1057 if (This
->state
!= READYSTATE_LOADING
) return E_FAIL
;
1059 hr
= BindStatusCallback_create(This
, &bsc
, &body
);
1060 if (FAILED(hr
)) return hr
;
1062 BindStatusCallback_Detach(This
->bsc
);
1068 static HRESULT WINAPI
httprequest_abort(IXMLHTTPRequest
*iface
)
1070 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1072 TRACE("(%p)\n", This
);
1074 BindStatusCallback_Detach(This
->bsc
);
1077 httprequest_setreadystate(This
, READYSTATE_UNINITIALIZED
);
1082 static HRESULT WINAPI
httprequest_get_status(IXMLHTTPRequest
*iface
, LONG
*status
)
1084 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1086 TRACE("(%p)->(%p)\n", This
, status
);
1088 if (!status
) return E_INVALIDARG
;
1089 if (This
->state
!= READYSTATE_COMPLETE
) return E_FAIL
;
1091 *status
= This
->status
;
1096 static HRESULT WINAPI
httprequest_get_statusText(IXMLHTTPRequest
*iface
, BSTR
*pbstrStatus
)
1098 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1100 FIXME("stub %p %p\n", This
, pbstrStatus
);
1105 static HRESULT WINAPI
httprequest_get_responseXML(IXMLHTTPRequest
*iface
, IDispatch
**body
)
1107 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1108 IXMLDOMDocument3
*doc
;
1112 TRACE("(%p)->(%p)\n", This
, body
);
1114 if (!body
) return E_INVALIDARG
;
1115 if (This
->state
!= READYSTATE_COMPLETE
) return E_FAIL
;
1117 hr
= DOMDocument_create(MSXML_DEFAULT
, NULL
, (void**)&doc
);
1118 if (hr
!= S_OK
) return hr
;
1120 hr
= IXMLHTTPRequest_get_responseText(iface
, &str
);
1125 hr
= IXMLDOMDocument3_loadXML(doc
, str
, &ok
);
1129 IXMLDOMDocument3_QueryInterface(doc
, &IID_IDispatch
, (void**)body
);
1130 IXMLDOMDocument3_Release(doc
);
1135 static HRESULT WINAPI
httprequest_get_responseText(IXMLHTTPRequest
*iface
, BSTR
*body
)
1137 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1141 TRACE("(%p)->(%p)\n", This
, body
);
1143 if (!body
) return E_INVALIDARG
;
1144 if (This
->state
!= READYSTATE_COMPLETE
) return E_FAIL
;
1146 hr
= GetHGlobalFromStream(This
->bsc
->stream
, &hglobal
);
1149 xmlChar
*ptr
= GlobalLock(hglobal
);
1150 DWORD size
= GlobalSize(hglobal
);
1151 xmlCharEncoding encoding
= XML_CHAR_ENCODING_UTF8
;
1153 /* try to determine data encoding */
1156 encoding
= xmlDetectCharEncoding(ptr
, 4);
1157 TRACE("detected encoding: %s\n", debugstr_a(xmlGetCharEncodingName(encoding
)));
1158 if ( encoding
!= XML_CHAR_ENCODING_UTF8
&&
1159 encoding
!= XML_CHAR_ENCODING_UTF16LE
&&
1160 encoding
!= XML_CHAR_ENCODING_NONE
)
1162 FIXME("unsupported encoding: %s\n", debugstr_a(xmlGetCharEncodingName(encoding
)));
1163 GlobalUnlock(hglobal
);
1168 /* without BOM assume UTF-8 */
1169 if (encoding
== XML_CHAR_ENCODING_UTF8
||
1170 encoding
== XML_CHAR_ENCODING_NONE
)
1172 DWORD length
= MultiByteToWideChar(CP_UTF8
, 0, (LPCSTR
)ptr
, size
, NULL
, 0);
1174 *body
= SysAllocStringLen(NULL
, length
);
1176 MultiByteToWideChar( CP_UTF8
, 0, (LPCSTR
)ptr
, size
, *body
, length
);
1179 *body
= SysAllocStringByteLen((LPCSTR
)ptr
, size
);
1181 if (!*body
) hr
= E_OUTOFMEMORY
;
1182 GlobalUnlock(hglobal
);
1188 static HRESULT WINAPI
httprequest_get_responseBody(IXMLHTTPRequest
*iface
, VARIANT
*body
)
1190 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1194 TRACE("(%p)->(%p)\n", This
, body
);
1196 if (!body
) return E_INVALIDARG
;
1197 V_VT(body
) = VT_EMPTY
;
1199 if (This
->state
!= READYSTATE_COMPLETE
) return E_PENDING
;
1201 hr
= GetHGlobalFromStream(This
->bsc
->stream
, &hglobal
);
1204 void *ptr
= GlobalLock(hglobal
);
1205 DWORD size
= GlobalSize(hglobal
);
1207 SAFEARRAYBOUND bound
;
1211 bound
.cElements
= size
;
1212 array
= SafeArrayCreate(VT_UI1
, 1, &bound
);
1218 V_VT(body
) = VT_ARRAY
| VT_UI1
;
1219 V_ARRAY(body
) = array
;
1221 hr
= SafeArrayAccessData(array
, &dest
);
1224 memcpy(dest
, ptr
, size
);
1225 SafeArrayUnaccessData(array
);
1235 GlobalUnlock(hglobal
);
1241 static HRESULT WINAPI
httprequest_get_responseStream(IXMLHTTPRequest
*iface
, VARIANT
*body
)
1243 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1248 TRACE("(%p)->(%p)\n", This
, body
);
1250 if (!body
) return E_INVALIDARG
;
1251 V_VT(body
) = VT_EMPTY
;
1253 if (This
->state
!= READYSTATE_COMPLETE
) return E_PENDING
;
1255 hr
= IStream_Clone(This
->bsc
->stream
, &stream
);
1258 IStream_Seek(stream
, move
, STREAM_SEEK_SET
, NULL
);
1260 V_VT(body
) = VT_UNKNOWN
;
1261 V_UNKNOWN(body
) = (IUnknown
*)stream
;
1266 static HRESULT WINAPI
httprequest_get_readyState(IXMLHTTPRequest
*iface
, LONG
*state
)
1268 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1270 TRACE("(%p)->(%p)\n", This
, state
);
1272 if (!state
) return E_INVALIDARG
;
1274 *state
= This
->state
;
1278 static HRESULT WINAPI
httprequest_put_onreadystatechange(IXMLHTTPRequest
*iface
, IDispatch
*sink
)
1280 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1282 TRACE("(%p)->(%p)\n", This
, sink
);
1284 if (This
->sink
) IDispatch_Release(This
->sink
);
1285 if ((This
->sink
= sink
)) IDispatch_AddRef(This
->sink
);
1290 static const struct IXMLHTTPRequestVtbl XMLHTTPRequestVtbl
=
1292 httprequest_QueryInterface
,
1294 httprequest_Release
,
1295 httprequest_GetTypeInfoCount
,
1296 httprequest_GetTypeInfo
,
1297 httprequest_GetIDsOfNames
,
1300 httprequest_setRequestHeader
,
1301 httprequest_getResponseHeader
,
1302 httprequest_getAllResponseHeaders
,
1305 httprequest_get_status
,
1306 httprequest_get_statusText
,
1307 httprequest_get_responseXML
,
1308 httprequest_get_responseText
,
1309 httprequest_get_responseBody
,
1310 httprequest_get_responseStream
,
1311 httprequest_get_readyState
,
1312 httprequest_put_onreadystatechange
1315 /* IObjectWithSite */
1316 static HRESULT WINAPI
1317 httprequest_ObjectWithSite_QueryInterface( IObjectWithSite
* iface
, REFIID riid
, void** ppvObject
)
1319 httprequest
*This
= impl_from_IObjectWithSite(iface
);
1320 return IXMLHTTPRequest_QueryInterface( (IXMLHTTPRequest
*)This
, riid
, ppvObject
);
1323 static ULONG WINAPI
httprequest_ObjectWithSite_AddRef( IObjectWithSite
* iface
)
1325 httprequest
*This
= impl_from_IObjectWithSite(iface
);
1326 return IXMLHTTPRequest_AddRef((IXMLHTTPRequest
*)This
);
1329 static ULONG WINAPI
httprequest_ObjectWithSite_Release( IObjectWithSite
* iface
)
1331 httprequest
*This
= impl_from_IObjectWithSite(iface
);
1332 return IXMLHTTPRequest_Release((IXMLHTTPRequest
*)This
);
1335 static HRESULT WINAPI
httprequest_ObjectWithSite_GetSite( IObjectWithSite
*iface
, REFIID iid
, void **ppvSite
)
1337 httprequest
*This
= impl_from_IObjectWithSite(iface
);
1339 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid( iid
), ppvSite
);
1344 return IUnknown_QueryInterface( This
->site
, iid
, ppvSite
);
1347 static HRESULT WINAPI
httprequest_ObjectWithSite_SetSite( IObjectWithSite
*iface
, IUnknown
*punk
)
1349 httprequest
*This
= impl_from_IObjectWithSite(iface
);
1350 IServiceProvider
*provider
;
1353 TRACE("(%p)->(%p)\n", iface
, punk
);
1356 IUnknown_AddRef( punk
);
1359 IUnknown_Release( This
->site
);
1363 hr
= IUnknown_QueryInterface(This
->site
, &IID_IServiceProvider
, (void**)&provider
);
1366 IHTMLDocument2
*doc
;
1368 hr
= IServiceProvider_QueryService(provider
, &SID_SContainerDispatch
, &IID_IHTMLDocument2
, (void**)&doc
);
1371 SysFreeString(This
->siteurl
);
1373 hr
= IHTMLDocument2_get_URL(doc
, &This
->siteurl
);
1374 IHTMLDocument2_Release(doc
);
1375 TRACE("host url %s, 0x%08x\n", debugstr_w(This
->siteurl
), hr
);
1377 IServiceProvider_Release(provider
);
1383 static const IObjectWithSiteVtbl ObjectWithSiteVtbl
=
1385 httprequest_ObjectWithSite_QueryInterface
,
1386 httprequest_ObjectWithSite_AddRef
,
1387 httprequest_ObjectWithSite_Release
,
1388 httprequest_ObjectWithSite_SetSite
,
1389 httprequest_ObjectWithSite_GetSite
1393 static HRESULT WINAPI
httprequest_Safety_QueryInterface(IObjectSafety
*iface
, REFIID riid
, void **ppv
)
1395 httprequest
*This
= impl_from_IObjectSafety(iface
);
1396 return IXMLHTTPRequest_QueryInterface( (IXMLHTTPRequest
*)This
, riid
, ppv
);
1399 static ULONG WINAPI
httprequest_Safety_AddRef(IObjectSafety
*iface
)
1401 httprequest
*This
= impl_from_IObjectSafety(iface
);
1402 return IXMLHTTPRequest_AddRef((IXMLHTTPRequest
*)This
);
1405 static ULONG WINAPI
httprequest_Safety_Release(IObjectSafety
*iface
)
1407 httprequest
*This
= impl_from_IObjectSafety(iface
);
1408 return IXMLHTTPRequest_Release((IXMLHTTPRequest
*)This
);
1411 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
1413 static HRESULT WINAPI
httprequest_Safety_GetInterfaceSafetyOptions(IObjectSafety
*iface
, REFIID riid
,
1414 DWORD
*supported
, DWORD
*enabled
)
1416 httprequest
*This
= impl_from_IObjectSafety(iface
);
1418 TRACE("(%p)->(%s %p %p)\n", This
, debugstr_guid(riid
), supported
, enabled
);
1420 if(!supported
|| !enabled
) return E_POINTER
;
1422 *supported
= SAFETY_SUPPORTED_OPTIONS
;
1423 *enabled
= This
->safeopt
;
1428 static HRESULT WINAPI
httprequest_Safety_SetInterfaceSafetyOptions(IObjectSafety
*iface
, REFIID riid
,
1429 DWORD mask
, DWORD enabled
)
1431 httprequest
*This
= impl_from_IObjectSafety(iface
);
1432 TRACE("(%p)->(%s %x %x)\n", This
, debugstr_guid(riid
), mask
, enabled
);
1434 if ((mask
& ~SAFETY_SUPPORTED_OPTIONS
) != 0)
1437 This
->safeopt
= (This
->safeopt
& ~mask
) | (mask
& enabled
);
1442 #undef SAFETY_SUPPORTED_OPTIONS
1444 static const IObjectSafetyVtbl ObjectSafetyVtbl
= {
1445 httprequest_Safety_QueryInterface
,
1446 httprequest_Safety_AddRef
,
1447 httprequest_Safety_Release
,
1448 httprequest_Safety_GetInterfaceSafetyOptions
,
1449 httprequest_Safety_SetInterfaceSafetyOptions
1452 HRESULT
XMLHTTPRequest_create(IUnknown
*pUnkOuter
, void **ppObj
)
1457 TRACE("(%p,%p)\n", pUnkOuter
, ppObj
);
1459 req
= heap_alloc( sizeof (*req
) );
1461 return E_OUTOFMEMORY
;
1463 req
->IXMLHTTPRequest_iface
.lpVtbl
= &XMLHTTPRequestVtbl
;
1464 req
->IObjectWithSite_iface
.lpVtbl
= &ObjectWithSiteVtbl
;
1465 req
->IObjectSafety_iface
.lpVtbl
= &ObjectSafetyVtbl
;
1471 req
->url
= req
->siteurl
= req
->user
= req
->password
= NULL
;
1473 req
->state
= READYSTATE_UNINITIALIZED
;
1478 req
->reqheader_size
= 0;
1479 req
->raw_respheaders
= NULL
;
1480 req
->use_utf8_content
= FALSE
;
1482 list_init(&req
->reqheaders
);
1483 list_init(&req
->respheaders
);
1488 *ppObj
= &req
->IXMLHTTPRequest_iface
;
1490 TRACE("returning iface %p\n", *ppObj
);
1497 HRESULT
XMLHTTPRequest_create(IUnknown
*pUnkOuter
, void **ppObj
)
1499 MESSAGE("This program tried to use a XMLHTTPRequest object, but\n"
1500 "libxml2 support was not present at compile time.\n");