wineps: Fix a couple of typos in the path painting function.
[wine/testsucceed.git] / dlls / msxml3 / httprequest.c
blob0265c1abbfcb344d86e56e11342ea9e88ff2028f
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 );
610 HRESULT hr;
612 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
614 hr = get_typeinfo(IXMLHTTPRequest_tid, ppTInfo);
616 return hr;
619 static HRESULT WINAPI httprequest_GetIDsOfNames(IXMLHTTPRequest *iface, REFIID riid,
620 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
622 httprequest *This = impl_from_IXMLHTTPRequest( iface );
623 ITypeInfo *typeinfo;
624 HRESULT hr;
626 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
627 lcid, rgDispId);
629 if(!rgszNames || cNames == 0 || !rgDispId)
630 return E_INVALIDARG;
632 hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
633 if(SUCCEEDED(hr))
635 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
636 ITypeInfo_Release(typeinfo);
639 return hr;
642 static HRESULT WINAPI httprequest_Invoke(IXMLHTTPRequest *iface, DISPID dispIdMember, REFIID riid,
643 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
644 EXCEPINFO *pExcepInfo, UINT *puArgErr)
646 httprequest *This = impl_from_IXMLHTTPRequest( iface );
647 ITypeInfo *typeinfo;
648 HRESULT hr;
650 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
651 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
653 hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
654 if(SUCCEEDED(hr))
656 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLHTTPRequest_iface, dispIdMember, wFlags,
657 pDispParams, pVarResult, pExcepInfo, puArgErr);
658 ITypeInfo_Release(typeinfo);
661 return hr;
664 static HRESULT WINAPI httprequest_open(IXMLHTTPRequest *iface, BSTR method, BSTR url,
665 VARIANT async, VARIANT user, VARIANT password)
667 httprequest *This = impl_from_IXMLHTTPRequest( iface );
668 HRESULT hr;
669 VARIANT str, is_async;
671 TRACE("(%p)->(%s %s %s)\n", This, debugstr_w(method), debugstr_w(url),
672 debugstr_variant(&async));
674 if (!method || !url) return E_INVALIDARG;
676 /* free previously set data */
677 SysFreeString(This->url);
678 SysFreeString(This->user);
679 SysFreeString(This->password);
680 This->url = This->user = This->password = NULL;
682 if (lstrcmpiW(method, MethodGetW) == 0)
684 This->verb = BINDVERB_GET;
686 else if (lstrcmpiW(method, MethodPutW) == 0)
688 This->verb = BINDVERB_PUT;
690 else if (lstrcmpiW(method, MethodPostW) == 0)
692 This->verb = BINDVERB_POST;
694 else
696 FIXME("unsupported request type %s\n", debugstr_w(method));
697 This->verb = -1;
698 return E_FAIL;
701 This->url = SysAllocString(url);
703 VariantInit(&is_async);
704 hr = VariantChangeType(&is_async, &async, 0, VT_BOOL);
705 This->async = hr == S_OK && V_BOOL(&is_async) == VARIANT_TRUE;
707 VariantInit(&str);
708 hr = VariantChangeType(&str, &user, 0, VT_BSTR);
709 if (hr == S_OK)
710 This->user = V_BSTR(&str);
712 hr = VariantChangeType(&str, &password, 0, VT_BSTR);
713 if (hr == S_OK)
714 This->password = V_BSTR(&str);
716 httprequest_setreadystate(This, READYSTATE_LOADING);
718 return S_OK;
721 static HRESULT WINAPI httprequest_setRequestHeader(IXMLHTTPRequest *iface, BSTR header, BSTR value)
723 httprequest *This = impl_from_IXMLHTTPRequest( iface );
724 struct reqheader *entry;
726 TRACE("(%p)->(%s %s)\n", This, debugstr_w(header), debugstr_w(value));
728 if (!header || !*header) return E_INVALIDARG;
729 if (This->state != READYSTATE_LOADING) return E_FAIL;
730 if (!value) return E_INVALIDARG;
732 /* replace existing header value if already added */
733 LIST_FOR_EACH_ENTRY(entry, &This->reqheaders, struct reqheader, entry)
735 if (lstrcmpW(entry->header, header) == 0)
737 LONG length = SysStringLen(entry->value);
738 HRESULT hr;
740 hr = SysReAllocString(&entry->value, value) ? S_OK : E_OUTOFMEMORY;
742 if (hr == S_OK)
743 This->reqheader_size += (SysStringLen(entry->value) - length);
745 return hr;
749 entry = heap_alloc(sizeof(*entry));
750 if (!entry) return E_OUTOFMEMORY;
752 /* new header */
753 entry->header = SysAllocString(header);
754 entry->value = SysAllocString(value);
756 /* header length including null terminator */
757 This->reqheader_size += SysStringLen(entry->header) + sizeof(colspaceW)/sizeof(WCHAR) +
758 SysStringLen(entry->value) + sizeof(crlfW)/sizeof(WCHAR) - 1;
760 list_add_head(&This->reqheaders, &entry->entry);
762 return S_OK;
765 static HRESULT WINAPI httprequest_getResponseHeader(IXMLHTTPRequest *iface, BSTR bstrHeader, BSTR *pbstrValue)
767 httprequest *This = impl_from_IXMLHTTPRequest( iface );
769 FIXME("stub (%p) %s %p\n", This, debugstr_w(bstrHeader), pbstrValue);
771 return E_NOTIMPL;
774 static HRESULT WINAPI httprequest_getAllResponseHeaders(IXMLHTTPRequest *iface, BSTR *pbstrHeaders)
776 httprequest *This = impl_from_IXMLHTTPRequest( iface );
778 FIXME("stub (%p) %p\n", This, pbstrHeaders);
780 return E_NOTIMPL;
783 static HRESULT WINAPI httprequest_send(IXMLHTTPRequest *iface, VARIANT body)
785 httprequest *This = impl_from_IXMLHTTPRequest( iface );
786 BindStatusCallback *bsc = NULL;
787 HRESULT hr;
789 TRACE("(%p)->(%s)\n", This, debugstr_variant(&body));
791 if (This->state != READYSTATE_LOADING) return E_FAIL;
793 hr = BindStatusCallback_create(This, &bsc, &body);
794 if (FAILED(hr)) return hr;
796 BindStatusCallback_Detach(This->bsc);
797 This->bsc = bsc;
799 return hr;
802 static HRESULT WINAPI httprequest_abort(IXMLHTTPRequest *iface)
804 httprequest *This = impl_from_IXMLHTTPRequest( iface );
806 TRACE("(%p)\n", This);
808 BindStatusCallback_Detach(This->bsc);
809 This->bsc = NULL;
811 httprequest_setreadystate(This, READYSTATE_UNINITIALIZED);
813 return S_OK;
816 static HRESULT WINAPI httprequest_get_status(IXMLHTTPRequest *iface, LONG *status)
818 httprequest *This = impl_from_IXMLHTTPRequest( iface );
820 TRACE("(%p)->(%p)\n", This, status);
822 if (!status) return E_INVALIDARG;
823 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
825 *status = This->status;
827 return S_OK;
830 static HRESULT WINAPI httprequest_get_statusText(IXMLHTTPRequest *iface, BSTR *pbstrStatus)
832 httprequest *This = impl_from_IXMLHTTPRequest( iface );
834 FIXME("stub %p %p\n", This, pbstrStatus);
836 return E_NOTIMPL;
839 static HRESULT WINAPI httprequest_get_responseXML(IXMLHTTPRequest *iface, IDispatch **body)
841 httprequest *This = impl_from_IXMLHTTPRequest( iface );
842 IXMLDOMDocument3 *doc;
843 HRESULT hr;
844 BSTR str;
846 TRACE("(%p)->(%p)\n", This, body);
848 if (!body) return E_INVALIDARG;
849 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
851 hr = DOMDocument_create(MSXML_DEFAULT, NULL, (void**)&doc);
852 if (hr != S_OK) return hr;
854 hr = IXMLHTTPRequest_get_responseText(iface, &str);
855 if (hr == S_OK)
857 VARIANT_BOOL ok;
859 hr = IXMLDOMDocument3_loadXML(doc, str, &ok);
860 SysFreeString(str);
863 IXMLDOMDocument3_QueryInterface(doc, &IID_IDispatch, (void**)body);
864 IXMLDOMDocument3_Release(doc);
866 return hr;
869 static HRESULT WINAPI httprequest_get_responseText(IXMLHTTPRequest *iface, BSTR *body)
871 httprequest *This = impl_from_IXMLHTTPRequest( iface );
872 HGLOBAL hglobal;
873 HRESULT hr;
875 TRACE("(%p)->(%p)\n", This, body);
877 if (!body) return E_INVALIDARG;
878 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
880 hr = GetHGlobalFromStream(This->bsc->stream, &hglobal);
881 if (hr == S_OK)
883 xmlChar *ptr = GlobalLock(hglobal);
884 DWORD size = GlobalSize(hglobal);
885 xmlCharEncoding encoding = XML_CHAR_ENCODING_UTF8;
887 /* try to determine data encoding */
888 if (size >= 4)
890 encoding = xmlDetectCharEncoding(ptr, 4);
891 TRACE("detected encoding: %s\n", debugstr_a(xmlGetCharEncodingName(encoding)));
892 if ( encoding != XML_CHAR_ENCODING_UTF8 &&
893 encoding != XML_CHAR_ENCODING_UTF16LE &&
894 encoding != XML_CHAR_ENCODING_NONE )
896 FIXME("unsupported encoding: %s\n", debugstr_a(xmlGetCharEncodingName(encoding)));
897 GlobalUnlock(hglobal);
898 return E_FAIL;
902 /* without BOM assume UTF-8 */
903 if (encoding == XML_CHAR_ENCODING_UTF8 ||
904 encoding == XML_CHAR_ENCODING_NONE )
906 DWORD length = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)ptr, size, NULL, 0);
908 *body = SysAllocStringLen(NULL, length);
909 if (*body)
910 MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)ptr, size, *body, length);
912 else
913 *body = SysAllocStringByteLen((LPCSTR)ptr, size);
915 if (!*body) hr = E_OUTOFMEMORY;
916 GlobalUnlock(hglobal);
919 return hr;
922 static HRESULT WINAPI httprequest_get_responseBody(IXMLHTTPRequest *iface, VARIANT *body)
924 httprequest *This = impl_from_IXMLHTTPRequest( iface );
925 HGLOBAL hglobal;
926 HRESULT hr;
928 TRACE("(%p)->(%p)\n", This, body);
930 if (!body) return E_INVALIDARG;
931 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
933 hr = GetHGlobalFromStream(This->bsc->stream, &hglobal);
934 if (hr == S_OK)
936 void *ptr = GlobalLock(hglobal);
937 DWORD size = GlobalSize(hglobal);
939 SAFEARRAYBOUND bound;
940 SAFEARRAY *array;
942 bound.lLbound = 0;
943 bound.cElements = size;
944 array = SafeArrayCreate(VT_UI1, 1, &bound);
946 if (array)
948 void *dest;
950 V_VT(body) = VT_ARRAY | VT_UI1;
951 V_ARRAY(body) = array;
953 hr = SafeArrayAccessData(array, &dest);
954 if (hr == S_OK)
956 memcpy(dest, ptr, size);
957 SafeArrayUnaccessData(array);
959 else
961 VariantClear(body);
964 else
965 hr = E_FAIL;
967 GlobalUnlock(hglobal);
970 return hr;
973 static HRESULT WINAPI httprequest_get_responseStream(IXMLHTTPRequest *iface, VARIANT *pvarBody)
975 httprequest *This = impl_from_IXMLHTTPRequest( iface );
977 FIXME("stub %p %p\n", This, pvarBody);
979 return E_NOTIMPL;
982 static HRESULT WINAPI httprequest_get_readyState(IXMLHTTPRequest *iface, LONG *state)
984 httprequest *This = impl_from_IXMLHTTPRequest( iface );
986 TRACE("(%p)->(%p)\n", This, state);
988 if (!state) return E_INVALIDARG;
990 *state = This->state;
991 return S_OK;
994 static HRESULT WINAPI httprequest_put_onreadystatechange(IXMLHTTPRequest *iface, IDispatch *sink)
996 httprequest *This = impl_from_IXMLHTTPRequest( iface );
998 TRACE("(%p)->(%p)\n", This, sink);
1000 if (This->sink) IDispatch_Release(This->sink);
1001 if ((This->sink = sink)) IDispatch_AddRef(This->sink);
1003 return S_OK;
1006 static const struct IXMLHTTPRequestVtbl dimimpl_vtbl =
1008 httprequest_QueryInterface,
1009 httprequest_AddRef,
1010 httprequest_Release,
1011 httprequest_GetTypeInfoCount,
1012 httprequest_GetTypeInfo,
1013 httprequest_GetIDsOfNames,
1014 httprequest_Invoke,
1015 httprequest_open,
1016 httprequest_setRequestHeader,
1017 httprequest_getResponseHeader,
1018 httprequest_getAllResponseHeaders,
1019 httprequest_send,
1020 httprequest_abort,
1021 httprequest_get_status,
1022 httprequest_get_statusText,
1023 httprequest_get_responseXML,
1024 httprequest_get_responseText,
1025 httprequest_get_responseBody,
1026 httprequest_get_responseStream,
1027 httprequest_get_readyState,
1028 httprequest_put_onreadystatechange
1031 /* IObjectWithSite */
1032 static HRESULT WINAPI
1033 httprequest_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
1035 httprequest *This = impl_from_IObjectWithSite(iface);
1036 return IXMLHTTPRequest_QueryInterface( (IXMLHTTPRequest *)This, riid, ppvObject );
1039 static ULONG WINAPI httprequest_ObjectWithSite_AddRef( IObjectWithSite* iface )
1041 httprequest *This = impl_from_IObjectWithSite(iface);
1042 return IXMLHTTPRequest_AddRef((IXMLHTTPRequest *)This);
1045 static ULONG WINAPI httprequest_ObjectWithSite_Release( IObjectWithSite* iface )
1047 httprequest *This = impl_from_IObjectWithSite(iface);
1048 return IXMLHTTPRequest_Release((IXMLHTTPRequest *)This);
1051 static HRESULT WINAPI httprequest_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
1053 httprequest *This = impl_from_IObjectWithSite(iface);
1055 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
1057 if ( !This->site )
1058 return E_FAIL;
1060 return IUnknown_QueryInterface( This->site, iid, ppvSite );
1063 static HRESULT WINAPI httprequest_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
1065 httprequest *This = impl_from_IObjectWithSite(iface);
1067 TRACE("(%p)->(%p)\n", iface, punk);
1069 if (punk)
1070 IUnknown_AddRef( punk );
1072 if(This->site)
1073 IUnknown_Release( This->site );
1075 This->site = punk;
1077 return S_OK;
1080 static const IObjectWithSiteVtbl httprequestObjectSite =
1082 httprequest_ObjectWithSite_QueryInterface,
1083 httprequest_ObjectWithSite_AddRef,
1084 httprequest_ObjectWithSite_Release,
1085 httprequest_ObjectWithSite_SetSite,
1086 httprequest_ObjectWithSite_GetSite
1089 /* IObjectSafety */
1090 static HRESULT WINAPI httprequest_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
1092 httprequest *This = impl_from_IObjectSafety(iface);
1093 return IXMLHTTPRequest_QueryInterface( (IXMLHTTPRequest *)This, riid, ppv );
1096 static ULONG WINAPI httprequest_Safety_AddRef(IObjectSafety *iface)
1098 httprequest *This = impl_from_IObjectSafety(iface);
1099 return IXMLHTTPRequest_AddRef((IXMLHTTPRequest *)This);
1102 static ULONG WINAPI httprequest_Safety_Release(IObjectSafety *iface)
1104 httprequest *This = impl_from_IObjectSafety(iface);
1105 return IXMLHTTPRequest_Release((IXMLHTTPRequest *)This);
1108 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
1110 static HRESULT WINAPI httprequest_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
1111 DWORD *supported, DWORD *enabled)
1113 httprequest *This = impl_from_IObjectSafety(iface);
1115 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
1117 if(!supported || !enabled) return E_POINTER;
1119 *supported = SAFETY_SUPPORTED_OPTIONS;
1120 *enabled = This->safeopt;
1122 return S_OK;
1125 static HRESULT WINAPI httprequest_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
1126 DWORD mask, DWORD enabled)
1128 httprequest *This = impl_from_IObjectSafety(iface);
1129 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
1131 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
1132 return E_FAIL;
1134 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
1136 return S_OK;
1139 #undef SAFETY_SUPPORTED_OPTIONS
1141 static const IObjectSafetyVtbl httprequestObjectSafety = {
1142 httprequest_Safety_QueryInterface,
1143 httprequest_Safety_AddRef,
1144 httprequest_Safety_Release,
1145 httprequest_Safety_GetInterfaceSafetyOptions,
1146 httprequest_Safety_SetInterfaceSafetyOptions
1149 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
1151 httprequest *req;
1152 HRESULT hr = S_OK;
1154 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
1156 req = heap_alloc( sizeof (*req) );
1157 if( !req )
1158 return E_OUTOFMEMORY;
1160 req->IXMLHTTPRequest_iface.lpVtbl = &dimimpl_vtbl;
1161 req->IObjectWithSite_iface.lpVtbl = &httprequestObjectSite;
1162 req->IObjectSafety_iface.lpVtbl = &httprequestObjectSafety;
1163 req->ref = 1;
1165 req->async = FALSE;
1166 req->verb = -1;
1167 req->url = req->user = req->password = NULL;
1169 req->state = READYSTATE_UNINITIALIZED;
1170 req->sink = NULL;
1172 req->bsc = NULL;
1173 req->status = 0;
1174 req->reqheader_size = 0;
1175 list_init(&req->reqheaders);
1176 req->site = NULL;
1177 req->safeopt = 0;
1179 *ppObj = &req->IXMLHTTPRequest_iface;
1181 TRACE("returning iface %p\n", *ppObj);
1183 return hr;
1186 #else
1188 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
1190 MESSAGE("This program tried to use a XMLHTTPRequest object, but\n"
1191 "libxml2 support was not present at compile time.\n");
1192 return E_NOTIMPL;
1195 #endif