msvcp90: Don't define empty structure.
[wine/multimedia.git] / dlls / msxml3 / httprequest.c
blob32cfc2c6f1ad02db098568fd54eabcb961d053f8
1 /*
2 * IXMLHTTPRequest implementation
4 * Copyright 2008 Alistair Leslie-Hughes
5 * Copyright 2010 Nikolay Sivov for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
23 #define NONAMELESSUNION
25 #include "config.h"
27 #include <stdarg.h>
28 #ifdef HAVE_LIBXML2
29 # include <libxml/parser.h>
30 # include <libxml/xmlerror.h>
31 # include <libxml/encoding.h>
32 #endif
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winuser.h"
37 #include "ole2.h"
38 #include "msxml6.h"
39 #include "objsafe.h"
41 #include "msxml_private.h"
43 #include "wine/debug.h"
44 #include "wine/list.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
48 #ifdef HAVE_LIBXML2
50 static const WCHAR MethodGetW[] = {'G','E','T',0};
51 static const WCHAR MethodPutW[] = {'P','U','T',0};
52 static const WCHAR MethodPostW[] = {'P','O','S','T',0};
54 static const WCHAR colspaceW[] = {':',' ',0};
55 static const WCHAR crlfW[] = {'\r','\n',0};
57 typedef struct BindStatusCallback BindStatusCallback;
59 struct reqheader
61 struct list entry;
62 BSTR header;
63 BSTR value;
66 typedef struct
68 IXMLHTTPRequest IXMLHTTPRequest_iface;
69 IObjectWithSite IObjectWithSite_iface;
70 IObjectSafety IObjectSafety_iface;
71 LONG ref;
73 READYSTATE state;
74 IDispatch *sink;
76 /* request */
77 BINDVERB verb;
78 BSTR url;
79 BOOL async;
80 struct list reqheaders;
81 /* cached resulting custom request headers string length in WCHARs */
82 LONG reqheader_size;
84 /* credentials */
85 BSTR user;
86 BSTR password;
88 /* bind callback */
89 BindStatusCallback *bsc;
90 LONG status;
92 /* IObjectWithSite*/
93 IUnknown *site;
95 /* IObjectSafety */
96 DWORD safeopt;
97 } httprequest;
99 static inline httprequest *impl_from_IXMLHTTPRequest( IXMLHTTPRequest *iface )
101 return CONTAINING_RECORD(iface, httprequest, IXMLHTTPRequest_iface);
104 static inline httprequest *impl_from_IObjectWithSite(IObjectWithSite *iface)
106 return CONTAINING_RECORD(iface, httprequest, IObjectWithSite_iface);
109 static inline httprequest *impl_from_IObjectSafety(IObjectSafety *iface)
111 return CONTAINING_RECORD(iface, httprequest, IObjectSafety_iface);
114 static void httprequest_setreadystate(httprequest *This, READYSTATE state)
116 READYSTATE last = This->state;
118 This->state = state;
120 if (This->sink && last != state)
122 DISPPARAMS params;
124 memset(&params, 0, sizeof(params));
125 IDispatch_Invoke(This->sink, 0, &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &params, 0, 0, 0);
129 struct BindStatusCallback
131 IBindStatusCallback IBindStatusCallback_iface;
132 IHttpNegotiate IHttpNegotiate_iface;
133 LONG ref;
135 IBinding *binding;
136 httprequest *request;
138 /* response data */
139 IStream *stream;
141 /* request body data */
142 HGLOBAL body;
145 static inline BindStatusCallback *impl_from_IBindStatusCallback( IBindStatusCallback *iface )
147 return CONTAINING_RECORD(iface, BindStatusCallback, IBindStatusCallback_iface);
150 static inline BindStatusCallback *impl_from_IHttpNegotiate( IHttpNegotiate *iface )
152 return CONTAINING_RECORD(iface, BindStatusCallback, IHttpNegotiate_iface);
155 static void BindStatusCallback_Detach(BindStatusCallback *bsc)
157 if (bsc)
159 if (bsc->binding) IBinding_Abort(bsc->binding);
160 bsc->request = NULL;
161 IBindStatusCallback_Release(&bsc->IBindStatusCallback_iface);
165 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
166 REFIID riid, void **ppv)
168 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
170 *ppv = NULL;
172 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
174 if (IsEqualGUID(&IID_IUnknown, riid) ||
175 IsEqualGUID(&IID_IBindStatusCallback, riid))
177 *ppv = &This->IBindStatusCallback_iface;
179 else if (IsEqualGUID(&IID_IHttpNegotiate, riid))
181 *ppv = &This->IHttpNegotiate_iface;
183 else if (IsEqualGUID(&IID_IServiceProvider, riid) ||
184 IsEqualGUID(&IID_IBindStatusCallbackEx, riid) ||
185 IsEqualGUID(&IID_IInternetProtocol, riid) ||
186 IsEqualGUID(&IID_IHttpNegotiate2, riid))
188 return E_NOINTERFACE;
191 if (*ppv)
193 IBindStatusCallback_AddRef(iface);
194 return S_OK;
197 FIXME("Unsupported riid = %s\n", debugstr_guid(riid));
199 return E_NOINTERFACE;
202 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
204 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
205 LONG ref = InterlockedIncrement(&This->ref);
207 TRACE("(%p) ref = %d\n", This, ref);
209 return ref;
212 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
214 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
215 LONG ref = InterlockedDecrement(&This->ref);
217 TRACE("(%p) ref = %d\n", This, ref);
219 if (!ref)
221 if (This->binding) IBinding_Release(This->binding);
222 if (This->stream) IStream_Release(This->stream);
223 if (This->body) GlobalFree(This->body);
224 heap_free(This);
227 return ref;
230 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
231 DWORD reserved, IBinding *pbind)
233 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
235 TRACE("(%p)->(%d %p)\n", This, reserved, pbind);
237 if (!pbind) return E_INVALIDARG;
239 This->binding = pbind;
240 IBinding_AddRef(pbind);
242 httprequest_setreadystate(This->request, READYSTATE_LOADED);
244 return CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
247 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pPriority)
249 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
251 TRACE("(%p)->(%p)\n", This, pPriority);
253 return E_NOTIMPL;
256 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
258 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
260 TRACE("(%p)->(%d)\n", This, reserved);
262 return E_NOTIMPL;
265 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
266 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
268 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
270 TRACE("(%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
271 debugstr_w(szStatusText));
273 return S_OK;
276 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
277 HRESULT hr, LPCWSTR error)
279 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
281 TRACE("(%p)->(0x%08x %s)\n", This, hr, debugstr_w(error));
283 if (This->binding)
285 IBinding_Release(This->binding);
286 This->binding = NULL;
289 if (hr == S_OK)
290 httprequest_setreadystate(This->request, READYSTATE_COMPLETE);
292 return S_OK;
295 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
296 DWORD *bind_flags, BINDINFO *pbindinfo)
298 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
300 TRACE("(%p)->(%p %p)\n", This, bind_flags, pbindinfo);
302 *bind_flags = 0;
303 if (This->request->async) *bind_flags |= BINDF_ASYNCHRONOUS;
305 if (This->request->verb != BINDVERB_GET && This->body)
307 pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
308 pbindinfo->stgmedData.u.hGlobal = This->body;
309 pbindinfo->cbstgmedData = GlobalSize(This->body);
310 /* callback owns passed body pointer */
311 IBindStatusCallback_QueryInterface(iface, &IID_IUnknown, (void**)&pbindinfo->stgmedData.pUnkForRelease);
314 pbindinfo->dwBindVerb = This->request->verb;
316 return S_OK;
319 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
320 DWORD flags, DWORD size, FORMATETC *format, STGMEDIUM *stgmed)
322 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
323 DWORD read, written;
324 BYTE buf[4096];
325 HRESULT hr;
327 TRACE("(%p)->(%08x %d %p %p)\n", This, flags, size, format, stgmed);
331 hr = IStream_Read(stgmed->u.pstm, buf, sizeof(buf), &read);
332 if (hr != S_OK) break;
334 hr = IStream_Write(This->stream, buf, read, &written);
335 } while((hr == S_OK) && written != 0 && read != 0);
337 httprequest_setreadystate(This->request, READYSTATE_INTERACTIVE);
339 return S_OK;
342 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
343 REFIID riid, IUnknown *punk)
345 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
347 FIXME("(%p)->(%s %p): stub\n", This, debugstr_guid(riid), punk);
349 return E_NOTIMPL;
352 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
353 BindStatusCallback_QueryInterface,
354 BindStatusCallback_AddRef,
355 BindStatusCallback_Release,
356 BindStatusCallback_OnStartBinding,
357 BindStatusCallback_GetPriority,
358 BindStatusCallback_OnLowResource,
359 BindStatusCallback_OnProgress,
360 BindStatusCallback_OnStopBinding,
361 BindStatusCallback_GetBindInfo,
362 BindStatusCallback_OnDataAvailable,
363 BindStatusCallback_OnObjectAvailable
366 static HRESULT WINAPI BSCHttpNegotiate_QueryInterface(IHttpNegotiate *iface,
367 REFIID riid, void **ppv)
369 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
370 return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
373 static ULONG WINAPI BSCHttpNegotiate_AddRef(IHttpNegotiate *iface)
375 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
376 return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
379 static ULONG WINAPI BSCHttpNegotiate_Release(IHttpNegotiate *iface)
381 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
382 return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
385 static HRESULT WINAPI BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate *iface,
386 LPCWSTR url, LPCWSTR headers, DWORD reserved, LPWSTR *add_headers)
388 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
389 const struct reqheader *entry;
390 WCHAR *buff, *ptr;
392 TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(url), debugstr_w(headers), reserved, add_headers);
394 *add_headers = NULL;
396 if (list_empty(&This->request->reqheaders)) return S_OK;
398 buff = CoTaskMemAlloc(This->request->reqheader_size*sizeof(WCHAR));
399 if (!buff) return E_OUTOFMEMORY;
401 ptr = buff;
402 LIST_FOR_EACH_ENTRY(entry, &This->request->reqheaders, struct reqheader, entry)
404 lstrcpyW(ptr, entry->header);
405 ptr += SysStringLen(entry->header);
407 lstrcpyW(ptr, colspaceW);
408 ptr += sizeof(colspaceW)/sizeof(WCHAR)-1;
410 lstrcpyW(ptr, entry->value);
411 ptr += SysStringLen(entry->value);
413 lstrcpyW(ptr, crlfW);
414 ptr += sizeof(crlfW)/sizeof(WCHAR)-1;
417 *add_headers = buff;
419 return S_OK;
422 static HRESULT WINAPI BSCHttpNegotiate_OnResponse(IHttpNegotiate *iface, DWORD code,
423 LPCWSTR resp_headers, LPCWSTR req_headers, LPWSTR *add_reqheaders)
425 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
427 TRACE("(%p)->(%d %s %s %p)\n", This, code, debugstr_w(resp_headers),
428 debugstr_w(req_headers), add_reqheaders);
430 This->request->status = code;
432 return S_OK;
435 static const IHttpNegotiateVtbl BSCHttpNegotiateVtbl = {
436 BSCHttpNegotiate_QueryInterface,
437 BSCHttpNegotiate_AddRef,
438 BSCHttpNegotiate_Release,
439 BSCHttpNegotiate_BeginningTransaction,
440 BSCHttpNegotiate_OnResponse
443 static HRESULT BindStatusCallback_create(httprequest* This, BindStatusCallback **obj, const VARIANT *body)
445 BindStatusCallback *bsc;
446 IBindCtx *pbc;
447 HRESULT hr;
449 hr = CreateBindCtx(0, &pbc);
450 if (hr != S_OK) return hr;
452 bsc = heap_alloc(sizeof(*bsc));
453 if (!bsc)
455 IBindCtx_Release(pbc);
456 return E_OUTOFMEMORY;
459 bsc->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl;
460 bsc->IHttpNegotiate_iface.lpVtbl = &BSCHttpNegotiateVtbl;
461 bsc->ref = 1;
462 bsc->request = This;
463 bsc->binding = NULL;
464 bsc->stream = NULL;
465 bsc->body = NULL;
467 TRACE("created callback %p\n", bsc);
469 if (This->verb != BINDVERB_GET)
471 if (V_VT(body) == VT_BSTR)
473 LONG size = SysStringLen(V_BSTR(body)) * sizeof(WCHAR);
474 void *ptr;
476 bsc->body = GlobalAlloc(GMEM_FIXED, size);
477 if (!bsc->body)
479 heap_free(bsc);
480 return E_OUTOFMEMORY;
483 ptr = GlobalLock(bsc->body);
484 memcpy(ptr, V_BSTR(body), size);
485 GlobalUnlock(bsc->body);
487 else
488 FIXME("unsupported body data type %d\n", V_VT(body));
491 hr = RegisterBindStatusCallback(pbc, &bsc->IBindStatusCallback_iface, NULL, 0);
492 if (hr == S_OK)
494 IMoniker *moniker;
496 hr = CreateURLMoniker(NULL, This->url, &moniker);
497 if (hr == S_OK)
499 IStream *stream;
501 hr = IMoniker_BindToStorage(moniker, pbc, NULL, &IID_IStream, (void**)&stream);
502 IMoniker_Release(moniker);
503 if (stream) IStream_Release(stream);
505 IBindCtx_Release(pbc);
508 if (FAILED(hr))
510 IBindStatusCallback_Release(&bsc->IBindStatusCallback_iface);
511 bsc = NULL;
514 *obj = bsc;
515 return hr;
518 static HRESULT WINAPI httprequest_QueryInterface(IXMLHTTPRequest *iface, REFIID riid, void **ppvObject)
520 httprequest *This = impl_from_IXMLHTTPRequest( iface );
521 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
523 if ( IsEqualGUID( riid, &IID_IXMLHTTPRequest) ||
524 IsEqualGUID( riid, &IID_IDispatch) ||
525 IsEqualGUID( riid, &IID_IUnknown) )
527 *ppvObject = iface;
529 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
531 *ppvObject = &This->IObjectWithSite_iface;
533 else if (IsEqualGUID(&IID_IObjectSafety, riid))
535 *ppvObject = &This->IObjectSafety_iface;
537 else
539 TRACE("Unsupported interface %s\n", debugstr_guid(riid));
540 *ppvObject = NULL;
541 return E_NOINTERFACE;
544 IXMLHTTPRequest_AddRef( iface );
546 return S_OK;
549 static ULONG WINAPI httprequest_AddRef(IXMLHTTPRequest *iface)
551 httprequest *This = impl_from_IXMLHTTPRequest( iface );
552 ULONG ref = InterlockedIncrement( &This->ref );
553 TRACE("(%p)->(%u)\n", This, ref );
554 return ref;
557 static ULONG WINAPI httprequest_Release(IXMLHTTPRequest *iface)
559 httprequest *This = impl_from_IXMLHTTPRequest( iface );
560 ULONG ref = InterlockedDecrement( &This->ref );
562 TRACE("(%p)->(%u)\n", This, ref );
564 if ( ref == 0 )
566 struct reqheader *header, *header2;
568 if (This->site)
569 IUnknown_Release( This->site );
571 SysFreeString(This->url);
572 SysFreeString(This->user);
573 SysFreeString(This->password);
575 /* request headers */
576 LIST_FOR_EACH_ENTRY_SAFE(header, header2, &This->reqheaders, struct reqheader, entry)
578 list_remove(&header->entry);
579 SysFreeString(header->header);
580 SysFreeString(header->value);
581 heap_free(header);
584 /* detach callback object */
585 BindStatusCallback_Detach(This->bsc);
587 if (This->sink) IDispatch_Release(This->sink);
589 heap_free( This );
592 return ref;
595 static HRESULT WINAPI httprequest_GetTypeInfoCount(IXMLHTTPRequest *iface, UINT *pctinfo)
597 httprequest *This = impl_from_IXMLHTTPRequest( iface );
599 TRACE("(%p)->(%p)\n", This, pctinfo);
601 *pctinfo = 1;
603 return S_OK;
606 static HRESULT WINAPI httprequest_GetTypeInfo(IXMLHTTPRequest *iface, UINT iTInfo,
607 LCID lcid, ITypeInfo **ppTInfo)
609 httprequest *This = impl_from_IXMLHTTPRequest( iface );
611 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
613 return get_typeinfo(IXMLHTTPRequest_tid, ppTInfo);
616 static HRESULT WINAPI httprequest_GetIDsOfNames(IXMLHTTPRequest *iface, REFIID riid,
617 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
619 httprequest *This = impl_from_IXMLHTTPRequest( iface );
620 ITypeInfo *typeinfo;
621 HRESULT hr;
623 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
624 lcid, rgDispId);
626 if(!rgszNames || cNames == 0 || !rgDispId)
627 return E_INVALIDARG;
629 hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
630 if(SUCCEEDED(hr))
632 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
633 ITypeInfo_Release(typeinfo);
636 return hr;
639 static HRESULT WINAPI httprequest_Invoke(IXMLHTTPRequest *iface, DISPID dispIdMember, REFIID riid,
640 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
641 EXCEPINFO *pExcepInfo, UINT *puArgErr)
643 httprequest *This = impl_from_IXMLHTTPRequest( iface );
644 ITypeInfo *typeinfo;
645 HRESULT hr;
647 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
648 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
650 hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
651 if(SUCCEEDED(hr))
653 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLHTTPRequest_iface, dispIdMember, wFlags,
654 pDispParams, pVarResult, pExcepInfo, puArgErr);
655 ITypeInfo_Release(typeinfo);
658 return hr;
661 static HRESULT WINAPI httprequest_open(IXMLHTTPRequest *iface, BSTR method, BSTR url,
662 VARIANT async, VARIANT user, VARIANT password)
664 httprequest *This = impl_from_IXMLHTTPRequest( iface );
665 HRESULT hr;
666 VARIANT str, is_async;
668 TRACE("(%p)->(%s %s %s)\n", This, debugstr_w(method), debugstr_w(url),
669 debugstr_variant(&async));
671 if (!method || !url) return E_INVALIDARG;
673 /* free previously set data */
674 SysFreeString(This->url);
675 SysFreeString(This->user);
676 SysFreeString(This->password);
677 This->url = This->user = This->password = NULL;
679 if (lstrcmpiW(method, MethodGetW) == 0)
681 This->verb = BINDVERB_GET;
683 else if (lstrcmpiW(method, MethodPutW) == 0)
685 This->verb = BINDVERB_PUT;
687 else if (lstrcmpiW(method, MethodPostW) == 0)
689 This->verb = BINDVERB_POST;
691 else
693 FIXME("unsupported request type %s\n", debugstr_w(method));
694 This->verb = -1;
695 return E_FAIL;
698 This->url = SysAllocString(url);
700 VariantInit(&is_async);
701 hr = VariantChangeType(&is_async, &async, 0, VT_BOOL);
702 This->async = hr == S_OK && V_BOOL(&is_async) == VARIANT_TRUE;
704 VariantInit(&str);
705 hr = VariantChangeType(&str, &user, 0, VT_BSTR);
706 if (hr == S_OK)
707 This->user = V_BSTR(&str);
709 hr = VariantChangeType(&str, &password, 0, VT_BSTR);
710 if (hr == S_OK)
711 This->password = V_BSTR(&str);
713 httprequest_setreadystate(This, READYSTATE_LOADING);
715 return S_OK;
718 static HRESULT WINAPI httprequest_setRequestHeader(IXMLHTTPRequest *iface, BSTR header, BSTR value)
720 httprequest *This = impl_from_IXMLHTTPRequest( iface );
721 struct reqheader *entry;
723 TRACE("(%p)->(%s %s)\n", This, debugstr_w(header), debugstr_w(value));
725 if (!header || !*header) return E_INVALIDARG;
726 if (This->state != READYSTATE_LOADING) return E_FAIL;
727 if (!value) return E_INVALIDARG;
729 /* replace existing header value if already added */
730 LIST_FOR_EACH_ENTRY(entry, &This->reqheaders, struct reqheader, entry)
732 if (lstrcmpW(entry->header, header) == 0)
734 LONG length = SysStringLen(entry->value);
735 HRESULT hr;
737 hr = SysReAllocString(&entry->value, value) ? S_OK : E_OUTOFMEMORY;
739 if (hr == S_OK)
740 This->reqheader_size += (SysStringLen(entry->value) - length);
742 return hr;
746 entry = heap_alloc(sizeof(*entry));
747 if (!entry) return E_OUTOFMEMORY;
749 /* new header */
750 entry->header = SysAllocString(header);
751 entry->value = SysAllocString(value);
753 /* header length including null terminator */
754 This->reqheader_size += SysStringLen(entry->header) + sizeof(colspaceW)/sizeof(WCHAR) +
755 SysStringLen(entry->value) + sizeof(crlfW)/sizeof(WCHAR) - 1;
757 list_add_head(&This->reqheaders, &entry->entry);
759 return S_OK;
762 static HRESULT WINAPI httprequest_getResponseHeader(IXMLHTTPRequest *iface, BSTR bstrHeader, BSTR *pbstrValue)
764 httprequest *This = impl_from_IXMLHTTPRequest( iface );
766 FIXME("stub (%p) %s %p\n", This, debugstr_w(bstrHeader), pbstrValue);
768 return E_NOTIMPL;
771 static HRESULT WINAPI httprequest_getAllResponseHeaders(IXMLHTTPRequest *iface, BSTR *pbstrHeaders)
773 httprequest *This = impl_from_IXMLHTTPRequest( iface );
775 FIXME("stub (%p) %p\n", This, pbstrHeaders);
777 return E_NOTIMPL;
780 static HRESULT WINAPI httprequest_send(IXMLHTTPRequest *iface, VARIANT body)
782 httprequest *This = impl_from_IXMLHTTPRequest( iface );
783 BindStatusCallback *bsc = NULL;
784 HRESULT hr;
786 TRACE("(%p)->(%s)\n", This, debugstr_variant(&body));
788 if (This->state != READYSTATE_LOADING) return E_FAIL;
790 hr = BindStatusCallback_create(This, &bsc, &body);
791 if (FAILED(hr)) return hr;
793 BindStatusCallback_Detach(This->bsc);
794 This->bsc = bsc;
796 return hr;
799 static HRESULT WINAPI httprequest_abort(IXMLHTTPRequest *iface)
801 httprequest *This = impl_from_IXMLHTTPRequest( iface );
803 TRACE("(%p)\n", This);
805 BindStatusCallback_Detach(This->bsc);
806 This->bsc = NULL;
808 httprequest_setreadystate(This, READYSTATE_UNINITIALIZED);
810 return S_OK;
813 static HRESULT WINAPI httprequest_get_status(IXMLHTTPRequest *iface, LONG *status)
815 httprequest *This = impl_from_IXMLHTTPRequest( iface );
817 TRACE("(%p)->(%p)\n", This, status);
819 if (!status) return E_INVALIDARG;
820 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
822 *status = This->status;
824 return S_OK;
827 static HRESULT WINAPI httprequest_get_statusText(IXMLHTTPRequest *iface, BSTR *pbstrStatus)
829 httprequest *This = impl_from_IXMLHTTPRequest( iface );
831 FIXME("stub %p %p\n", This, pbstrStatus);
833 return E_NOTIMPL;
836 static HRESULT WINAPI httprequest_get_responseXML(IXMLHTTPRequest *iface, IDispatch **body)
838 httprequest *This = impl_from_IXMLHTTPRequest( iface );
839 IXMLDOMDocument3 *doc;
840 HRESULT hr;
841 BSTR str;
843 TRACE("(%p)->(%p)\n", This, body);
845 if (!body) return E_INVALIDARG;
846 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
848 hr = DOMDocument_create(MSXML_DEFAULT, NULL, (void**)&doc);
849 if (hr != S_OK) return hr;
851 hr = IXMLHTTPRequest_get_responseText(iface, &str);
852 if (hr == S_OK)
854 VARIANT_BOOL ok;
856 hr = IXMLDOMDocument3_loadXML(doc, str, &ok);
857 SysFreeString(str);
860 IXMLDOMDocument3_QueryInterface(doc, &IID_IDispatch, (void**)body);
861 IXMLDOMDocument3_Release(doc);
863 return hr;
866 static HRESULT WINAPI httprequest_get_responseText(IXMLHTTPRequest *iface, BSTR *body)
868 httprequest *This = impl_from_IXMLHTTPRequest( iface );
869 HGLOBAL hglobal;
870 HRESULT hr;
872 TRACE("(%p)->(%p)\n", This, body);
874 if (!body) return E_INVALIDARG;
875 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
877 hr = GetHGlobalFromStream(This->bsc->stream, &hglobal);
878 if (hr == S_OK)
880 xmlChar *ptr = GlobalLock(hglobal);
881 DWORD size = GlobalSize(hglobal);
882 xmlCharEncoding encoding = XML_CHAR_ENCODING_UTF8;
884 /* try to determine data encoding */
885 if (size >= 4)
887 encoding = xmlDetectCharEncoding(ptr, 4);
888 TRACE("detected encoding: %s\n", debugstr_a(xmlGetCharEncodingName(encoding)));
889 if ( encoding != XML_CHAR_ENCODING_UTF8 &&
890 encoding != XML_CHAR_ENCODING_UTF16LE &&
891 encoding != XML_CHAR_ENCODING_NONE )
893 FIXME("unsupported encoding: %s\n", debugstr_a(xmlGetCharEncodingName(encoding)));
894 GlobalUnlock(hglobal);
895 return E_FAIL;
899 /* without BOM assume UTF-8 */
900 if (encoding == XML_CHAR_ENCODING_UTF8 ||
901 encoding == XML_CHAR_ENCODING_NONE )
903 DWORD length = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)ptr, size, NULL, 0);
905 *body = SysAllocStringLen(NULL, length);
906 if (*body)
907 MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)ptr, size, *body, length);
909 else
910 *body = SysAllocStringByteLen((LPCSTR)ptr, size);
912 if (!*body) hr = E_OUTOFMEMORY;
913 GlobalUnlock(hglobal);
916 return hr;
919 static HRESULT WINAPI httprequest_get_responseBody(IXMLHTTPRequest *iface, VARIANT *body)
921 httprequest *This = impl_from_IXMLHTTPRequest( iface );
922 HGLOBAL hglobal;
923 HRESULT hr;
925 TRACE("(%p)->(%p)\n", This, body);
927 if (!body) return E_INVALIDARG;
928 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
930 hr = GetHGlobalFromStream(This->bsc->stream, &hglobal);
931 if (hr == S_OK)
933 void *ptr = GlobalLock(hglobal);
934 DWORD size = GlobalSize(hglobal);
936 SAFEARRAYBOUND bound;
937 SAFEARRAY *array;
939 bound.lLbound = 0;
940 bound.cElements = size;
941 array = SafeArrayCreate(VT_UI1, 1, &bound);
943 if (array)
945 void *dest;
947 V_VT(body) = VT_ARRAY | VT_UI1;
948 V_ARRAY(body) = array;
950 hr = SafeArrayAccessData(array, &dest);
951 if (hr == S_OK)
953 memcpy(dest, ptr, size);
954 SafeArrayUnaccessData(array);
956 else
958 VariantClear(body);
961 else
962 hr = E_FAIL;
964 GlobalUnlock(hglobal);
967 return hr;
970 static HRESULT WINAPI httprequest_get_responseStream(IXMLHTTPRequest *iface, VARIANT *pvarBody)
972 httprequest *This = impl_from_IXMLHTTPRequest( iface );
974 FIXME("stub %p %p\n", This, pvarBody);
976 return E_NOTIMPL;
979 static HRESULT WINAPI httprequest_get_readyState(IXMLHTTPRequest *iface, LONG *state)
981 httprequest *This = impl_from_IXMLHTTPRequest( iface );
983 TRACE("(%p)->(%p)\n", This, state);
985 if (!state) return E_INVALIDARG;
987 *state = This->state;
988 return S_OK;
991 static HRESULT WINAPI httprequest_put_onreadystatechange(IXMLHTTPRequest *iface, IDispatch *sink)
993 httprequest *This = impl_from_IXMLHTTPRequest( iface );
995 TRACE("(%p)->(%p)\n", This, sink);
997 if (This->sink) IDispatch_Release(This->sink);
998 if ((This->sink = sink)) IDispatch_AddRef(This->sink);
1000 return S_OK;
1003 static const struct IXMLHTTPRequestVtbl dimimpl_vtbl =
1005 httprequest_QueryInterface,
1006 httprequest_AddRef,
1007 httprequest_Release,
1008 httprequest_GetTypeInfoCount,
1009 httprequest_GetTypeInfo,
1010 httprequest_GetIDsOfNames,
1011 httprequest_Invoke,
1012 httprequest_open,
1013 httprequest_setRequestHeader,
1014 httprequest_getResponseHeader,
1015 httprequest_getAllResponseHeaders,
1016 httprequest_send,
1017 httprequest_abort,
1018 httprequest_get_status,
1019 httprequest_get_statusText,
1020 httprequest_get_responseXML,
1021 httprequest_get_responseText,
1022 httprequest_get_responseBody,
1023 httprequest_get_responseStream,
1024 httprequest_get_readyState,
1025 httprequest_put_onreadystatechange
1028 /* IObjectWithSite */
1029 static HRESULT WINAPI
1030 httprequest_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
1032 httprequest *This = impl_from_IObjectWithSite(iface);
1033 return IXMLHTTPRequest_QueryInterface( (IXMLHTTPRequest *)This, riid, ppvObject );
1036 static ULONG WINAPI httprequest_ObjectWithSite_AddRef( IObjectWithSite* iface )
1038 httprequest *This = impl_from_IObjectWithSite(iface);
1039 return IXMLHTTPRequest_AddRef((IXMLHTTPRequest *)This);
1042 static ULONG WINAPI httprequest_ObjectWithSite_Release( IObjectWithSite* iface )
1044 httprequest *This = impl_from_IObjectWithSite(iface);
1045 return IXMLHTTPRequest_Release((IXMLHTTPRequest *)This);
1048 static HRESULT WINAPI httprequest_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
1050 httprequest *This = impl_from_IObjectWithSite(iface);
1052 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
1054 if ( !This->site )
1055 return E_FAIL;
1057 return IUnknown_QueryInterface( This->site, iid, ppvSite );
1060 static HRESULT WINAPI httprequest_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
1062 httprequest *This = impl_from_IObjectWithSite(iface);
1064 TRACE("(%p)->(%p)\n", iface, punk);
1066 if (punk)
1067 IUnknown_AddRef( punk );
1069 if(This->site)
1070 IUnknown_Release( This->site );
1072 This->site = punk;
1074 return S_OK;
1077 static const IObjectWithSiteVtbl httprequestObjectSite =
1079 httprequest_ObjectWithSite_QueryInterface,
1080 httprequest_ObjectWithSite_AddRef,
1081 httprequest_ObjectWithSite_Release,
1082 httprequest_ObjectWithSite_SetSite,
1083 httprequest_ObjectWithSite_GetSite
1086 /* IObjectSafety */
1087 static HRESULT WINAPI httprequest_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
1089 httprequest *This = impl_from_IObjectSafety(iface);
1090 return IXMLHTTPRequest_QueryInterface( (IXMLHTTPRequest *)This, riid, ppv );
1093 static ULONG WINAPI httprequest_Safety_AddRef(IObjectSafety *iface)
1095 httprequest *This = impl_from_IObjectSafety(iface);
1096 return IXMLHTTPRequest_AddRef((IXMLHTTPRequest *)This);
1099 static ULONG WINAPI httprequest_Safety_Release(IObjectSafety *iface)
1101 httprequest *This = impl_from_IObjectSafety(iface);
1102 return IXMLHTTPRequest_Release((IXMLHTTPRequest *)This);
1105 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
1107 static HRESULT WINAPI httprequest_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
1108 DWORD *supported, DWORD *enabled)
1110 httprequest *This = impl_from_IObjectSafety(iface);
1112 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
1114 if(!supported || !enabled) return E_POINTER;
1116 *supported = SAFETY_SUPPORTED_OPTIONS;
1117 *enabled = This->safeopt;
1119 return S_OK;
1122 static HRESULT WINAPI httprequest_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
1123 DWORD mask, DWORD enabled)
1125 httprequest *This = impl_from_IObjectSafety(iface);
1126 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
1128 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
1129 return E_FAIL;
1131 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
1133 return S_OK;
1136 #undef SAFETY_SUPPORTED_OPTIONS
1138 static const IObjectSafetyVtbl httprequestObjectSafety = {
1139 httprequest_Safety_QueryInterface,
1140 httprequest_Safety_AddRef,
1141 httprequest_Safety_Release,
1142 httprequest_Safety_GetInterfaceSafetyOptions,
1143 httprequest_Safety_SetInterfaceSafetyOptions
1146 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
1148 httprequest *req;
1149 HRESULT hr = S_OK;
1151 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
1153 req = heap_alloc( sizeof (*req) );
1154 if( !req )
1155 return E_OUTOFMEMORY;
1157 req->IXMLHTTPRequest_iface.lpVtbl = &dimimpl_vtbl;
1158 req->IObjectWithSite_iface.lpVtbl = &httprequestObjectSite;
1159 req->IObjectSafety_iface.lpVtbl = &httprequestObjectSafety;
1160 req->ref = 1;
1162 req->async = FALSE;
1163 req->verb = -1;
1164 req->url = req->user = req->password = NULL;
1166 req->state = READYSTATE_UNINITIALIZED;
1167 req->sink = NULL;
1169 req->bsc = NULL;
1170 req->status = 0;
1171 req->reqheader_size = 0;
1172 list_init(&req->reqheaders);
1173 req->site = NULL;
1174 req->safeopt = 0;
1176 *ppObj = &req->IXMLHTTPRequest_iface;
1178 TRACE("returning iface %p\n", *ppObj);
1180 return hr;
1183 #else
1185 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
1187 MESSAGE("This program tried to use a XMLHTTPRequest object, but\n"
1188 "libxml2 support was not present at compile time.\n");
1189 return E_NOTIMPL;
1192 #endif