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
;
110 static inline httprequest
*impl_from_IXMLHTTPRequest( IXMLHTTPRequest
*iface
)
112 return CONTAINING_RECORD(iface
, httprequest
, IXMLHTTPRequest_iface
);
115 static inline httprequest
*impl_from_IObjectWithSite(IObjectWithSite
*iface
)
117 return CONTAINING_RECORD(iface
, httprequest
, IObjectWithSite_iface
);
120 static inline httprequest
*impl_from_IObjectSafety(IObjectSafety
*iface
)
122 return CONTAINING_RECORD(iface
, httprequest
, IObjectSafety_iface
);
125 static void httprequest_setreadystate(httprequest
*This
, READYSTATE state
)
127 READYSTATE last
= This
->state
;
131 if (This
->sink
&& last
!= state
)
135 memset(¶ms
, 0, sizeof(params
));
136 IDispatch_Invoke(This
->sink
, 0, &IID_NULL
, LOCALE_SYSTEM_DEFAULT
, DISPATCH_METHOD
, ¶ms
, 0, 0, 0);
140 static void free_response_headers(httprequest
*This
)
142 struct httpheader
*header
, *header2
;
144 LIST_FOR_EACH_ENTRY_SAFE(header
, header2
, &This
->respheaders
, struct httpheader
, entry
)
146 list_remove(&header
->entry
);
147 SysFreeString(header
->header
);
148 SysFreeString(header
->value
);
152 SysFreeString(This
->raw_respheaders
);
153 This
->raw_respheaders
= NULL
;
156 struct BindStatusCallback
158 IBindStatusCallback IBindStatusCallback_iface
;
159 IHttpNegotiate IHttpNegotiate_iface
;
160 IAuthenticate IAuthenticate_iface
;
164 httprequest
*request
;
169 /* request body data */
173 static inline BindStatusCallback
*impl_from_IBindStatusCallback( IBindStatusCallback
*iface
)
175 return CONTAINING_RECORD(iface
, BindStatusCallback
, IBindStatusCallback_iface
);
178 static inline BindStatusCallback
*impl_from_IHttpNegotiate( IHttpNegotiate
*iface
)
180 return CONTAINING_RECORD(iface
, BindStatusCallback
, IHttpNegotiate_iface
);
183 static inline BindStatusCallback
*impl_from_IAuthenticate( IAuthenticate
*iface
)
185 return CONTAINING_RECORD(iface
, BindStatusCallback
, IAuthenticate_iface
);
188 static void BindStatusCallback_Detach(BindStatusCallback
*bsc
)
192 if (bsc
->binding
) IBinding_Abort(bsc
->binding
);
194 IBindStatusCallback_Release(&bsc
->IBindStatusCallback_iface
);
198 static HRESULT WINAPI
BindStatusCallback_QueryInterface(IBindStatusCallback
*iface
,
199 REFIID riid
, void **ppv
)
201 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
205 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
207 if (IsEqualGUID(&IID_IUnknown
, riid
) ||
208 IsEqualGUID(&IID_IBindStatusCallback
, riid
))
210 *ppv
= &This
->IBindStatusCallback_iface
;
212 else if (IsEqualGUID(&IID_IHttpNegotiate
, riid
))
214 *ppv
= &This
->IHttpNegotiate_iface
;
216 else if (IsEqualGUID(&IID_IAuthenticate
, riid
))
218 *ppv
= &This
->IAuthenticate_iface
;
220 else if (IsEqualGUID(&IID_IServiceProvider
, riid
) ||
221 IsEqualGUID(&IID_IBindStatusCallbackEx
, riid
) ||
222 IsEqualGUID(&IID_IInternetProtocol
, riid
) ||
223 IsEqualGUID(&IID_IHttpNegotiate2
, riid
))
225 return E_NOINTERFACE
;
230 IBindStatusCallback_AddRef(iface
);
234 FIXME("Unsupported riid = %s\n", debugstr_guid(riid
));
236 return E_NOINTERFACE
;
239 static ULONG WINAPI
BindStatusCallback_AddRef(IBindStatusCallback
*iface
)
241 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
242 LONG ref
= InterlockedIncrement(&This
->ref
);
244 TRACE("(%p) ref = %d\n", This
, ref
);
249 static ULONG WINAPI
BindStatusCallback_Release(IBindStatusCallback
*iface
)
251 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
252 LONG ref
= InterlockedDecrement(&This
->ref
);
254 TRACE("(%p) ref = %d\n", This
, ref
);
258 if (This
->binding
) IBinding_Release(This
->binding
);
259 if (This
->stream
) IStream_Release(This
->stream
);
260 if (This
->body
) GlobalFree(This
->body
);
267 static HRESULT WINAPI
BindStatusCallback_OnStartBinding(IBindStatusCallback
*iface
,
268 DWORD reserved
, IBinding
*pbind
)
270 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
272 TRACE("(%p)->(%d %p)\n", This
, reserved
, pbind
);
274 if (!pbind
) return E_INVALIDARG
;
276 This
->binding
= pbind
;
277 IBinding_AddRef(pbind
);
279 httprequest_setreadystate(This
->request
, READYSTATE_LOADED
);
281 return CreateStreamOnHGlobal(NULL
, TRUE
, &This
->stream
);
284 static HRESULT WINAPI
BindStatusCallback_GetPriority(IBindStatusCallback
*iface
, LONG
*pPriority
)
286 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
288 TRACE("(%p)->(%p)\n", This
, pPriority
);
293 static HRESULT WINAPI
BindStatusCallback_OnLowResource(IBindStatusCallback
*iface
, DWORD reserved
)
295 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
297 TRACE("(%p)->(%d)\n", This
, reserved
);
302 static HRESULT WINAPI
BindStatusCallback_OnProgress(IBindStatusCallback
*iface
, ULONG ulProgress
,
303 ULONG ulProgressMax
, ULONG ulStatusCode
, LPCWSTR szStatusText
)
305 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
307 TRACE("(%p)->(%u %u %u %s)\n", This
, ulProgress
, ulProgressMax
, ulStatusCode
,
308 debugstr_w(szStatusText
));
313 static HRESULT WINAPI
BindStatusCallback_OnStopBinding(IBindStatusCallback
*iface
,
314 HRESULT hr
, LPCWSTR error
)
316 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
318 TRACE("(%p)->(0x%08x %s)\n", This
, hr
, debugstr_w(error
));
322 IBinding_Release(This
->binding
);
323 This
->binding
= NULL
;
327 httprequest_setreadystate(This
->request
, READYSTATE_COMPLETE
);
332 static HRESULT WINAPI
BindStatusCallback_GetBindInfo(IBindStatusCallback
*iface
,
333 DWORD
*bind_flags
, BINDINFO
*pbindinfo
)
335 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
337 TRACE("(%p)->(%p %p)\n", This
, bind_flags
, pbindinfo
);
340 if (This
->request
->async
) *bind_flags
|= BINDF_ASYNCHRONOUS
;
342 if (This
->request
->verb
!= BINDVERB_GET
&& This
->body
)
344 pbindinfo
->stgmedData
.tymed
= TYMED_HGLOBAL
;
345 pbindinfo
->stgmedData
.u
.hGlobal
= This
->body
;
346 pbindinfo
->cbstgmedData
= GlobalSize(This
->body
);
347 /* callback owns passed body pointer */
348 IBindStatusCallback_QueryInterface(iface
, &IID_IUnknown
, (void**)&pbindinfo
->stgmedData
.pUnkForRelease
);
351 pbindinfo
->dwBindVerb
= This
->request
->verb
;
352 if (This
->request
->verb
== BINDVERB_CUSTOM
)
354 pbindinfo
->szCustomVerb
= CoTaskMemAlloc(SysStringByteLen(This
->request
->custom
));
355 strcpyW(pbindinfo
->szCustomVerb
, This
->request
->custom
);
361 static HRESULT WINAPI
BindStatusCallback_OnDataAvailable(IBindStatusCallback
*iface
,
362 DWORD flags
, DWORD size
, FORMATETC
*format
, STGMEDIUM
*stgmed
)
364 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
369 TRACE("(%p)->(%08x %d %p %p)\n", This
, flags
, size
, format
, stgmed
);
373 hr
= IStream_Read(stgmed
->u
.pstm
, buf
, sizeof(buf
), &read
);
374 if (hr
!= S_OK
) break;
376 hr
= IStream_Write(This
->stream
, buf
, read
, &written
);
377 } while((hr
== S_OK
) && written
!= 0 && read
!= 0);
379 httprequest_setreadystate(This
->request
, READYSTATE_INTERACTIVE
);
384 static HRESULT WINAPI
BindStatusCallback_OnObjectAvailable(IBindStatusCallback
*iface
,
385 REFIID riid
, IUnknown
*punk
)
387 BindStatusCallback
*This
= impl_from_IBindStatusCallback(iface
);
389 FIXME("(%p)->(%s %p): stub\n", This
, debugstr_guid(riid
), punk
);
394 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl
= {
395 BindStatusCallback_QueryInterface
,
396 BindStatusCallback_AddRef
,
397 BindStatusCallback_Release
,
398 BindStatusCallback_OnStartBinding
,
399 BindStatusCallback_GetPriority
,
400 BindStatusCallback_OnLowResource
,
401 BindStatusCallback_OnProgress
,
402 BindStatusCallback_OnStopBinding
,
403 BindStatusCallback_GetBindInfo
,
404 BindStatusCallback_OnDataAvailable
,
405 BindStatusCallback_OnObjectAvailable
408 static HRESULT WINAPI
BSCHttpNegotiate_QueryInterface(IHttpNegotiate
*iface
,
409 REFIID riid
, void **ppv
)
411 BindStatusCallback
*This
= impl_from_IHttpNegotiate(iface
);
412 return IBindStatusCallback_QueryInterface(&This
->IBindStatusCallback_iface
, riid
, ppv
);
415 static ULONG WINAPI
BSCHttpNegotiate_AddRef(IHttpNegotiate
*iface
)
417 BindStatusCallback
*This
= impl_from_IHttpNegotiate(iface
);
418 return IBindStatusCallback_AddRef(&This
->IBindStatusCallback_iface
);
421 static ULONG WINAPI
BSCHttpNegotiate_Release(IHttpNegotiate
*iface
)
423 BindStatusCallback
*This
= impl_from_IHttpNegotiate(iface
);
424 return IBindStatusCallback_Release(&This
->IBindStatusCallback_iface
);
427 static HRESULT WINAPI
BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate
*iface
,
428 LPCWSTR url
, LPCWSTR headers
, DWORD reserved
, LPWSTR
*add_headers
)
430 static const WCHAR content_type_utf8W
[] = {'C','o','n','t','e','n','t','-','T','y','p','e',':',' ',
431 't','e','x','t','/','p','l','a','i','n',';','c','h','a','r','s','e','t','=','u','t','f','-','8','\r','\n',0};
433 BindStatusCallback
*This
= impl_from_IHttpNegotiate(iface
);
434 const struct httpheader
*entry
;
438 TRACE("(%p)->(%s %s %d %p)\n", This
, debugstr_w(url
), debugstr_w(headers
), reserved
, add_headers
);
442 if (This
->request
->use_utf8_content
)
443 size
= sizeof(content_type_utf8W
);
445 if (!list_empty(&This
->request
->reqheaders
))
446 size
+= This
->request
->reqheader_size
*sizeof(WCHAR
);
448 if (!size
) return S_OK
;
450 buff
= CoTaskMemAlloc(size
);
451 if (!buff
) return E_OUTOFMEMORY
;
454 if (This
->request
->use_utf8_content
)
456 lstrcpyW(ptr
, content_type_utf8W
);
457 ptr
+= sizeof(content_type_utf8W
)/sizeof(WCHAR
)-1;
461 LIST_FOR_EACH_ENTRY(entry
, &This
->request
->reqheaders
, struct httpheader
, entry
)
463 lstrcpyW(ptr
, entry
->header
);
464 ptr
+= SysStringLen(entry
->header
);
466 lstrcpyW(ptr
, colspaceW
);
467 ptr
+= sizeof(colspaceW
)/sizeof(WCHAR
)-1;
469 lstrcpyW(ptr
, entry
->value
);
470 ptr
+= SysStringLen(entry
->value
);
472 lstrcpyW(ptr
, crlfW
);
473 ptr
+= sizeof(crlfW
)/sizeof(WCHAR
)-1;
481 static void add_response_header(httprequest
*This
, const WCHAR
*data
, int len
)
483 struct httpheader
*entry
;
484 const WCHAR
*ptr
= data
;
491 header
= SysAllocStringLen(data
, ptr
-data
);
492 /* skip leading spaces for a value */
493 while (*++ptr
== ' ')
495 value
= SysAllocStringLen(ptr
, len
-(ptr
-data
));
504 TRACE("got header %s:%s\n", debugstr_w(header
), debugstr_w(value
));
506 entry
= heap_alloc(sizeof(*entry
));
507 entry
->header
= header
;
508 entry
->value
= value
;
509 list_add_head(&This
->respheaders
, &entry
->entry
);
512 static HRESULT WINAPI
BSCHttpNegotiate_OnResponse(IHttpNegotiate
*iface
, DWORD code
,
513 LPCWSTR resp_headers
, LPCWSTR req_headers
, LPWSTR
*add_reqheaders
)
515 BindStatusCallback
*This
= impl_from_IHttpNegotiate(iface
);
517 TRACE("(%p)->(%d %s %s %p)\n", This
, code
, debugstr_w(resp_headers
),
518 debugstr_w(req_headers
), add_reqheaders
);
520 This
->request
->status
= code
;
521 /* store headers and status text */
522 free_response_headers(This
->request
);
523 SysFreeString(This
->request
->status_text
);
524 This
->request
->status_text
= NULL
;
527 const WCHAR
*ptr
, *line
;
529 ptr
= line
= resp_headers
;
531 /* skip status line */
534 if (*ptr
== '\r' && *(ptr
+1) == '\n')
536 const WCHAR
*end
= ptr
-1;
538 /* scan back to get status phrase */
539 while (ptr
> resp_headers
)
543 This
->request
->status_text
= SysAllocStringLen(ptr
+1, end
-ptr
);
544 TRACE("status text %s\n", debugstr_w(This
->request
->status_text
));
554 /* store as unparsed string for now */
555 This
->request
->raw_respheaders
= SysAllocString(line
);
561 static const IHttpNegotiateVtbl BSCHttpNegotiateVtbl
= {
562 BSCHttpNegotiate_QueryInterface
,
563 BSCHttpNegotiate_AddRef
,
564 BSCHttpNegotiate_Release
,
565 BSCHttpNegotiate_BeginningTransaction
,
566 BSCHttpNegotiate_OnResponse
569 static HRESULT WINAPI
Authenticate_QueryInterface(IAuthenticate
*iface
,
570 REFIID riid
, void **ppv
)
572 BindStatusCallback
*This
= impl_from_IAuthenticate(iface
);
573 return IBindStatusCallback_QueryInterface(&This
->IBindStatusCallback_iface
, riid
, ppv
);
576 static ULONG WINAPI
Authenticate_AddRef(IAuthenticate
*iface
)
578 BindStatusCallback
*This
= impl_from_IAuthenticate(iface
);
579 return IBindStatusCallback_AddRef(&This
->IBindStatusCallback_iface
);
582 static ULONG WINAPI
Authenticate_Release(IAuthenticate
*iface
)
584 BindStatusCallback
*This
= impl_from_IAuthenticate(iface
);
585 return IBindStatusCallback_Release(&This
->IBindStatusCallback_iface
);
588 static HRESULT WINAPI
Authenticate_Authenticate(IAuthenticate
*iface
,
589 HWND
*hwnd
, LPWSTR
*username
, LPWSTR
*password
)
591 BindStatusCallback
*This
= impl_from_IAuthenticate(iface
);
592 FIXME("(%p)->(%p %p %p)\n", This
, hwnd
, username
, password
);
596 static const IAuthenticateVtbl AuthenticateVtbl
= {
597 Authenticate_QueryInterface
,
599 Authenticate_Release
,
600 Authenticate_Authenticate
603 static HRESULT
BindStatusCallback_create(httprequest
* This
, BindStatusCallback
**obj
, const VARIANT
*body
)
605 BindStatusCallback
*bsc
;
610 hr
= CreateBindCtx(0, &pbc
);
611 if (hr
!= S_OK
) return hr
;
613 bsc
= heap_alloc(sizeof(*bsc
));
616 IBindCtx_Release(pbc
);
617 return E_OUTOFMEMORY
;
620 bsc
->IBindStatusCallback_iface
.lpVtbl
= &BindStatusCallbackVtbl
;
621 bsc
->IHttpNegotiate_iface
.lpVtbl
= &BSCHttpNegotiateVtbl
;
622 bsc
->IAuthenticate_iface
.lpVtbl
= &AuthenticateVtbl
;
629 TRACE("(%p)->(%p)\n", This
, bsc
);
631 This
->use_utf8_content
= FALSE
;
633 if (This
->verb
!= BINDVERB_GET
)
635 void *send_data
, *ptr
;
636 SAFEARRAY
*sa
= NULL
;
638 if (V_VT(body
) == (VT_VARIANT
|VT_BYREF
))
639 body
= V_VARIANTREF(body
);
645 int len
= SysStringLen(V_BSTR(body
));
646 const WCHAR
*str
= V_BSTR(body
);
649 for (i
= 0; i
< len
; i
++)
658 size
= WideCharToMultiByte(cp
, 0, str
, len
, NULL
, 0, NULL
, NULL
);
659 if (!(ptr
= heap_alloc(size
)))
662 return E_OUTOFMEMORY
;
664 WideCharToMultiByte(cp
, 0, str
, len
, ptr
, size
, NULL
, NULL
);
665 if (cp
== CP_UTF8
) This
->use_utf8_content
= TRUE
;
668 case VT_ARRAY
|VT_UI1
:
671 if ((hr
= SafeArrayAccessData(sa
, (void **)&ptr
)) != S_OK
) return hr
;
672 if ((hr
= SafeArrayGetUBound(sa
, 1, &size
) != S_OK
))
674 SafeArrayUnaccessData(sa
);
685 FIXME("unsupported body data type %d\n", V_VT(body
));
689 bsc
->body
= GlobalAlloc(GMEM_FIXED
, size
);
692 if (V_VT(body
) == VT_BSTR
)
694 else if (V_VT(body
) == (VT_ARRAY
|VT_UI1
))
695 SafeArrayUnaccessData(sa
);
698 return E_OUTOFMEMORY
;
701 send_data
= GlobalLock(bsc
->body
);
702 memcpy(send_data
, ptr
, size
);
703 GlobalUnlock(bsc
->body
);
705 if (V_VT(body
) == VT_BSTR
)
707 else if (V_VT(body
) == (VT_ARRAY
|VT_UI1
))
708 SafeArrayUnaccessData(sa
);
711 hr
= RegisterBindStatusCallback(pbc
, &bsc
->IBindStatusCallback_iface
, NULL
, 0);
716 hr
= CreateURLMoniker(NULL
, This
->url
, &moniker
);
721 hr
= IMoniker_BindToStorage(moniker
, pbc
, NULL
, &IID_IStream
, (void**)&stream
);
722 IMoniker_Release(moniker
);
723 if (stream
) IStream_Release(stream
);
725 IBindCtx_Release(pbc
);
730 IBindStatusCallback_Release(&bsc
->IBindStatusCallback_iface
);
738 static HRESULT WINAPI
httprequest_QueryInterface(IXMLHTTPRequest
*iface
, REFIID riid
, void **ppvObject
)
740 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
741 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
743 if ( IsEqualGUID( riid
, &IID_IXMLHTTPRequest
) ||
744 IsEqualGUID( riid
, &IID_IDispatch
) ||
745 IsEqualGUID( riid
, &IID_IUnknown
) )
749 else if (IsEqualGUID(&IID_IObjectWithSite
, riid
))
751 *ppvObject
= &This
->IObjectWithSite_iface
;
753 else if (IsEqualGUID(&IID_IObjectSafety
, riid
))
755 *ppvObject
= &This
->IObjectSafety_iface
;
759 TRACE("Unsupported interface %s\n", debugstr_guid(riid
));
761 return E_NOINTERFACE
;
764 IXMLHTTPRequest_AddRef( iface
);
769 static ULONG WINAPI
httprequest_AddRef(IXMLHTTPRequest
*iface
)
771 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
772 ULONG ref
= InterlockedIncrement( &This
->ref
);
773 TRACE("(%p)->(%u)\n", This
, ref
);
777 static ULONG WINAPI
httprequest_Release(IXMLHTTPRequest
*iface
)
779 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
780 ULONG ref
= InterlockedDecrement( &This
->ref
);
782 TRACE("(%p)->(%u)\n", This
, ref
);
786 struct httpheader
*header
, *header2
;
789 IUnknown_Release( This
->site
);
791 SysFreeString(This
->custom
);
792 SysFreeString(This
->siteurl
);
793 SysFreeString(This
->url
);
794 SysFreeString(This
->user
);
795 SysFreeString(This
->password
);
797 /* request headers */
798 LIST_FOR_EACH_ENTRY_SAFE(header
, header2
, &This
->reqheaders
, struct httpheader
, entry
)
800 list_remove(&header
->entry
);
801 SysFreeString(header
->header
);
802 SysFreeString(header
->value
);
805 /* response headers */
806 free_response_headers(This
);
807 SysFreeString(This
->status_text
);
809 /* detach callback object */
810 BindStatusCallback_Detach(This
->bsc
);
812 if (This
->sink
) IDispatch_Release(This
->sink
);
820 static HRESULT WINAPI
httprequest_GetTypeInfoCount(IXMLHTTPRequest
*iface
, UINT
*pctinfo
)
822 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
824 TRACE("(%p)->(%p)\n", This
, pctinfo
);
831 static HRESULT WINAPI
httprequest_GetTypeInfo(IXMLHTTPRequest
*iface
, UINT iTInfo
,
832 LCID lcid
, ITypeInfo
**ppTInfo
)
834 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
836 TRACE("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
838 return get_typeinfo(IXMLHTTPRequest_tid
, ppTInfo
);
841 static HRESULT WINAPI
httprequest_GetIDsOfNames(IXMLHTTPRequest
*iface
, REFIID riid
,
842 LPOLESTR
*rgszNames
, UINT cNames
, LCID lcid
, DISPID
*rgDispId
)
844 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
848 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
851 if(!rgszNames
|| cNames
== 0 || !rgDispId
)
854 hr
= get_typeinfo(IXMLHTTPRequest_tid
, &typeinfo
);
857 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
858 ITypeInfo_Release(typeinfo
);
864 static HRESULT WINAPI
httprequest_Invoke(IXMLHTTPRequest
*iface
, DISPID dispIdMember
, REFIID riid
,
865 LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
,
866 EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
868 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
872 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
873 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
875 hr
= get_typeinfo(IXMLHTTPRequest_tid
, &typeinfo
);
878 hr
= ITypeInfo_Invoke(typeinfo
, &This
->IXMLHTTPRequest_iface
, dispIdMember
, wFlags
,
879 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
880 ITypeInfo_Release(typeinfo
);
886 static HRESULT WINAPI
httprequest_open(IXMLHTTPRequest
*iface
, BSTR method
, BSTR url
,
887 VARIANT async
, VARIANT user
, VARIANT password
)
889 static const WCHAR MethodGetW
[] = {'G','E','T',0};
890 static const WCHAR MethodPutW
[] = {'P','U','T',0};
891 static const WCHAR MethodPostW
[] = {'P','O','S','T',0};
892 static const WCHAR MethodDeleteW
[] = {'D','E','L','E','T','E',0};
894 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
895 VARIANT str
, is_async
;
898 TRACE("(%p)->(%s %s %s)\n", This
, debugstr_w(method
), debugstr_w(url
),
899 debugstr_variant(&async
));
901 if (!method
|| !url
) return E_INVALIDARG
;
903 /* free previously set data */
904 SysFreeString(This
->url
);
905 SysFreeString(This
->user
);
906 SysFreeString(This
->password
);
907 This
->url
= This
->user
= This
->password
= NULL
;
909 if (!strcmpiW(method
, MethodGetW
))
911 This
->verb
= BINDVERB_GET
;
913 else if (!strcmpiW(method
, MethodPutW
))
915 This
->verb
= BINDVERB_PUT
;
917 else if (!strcmpiW(method
, MethodPostW
))
919 This
->verb
= BINDVERB_POST
;
921 else if (!strcmpiW(method
, MethodDeleteW
))
923 This
->verb
= BINDVERB_CUSTOM
;
924 SysReAllocString(&This
->custom
, method
);
928 FIXME("unsupported request type %s\n", debugstr_w(method
));
933 /* try to combine with site url */
934 if (This
->siteurl
&& PathIsRelativeW(url
))
936 DWORD len
= INTERNET_MAX_URL_LENGTH
;
937 WCHAR
*fullW
= heap_alloc(len
*sizeof(WCHAR
));
939 hr
= UrlCombineW(This
->siteurl
, url
, fullW
, &len
, 0);
942 TRACE("combined url %s\n", debugstr_w(fullW
));
943 This
->url
= SysAllocString(fullW
);
948 This
->url
= SysAllocString(url
);
950 VariantInit(&is_async
);
951 hr
= VariantChangeType(&is_async
, &async
, 0, VT_BOOL
);
952 This
->async
= hr
== S_OK
&& V_BOOL(&is_async
) == VARIANT_TRUE
;
955 hr
= VariantChangeType(&str
, &user
, 0, VT_BSTR
);
957 This
->user
= V_BSTR(&str
);
960 hr
= VariantChangeType(&str
, &password
, 0, VT_BSTR
);
962 This
->password
= V_BSTR(&str
);
964 httprequest_setreadystate(This
, READYSTATE_LOADING
);
969 static HRESULT WINAPI
httprequest_setRequestHeader(IXMLHTTPRequest
*iface
, BSTR header
, BSTR value
)
971 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
972 struct httpheader
*entry
;
974 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(header
), debugstr_w(value
));
976 if (!header
|| !*header
) return E_INVALIDARG
;
977 if (This
->state
!= READYSTATE_LOADING
) return E_FAIL
;
978 if (!value
) return E_INVALIDARG
;
980 /* replace existing header value if already added */
981 LIST_FOR_EACH_ENTRY(entry
, &This
->reqheaders
, struct httpheader
, entry
)
983 if (lstrcmpW(entry
->header
, header
) == 0)
985 LONG length
= SysStringLen(entry
->value
);
988 hr
= SysReAllocString(&entry
->value
, value
) ? S_OK
: E_OUTOFMEMORY
;
991 This
->reqheader_size
+= (SysStringLen(entry
->value
) - length
);
997 entry
= heap_alloc(sizeof(*entry
));
998 if (!entry
) return E_OUTOFMEMORY
;
1001 entry
->header
= SysAllocString(header
);
1002 entry
->value
= SysAllocString(value
);
1004 /* header length including null terminator */
1005 This
->reqheader_size
+= SysStringLen(entry
->header
) + sizeof(colspaceW
)/sizeof(WCHAR
) +
1006 SysStringLen(entry
->value
) + sizeof(crlfW
)/sizeof(WCHAR
) - 1;
1008 list_add_head(&This
->reqheaders
, &entry
->entry
);
1013 static HRESULT WINAPI
httprequest_getResponseHeader(IXMLHTTPRequest
*iface
, BSTR header
, BSTR
*value
)
1015 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1016 struct httpheader
*entry
;
1018 TRACE("(%p)->(%s %p)\n", This
, debugstr_w(header
), value
);
1020 if (!header
|| !value
) return E_INVALIDARG
;
1022 if (This
->raw_respheaders
&& list_empty(&This
->respheaders
))
1026 ptr
= line
= This
->raw_respheaders
;
1029 if (*ptr
== '\r' && *(ptr
+1) == '\n')
1031 add_response_header(This
, line
, ptr
-line
);
1032 ptr
++; line
= ++ptr
;
1039 LIST_FOR_EACH_ENTRY(entry
, &This
->respheaders
, struct httpheader
, entry
)
1041 if (!strcmpiW(entry
->header
, header
))
1043 *value
= SysAllocString(entry
->value
);
1044 TRACE("header value %s\n", debugstr_w(*value
));
1052 static HRESULT WINAPI
httprequest_getAllResponseHeaders(IXMLHTTPRequest
*iface
, BSTR
*respheaders
)
1054 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1056 TRACE("(%p)->(%p)\n", This
, respheaders
);
1058 if (!respheaders
) return E_INVALIDARG
;
1060 *respheaders
= SysAllocString(This
->raw_respheaders
);
1065 static HRESULT WINAPI
httprequest_send(IXMLHTTPRequest
*iface
, VARIANT body
)
1067 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1068 BindStatusCallback
*bsc
= NULL
;
1071 TRACE("(%p)->(%s)\n", This
, debugstr_variant(&body
));
1073 if (This
->state
!= READYSTATE_LOADING
) return E_FAIL
;
1075 hr
= BindStatusCallback_create(This
, &bsc
, &body
);
1076 if (FAILED(hr
)) return hr
;
1078 BindStatusCallback_Detach(This
->bsc
);
1084 static HRESULT WINAPI
httprequest_abort(IXMLHTTPRequest
*iface
)
1086 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1088 TRACE("(%p)\n", This
);
1090 BindStatusCallback_Detach(This
->bsc
);
1093 httprequest_setreadystate(This
, READYSTATE_UNINITIALIZED
);
1098 static HRESULT WINAPI
httprequest_get_status(IXMLHTTPRequest
*iface
, LONG
*status
)
1100 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1102 TRACE("(%p)->(%p)\n", This
, status
);
1104 if (!status
) return E_INVALIDARG
;
1105 if (This
->state
!= READYSTATE_COMPLETE
) return E_FAIL
;
1107 *status
= This
->status
;
1112 static HRESULT WINAPI
httprequest_get_statusText(IXMLHTTPRequest
*iface
, BSTR
*status
)
1114 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1116 TRACE("(%p)->(%p)\n", This
, status
);
1118 if (!status
) return E_INVALIDARG
;
1119 if (This
->state
!= READYSTATE_COMPLETE
) return E_FAIL
;
1121 *status
= SysAllocString(This
->status_text
);
1126 static HRESULT WINAPI
httprequest_get_responseXML(IXMLHTTPRequest
*iface
, IDispatch
**body
)
1128 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1129 IXMLDOMDocument3
*doc
;
1133 TRACE("(%p)->(%p)\n", This
, body
);
1135 if (!body
) return E_INVALIDARG
;
1136 if (This
->state
!= READYSTATE_COMPLETE
) return E_FAIL
;
1138 hr
= DOMDocument_create(MSXML_DEFAULT
, NULL
, (void**)&doc
);
1139 if (hr
!= S_OK
) return hr
;
1141 hr
= IXMLHTTPRequest_get_responseText(iface
, &str
);
1146 hr
= IXMLDOMDocument3_loadXML(doc
, str
, &ok
);
1150 IXMLDOMDocument3_QueryInterface(doc
, &IID_IDispatch
, (void**)body
);
1151 IXMLDOMDocument3_Release(doc
);
1156 static HRESULT WINAPI
httprequest_get_responseText(IXMLHTTPRequest
*iface
, BSTR
*body
)
1158 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1162 TRACE("(%p)->(%p)\n", This
, body
);
1164 if (!body
) return E_INVALIDARG
;
1165 if (This
->state
!= READYSTATE_COMPLETE
) return E_FAIL
;
1167 hr
= GetHGlobalFromStream(This
->bsc
->stream
, &hglobal
);
1170 xmlChar
*ptr
= GlobalLock(hglobal
);
1171 DWORD size
= GlobalSize(hglobal
);
1172 xmlCharEncoding encoding
= XML_CHAR_ENCODING_UTF8
;
1174 /* try to determine data encoding */
1177 encoding
= xmlDetectCharEncoding(ptr
, 4);
1178 TRACE("detected encoding: %s\n", debugstr_a(xmlGetCharEncodingName(encoding
)));
1179 if ( encoding
!= XML_CHAR_ENCODING_UTF8
&&
1180 encoding
!= XML_CHAR_ENCODING_UTF16LE
&&
1181 encoding
!= XML_CHAR_ENCODING_NONE
)
1183 FIXME("unsupported encoding: %s\n", debugstr_a(xmlGetCharEncodingName(encoding
)));
1184 GlobalUnlock(hglobal
);
1189 /* without BOM assume UTF-8 */
1190 if (encoding
== XML_CHAR_ENCODING_UTF8
||
1191 encoding
== XML_CHAR_ENCODING_NONE
)
1193 DWORD length
= MultiByteToWideChar(CP_UTF8
, 0, (LPCSTR
)ptr
, size
, NULL
, 0);
1195 *body
= SysAllocStringLen(NULL
, length
);
1197 MultiByteToWideChar( CP_UTF8
, 0, (LPCSTR
)ptr
, size
, *body
, length
);
1200 *body
= SysAllocStringByteLen((LPCSTR
)ptr
, size
);
1202 if (!*body
) hr
= E_OUTOFMEMORY
;
1203 GlobalUnlock(hglobal
);
1209 static HRESULT WINAPI
httprequest_get_responseBody(IXMLHTTPRequest
*iface
, VARIANT
*body
)
1211 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1215 TRACE("(%p)->(%p)\n", This
, body
);
1217 if (!body
) return E_INVALIDARG
;
1218 V_VT(body
) = VT_EMPTY
;
1220 if (This
->state
!= READYSTATE_COMPLETE
) return E_PENDING
;
1222 hr
= GetHGlobalFromStream(This
->bsc
->stream
, &hglobal
);
1225 void *ptr
= GlobalLock(hglobal
);
1226 DWORD size
= GlobalSize(hglobal
);
1228 SAFEARRAYBOUND bound
;
1232 bound
.cElements
= size
;
1233 array
= SafeArrayCreate(VT_UI1
, 1, &bound
);
1239 V_VT(body
) = VT_ARRAY
| VT_UI1
;
1240 V_ARRAY(body
) = array
;
1242 hr
= SafeArrayAccessData(array
, &dest
);
1245 memcpy(dest
, ptr
, size
);
1246 SafeArrayUnaccessData(array
);
1256 GlobalUnlock(hglobal
);
1262 static HRESULT WINAPI
httprequest_get_responseStream(IXMLHTTPRequest
*iface
, VARIANT
*body
)
1264 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1269 TRACE("(%p)->(%p)\n", This
, body
);
1271 if (!body
) return E_INVALIDARG
;
1272 V_VT(body
) = VT_EMPTY
;
1274 if (This
->state
!= READYSTATE_COMPLETE
) return E_PENDING
;
1276 hr
= IStream_Clone(This
->bsc
->stream
, &stream
);
1279 IStream_Seek(stream
, move
, STREAM_SEEK_SET
, NULL
);
1281 V_VT(body
) = VT_UNKNOWN
;
1282 V_UNKNOWN(body
) = (IUnknown
*)stream
;
1287 static HRESULT WINAPI
httprequest_get_readyState(IXMLHTTPRequest
*iface
, LONG
*state
)
1289 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1291 TRACE("(%p)->(%p)\n", This
, state
);
1293 if (!state
) return E_INVALIDARG
;
1295 *state
= This
->state
;
1299 static HRESULT WINAPI
httprequest_put_onreadystatechange(IXMLHTTPRequest
*iface
, IDispatch
*sink
)
1301 httprequest
*This
= impl_from_IXMLHTTPRequest( iface
);
1303 TRACE("(%p)->(%p)\n", This
, sink
);
1305 if (This
->sink
) IDispatch_Release(This
->sink
);
1306 if ((This
->sink
= sink
)) IDispatch_AddRef(This
->sink
);
1311 static const struct IXMLHTTPRequestVtbl XMLHTTPRequestVtbl
=
1313 httprequest_QueryInterface
,
1315 httprequest_Release
,
1316 httprequest_GetTypeInfoCount
,
1317 httprequest_GetTypeInfo
,
1318 httprequest_GetIDsOfNames
,
1321 httprequest_setRequestHeader
,
1322 httprequest_getResponseHeader
,
1323 httprequest_getAllResponseHeaders
,
1326 httprequest_get_status
,
1327 httprequest_get_statusText
,
1328 httprequest_get_responseXML
,
1329 httprequest_get_responseText
,
1330 httprequest_get_responseBody
,
1331 httprequest_get_responseStream
,
1332 httprequest_get_readyState
,
1333 httprequest_put_onreadystatechange
1336 /* IObjectWithSite */
1337 static HRESULT WINAPI
1338 httprequest_ObjectWithSite_QueryInterface( IObjectWithSite
* iface
, REFIID riid
, void** ppvObject
)
1340 httprequest
*This
= impl_from_IObjectWithSite(iface
);
1341 return IXMLHTTPRequest_QueryInterface( (IXMLHTTPRequest
*)This
, riid
, ppvObject
);
1344 static ULONG WINAPI
httprequest_ObjectWithSite_AddRef( IObjectWithSite
* iface
)
1346 httprequest
*This
= impl_from_IObjectWithSite(iface
);
1347 return IXMLHTTPRequest_AddRef((IXMLHTTPRequest
*)This
);
1350 static ULONG WINAPI
httprequest_ObjectWithSite_Release( IObjectWithSite
* iface
)
1352 httprequest
*This
= impl_from_IObjectWithSite(iface
);
1353 return IXMLHTTPRequest_Release((IXMLHTTPRequest
*)This
);
1356 static HRESULT WINAPI
httprequest_ObjectWithSite_GetSite( IObjectWithSite
*iface
, REFIID iid
, void **ppvSite
)
1358 httprequest
*This
= impl_from_IObjectWithSite(iface
);
1360 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid( iid
), ppvSite
);
1365 return IUnknown_QueryInterface( This
->site
, iid
, ppvSite
);
1368 static HRESULT WINAPI
httprequest_ObjectWithSite_SetSite( IObjectWithSite
*iface
, IUnknown
*punk
)
1370 httprequest
*This
= impl_from_IObjectWithSite(iface
);
1371 IServiceProvider
*provider
;
1374 TRACE("(%p)->(%p)\n", iface
, punk
);
1377 IUnknown_AddRef( punk
);
1380 IUnknown_Release( This
->site
);
1384 hr
= IUnknown_QueryInterface(This
->site
, &IID_IServiceProvider
, (void**)&provider
);
1387 IHTMLDocument2
*doc
;
1389 hr
= IServiceProvider_QueryService(provider
, &SID_SContainerDispatch
, &IID_IHTMLDocument2
, (void**)&doc
);
1392 SysFreeString(This
->siteurl
);
1394 hr
= IHTMLDocument2_get_URL(doc
, &This
->siteurl
);
1395 IHTMLDocument2_Release(doc
);
1396 TRACE("host url %s, 0x%08x\n", debugstr_w(This
->siteurl
), hr
);
1398 IServiceProvider_Release(provider
);
1404 static const IObjectWithSiteVtbl ObjectWithSiteVtbl
=
1406 httprequest_ObjectWithSite_QueryInterface
,
1407 httprequest_ObjectWithSite_AddRef
,
1408 httprequest_ObjectWithSite_Release
,
1409 httprequest_ObjectWithSite_SetSite
,
1410 httprequest_ObjectWithSite_GetSite
1414 static HRESULT WINAPI
httprequest_Safety_QueryInterface(IObjectSafety
*iface
, REFIID riid
, void **ppv
)
1416 httprequest
*This
= impl_from_IObjectSafety(iface
);
1417 return IXMLHTTPRequest_QueryInterface( (IXMLHTTPRequest
*)This
, riid
, ppv
);
1420 static ULONG WINAPI
httprequest_Safety_AddRef(IObjectSafety
*iface
)
1422 httprequest
*This
= impl_from_IObjectSafety(iface
);
1423 return IXMLHTTPRequest_AddRef((IXMLHTTPRequest
*)This
);
1426 static ULONG WINAPI
httprequest_Safety_Release(IObjectSafety
*iface
)
1428 httprequest
*This
= impl_from_IObjectSafety(iface
);
1429 return IXMLHTTPRequest_Release((IXMLHTTPRequest
*)This
);
1432 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
1434 static HRESULT WINAPI
httprequest_Safety_GetInterfaceSafetyOptions(IObjectSafety
*iface
, REFIID riid
,
1435 DWORD
*supported
, DWORD
*enabled
)
1437 httprequest
*This
= impl_from_IObjectSafety(iface
);
1439 TRACE("(%p)->(%s %p %p)\n", This
, debugstr_guid(riid
), supported
, enabled
);
1441 if(!supported
|| !enabled
) return E_POINTER
;
1443 *supported
= SAFETY_SUPPORTED_OPTIONS
;
1444 *enabled
= This
->safeopt
;
1449 static HRESULT WINAPI
httprequest_Safety_SetInterfaceSafetyOptions(IObjectSafety
*iface
, REFIID riid
,
1450 DWORD mask
, DWORD enabled
)
1452 httprequest
*This
= impl_from_IObjectSafety(iface
);
1453 TRACE("(%p)->(%s %x %x)\n", This
, debugstr_guid(riid
), mask
, enabled
);
1455 if ((mask
& ~SAFETY_SUPPORTED_OPTIONS
) != 0)
1458 This
->safeopt
= (This
->safeopt
& ~mask
) | (mask
& enabled
);
1463 #undef SAFETY_SUPPORTED_OPTIONS
1465 static const IObjectSafetyVtbl ObjectSafetyVtbl
= {
1466 httprequest_Safety_QueryInterface
,
1467 httprequest_Safety_AddRef
,
1468 httprequest_Safety_Release
,
1469 httprequest_Safety_GetInterfaceSafetyOptions
,
1470 httprequest_Safety_SetInterfaceSafetyOptions
1473 HRESULT
XMLHTTPRequest_create(IUnknown
*pUnkOuter
, void **ppObj
)
1478 TRACE("(%p,%p)\n", pUnkOuter
, ppObj
);
1480 req
= heap_alloc( sizeof (*req
) );
1482 return E_OUTOFMEMORY
;
1484 req
->IXMLHTTPRequest_iface
.lpVtbl
= &XMLHTTPRequestVtbl
;
1485 req
->IObjectWithSite_iface
.lpVtbl
= &ObjectWithSiteVtbl
;
1486 req
->IObjectSafety_iface
.lpVtbl
= &ObjectSafetyVtbl
;
1492 req
->url
= req
->siteurl
= req
->user
= req
->password
= NULL
;
1494 req
->state
= READYSTATE_UNINITIALIZED
;
1499 req
->status_text
= NULL
;
1500 req
->reqheader_size
= 0;
1501 req
->raw_respheaders
= NULL
;
1502 req
->use_utf8_content
= FALSE
;
1504 list_init(&req
->reqheaders
);
1505 list_init(&req
->respheaders
);
1510 *ppObj
= &req
->IXMLHTTPRequest_iface
;
1512 TRACE("returning iface %p\n", *ppObj
);
1519 HRESULT
XMLHTTPRequest_create(IUnknown
*pUnkOuter
, void **ppObj
)
1521 MESSAGE("This program tried to use a XMLHTTPRequest object, but\n"
1522 "libxml2 support was not present at compile time.\n");