include: Add the missing inaddr.h and in6addr.h include directives.
[wine.git] / dlls / msxml3 / httprequest.c
blob2385d18cc68f115d4b87254635c86d47424227dd
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 VariantInit(&str);
710 hr = VariantChangeType(&str, &password, 0, VT_BSTR);
711 if (hr == S_OK)
712 This->password = V_BSTR(&str);
714 httprequest_setreadystate(This, READYSTATE_LOADING);
716 return S_OK;
719 static HRESULT WINAPI httprequest_setRequestHeader(IXMLHTTPRequest *iface, BSTR header, BSTR value)
721 httprequest *This = impl_from_IXMLHTTPRequest( iface );
722 struct reqheader *entry;
724 TRACE("(%p)->(%s %s)\n", This, debugstr_w(header), debugstr_w(value));
726 if (!header || !*header) return E_INVALIDARG;
727 if (This->state != READYSTATE_LOADING) return E_FAIL;
728 if (!value) return E_INVALIDARG;
730 /* replace existing header value if already added */
731 LIST_FOR_EACH_ENTRY(entry, &This->reqheaders, struct reqheader, entry)
733 if (lstrcmpW(entry->header, header) == 0)
735 LONG length = SysStringLen(entry->value);
736 HRESULT hr;
738 hr = SysReAllocString(&entry->value, value) ? S_OK : E_OUTOFMEMORY;
740 if (hr == S_OK)
741 This->reqheader_size += (SysStringLen(entry->value) - length);
743 return hr;
747 entry = heap_alloc(sizeof(*entry));
748 if (!entry) return E_OUTOFMEMORY;
750 /* new header */
751 entry->header = SysAllocString(header);
752 entry->value = SysAllocString(value);
754 /* header length including null terminator */
755 This->reqheader_size += SysStringLen(entry->header) + sizeof(colspaceW)/sizeof(WCHAR) +
756 SysStringLen(entry->value) + sizeof(crlfW)/sizeof(WCHAR) - 1;
758 list_add_head(&This->reqheaders, &entry->entry);
760 return S_OK;
763 static HRESULT WINAPI httprequest_getResponseHeader(IXMLHTTPRequest *iface, BSTR bstrHeader, BSTR *pbstrValue)
765 httprequest *This = impl_from_IXMLHTTPRequest( iface );
767 FIXME("stub (%p) %s %p\n", This, debugstr_w(bstrHeader), pbstrValue);
769 return E_NOTIMPL;
772 static HRESULT WINAPI httprequest_getAllResponseHeaders(IXMLHTTPRequest *iface, BSTR *pbstrHeaders)
774 httprequest *This = impl_from_IXMLHTTPRequest( iface );
776 FIXME("stub (%p) %p\n", This, pbstrHeaders);
778 return E_NOTIMPL;
781 static HRESULT WINAPI httprequest_send(IXMLHTTPRequest *iface, VARIANT body)
783 httprequest *This = impl_from_IXMLHTTPRequest( iface );
784 BindStatusCallback *bsc = NULL;
785 HRESULT hr;
787 TRACE("(%p)->(%s)\n", This, debugstr_variant(&body));
789 if (This->state != READYSTATE_LOADING) return E_FAIL;
791 hr = BindStatusCallback_create(This, &bsc, &body);
792 if (FAILED(hr)) return hr;
794 BindStatusCallback_Detach(This->bsc);
795 This->bsc = bsc;
797 return hr;
800 static HRESULT WINAPI httprequest_abort(IXMLHTTPRequest *iface)
802 httprequest *This = impl_from_IXMLHTTPRequest( iface );
804 TRACE("(%p)\n", This);
806 BindStatusCallback_Detach(This->bsc);
807 This->bsc = NULL;
809 httprequest_setreadystate(This, READYSTATE_UNINITIALIZED);
811 return S_OK;
814 static HRESULT WINAPI httprequest_get_status(IXMLHTTPRequest *iface, LONG *status)
816 httprequest *This = impl_from_IXMLHTTPRequest( iface );
818 TRACE("(%p)->(%p)\n", This, status);
820 if (!status) return E_INVALIDARG;
821 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
823 *status = This->status;
825 return S_OK;
828 static HRESULT WINAPI httprequest_get_statusText(IXMLHTTPRequest *iface, BSTR *pbstrStatus)
830 httprequest *This = impl_from_IXMLHTTPRequest( iface );
832 FIXME("stub %p %p\n", This, pbstrStatus);
834 return E_NOTIMPL;
837 static HRESULT WINAPI httprequest_get_responseXML(IXMLHTTPRequest *iface, IDispatch **body)
839 httprequest *This = impl_from_IXMLHTTPRequest( iface );
840 IXMLDOMDocument3 *doc;
841 HRESULT hr;
842 BSTR str;
844 TRACE("(%p)->(%p)\n", This, body);
846 if (!body) return E_INVALIDARG;
847 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
849 hr = DOMDocument_create(MSXML_DEFAULT, NULL, (void**)&doc);
850 if (hr != S_OK) return hr;
852 hr = IXMLHTTPRequest_get_responseText(iface, &str);
853 if (hr == S_OK)
855 VARIANT_BOOL ok;
857 hr = IXMLDOMDocument3_loadXML(doc, str, &ok);
858 SysFreeString(str);
861 IXMLDOMDocument3_QueryInterface(doc, &IID_IDispatch, (void**)body);
862 IXMLDOMDocument3_Release(doc);
864 return hr;
867 static HRESULT WINAPI httprequest_get_responseText(IXMLHTTPRequest *iface, BSTR *body)
869 httprequest *This = impl_from_IXMLHTTPRequest( iface );
870 HGLOBAL hglobal;
871 HRESULT hr;
873 TRACE("(%p)->(%p)\n", This, body);
875 if (!body) return E_INVALIDARG;
876 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
878 hr = GetHGlobalFromStream(This->bsc->stream, &hglobal);
879 if (hr == S_OK)
881 xmlChar *ptr = GlobalLock(hglobal);
882 DWORD size = GlobalSize(hglobal);
883 xmlCharEncoding encoding = XML_CHAR_ENCODING_UTF8;
885 /* try to determine data encoding */
886 if (size >= 4)
888 encoding = xmlDetectCharEncoding(ptr, 4);
889 TRACE("detected encoding: %s\n", debugstr_a(xmlGetCharEncodingName(encoding)));
890 if ( encoding != XML_CHAR_ENCODING_UTF8 &&
891 encoding != XML_CHAR_ENCODING_UTF16LE &&
892 encoding != XML_CHAR_ENCODING_NONE )
894 FIXME("unsupported encoding: %s\n", debugstr_a(xmlGetCharEncodingName(encoding)));
895 GlobalUnlock(hglobal);
896 return E_FAIL;
900 /* without BOM assume UTF-8 */
901 if (encoding == XML_CHAR_ENCODING_UTF8 ||
902 encoding == XML_CHAR_ENCODING_NONE )
904 DWORD length = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)ptr, size, NULL, 0);
906 *body = SysAllocStringLen(NULL, length);
907 if (*body)
908 MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)ptr, size, *body, length);
910 else
911 *body = SysAllocStringByteLen((LPCSTR)ptr, size);
913 if (!*body) hr = E_OUTOFMEMORY;
914 GlobalUnlock(hglobal);
917 return hr;
920 static HRESULT WINAPI httprequest_get_responseBody(IXMLHTTPRequest *iface, VARIANT *body)
922 httprequest *This = impl_from_IXMLHTTPRequest( iface );
923 HGLOBAL hglobal;
924 HRESULT hr;
926 TRACE("(%p)->(%p)\n", This, body);
928 if (!body) return E_INVALIDARG;
929 if (This->state != READYSTATE_COMPLETE) return E_FAIL;
931 hr = GetHGlobalFromStream(This->bsc->stream, &hglobal);
932 if (hr == S_OK)
934 void *ptr = GlobalLock(hglobal);
935 DWORD size = GlobalSize(hglobal);
937 SAFEARRAYBOUND bound;
938 SAFEARRAY *array;
940 bound.lLbound = 0;
941 bound.cElements = size;
942 array = SafeArrayCreate(VT_UI1, 1, &bound);
944 if (array)
946 void *dest;
948 V_VT(body) = VT_ARRAY | VT_UI1;
949 V_ARRAY(body) = array;
951 hr = SafeArrayAccessData(array, &dest);
952 if (hr == S_OK)
954 memcpy(dest, ptr, size);
955 SafeArrayUnaccessData(array);
957 else
959 VariantClear(body);
962 else
963 hr = E_FAIL;
965 GlobalUnlock(hglobal);
968 return hr;
971 static HRESULT WINAPI httprequest_get_responseStream(IXMLHTTPRequest *iface, VARIANT *pvarBody)
973 httprequest *This = impl_from_IXMLHTTPRequest( iface );
975 FIXME("stub %p %p\n", This, pvarBody);
977 return E_NOTIMPL;
980 static HRESULT WINAPI httprequest_get_readyState(IXMLHTTPRequest *iface, LONG *state)
982 httprequest *This = impl_from_IXMLHTTPRequest( iface );
984 TRACE("(%p)->(%p)\n", This, state);
986 if (!state) return E_INVALIDARG;
988 *state = This->state;
989 return S_OK;
992 static HRESULT WINAPI httprequest_put_onreadystatechange(IXMLHTTPRequest *iface, IDispatch *sink)
994 httprequest *This = impl_from_IXMLHTTPRequest( iface );
996 TRACE("(%p)->(%p)\n", This, sink);
998 if (This->sink) IDispatch_Release(This->sink);
999 if ((This->sink = sink)) IDispatch_AddRef(This->sink);
1001 return S_OK;
1004 static const struct IXMLHTTPRequestVtbl dimimpl_vtbl =
1006 httprequest_QueryInterface,
1007 httprequest_AddRef,
1008 httprequest_Release,
1009 httprequest_GetTypeInfoCount,
1010 httprequest_GetTypeInfo,
1011 httprequest_GetIDsOfNames,
1012 httprequest_Invoke,
1013 httprequest_open,
1014 httprequest_setRequestHeader,
1015 httprequest_getResponseHeader,
1016 httprequest_getAllResponseHeaders,
1017 httprequest_send,
1018 httprequest_abort,
1019 httprequest_get_status,
1020 httprequest_get_statusText,
1021 httprequest_get_responseXML,
1022 httprequest_get_responseText,
1023 httprequest_get_responseBody,
1024 httprequest_get_responseStream,
1025 httprequest_get_readyState,
1026 httprequest_put_onreadystatechange
1029 /* IObjectWithSite */
1030 static HRESULT WINAPI
1031 httprequest_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
1033 httprequest *This = impl_from_IObjectWithSite(iface);
1034 return IXMLHTTPRequest_QueryInterface( (IXMLHTTPRequest *)This, riid, ppvObject );
1037 static ULONG WINAPI httprequest_ObjectWithSite_AddRef( IObjectWithSite* iface )
1039 httprequest *This = impl_from_IObjectWithSite(iface);
1040 return IXMLHTTPRequest_AddRef((IXMLHTTPRequest *)This);
1043 static ULONG WINAPI httprequest_ObjectWithSite_Release( IObjectWithSite* iface )
1045 httprequest *This = impl_from_IObjectWithSite(iface);
1046 return IXMLHTTPRequest_Release((IXMLHTTPRequest *)This);
1049 static HRESULT WINAPI httprequest_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
1051 httprequest *This = impl_from_IObjectWithSite(iface);
1053 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
1055 if ( !This->site )
1056 return E_FAIL;
1058 return IUnknown_QueryInterface( This->site, iid, ppvSite );
1061 static HRESULT WINAPI httprequest_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
1063 httprequest *This = impl_from_IObjectWithSite(iface);
1065 TRACE("(%p)->(%p)\n", iface, punk);
1067 if (punk)
1068 IUnknown_AddRef( punk );
1070 if(This->site)
1071 IUnknown_Release( This->site );
1073 This->site = punk;
1075 return S_OK;
1078 static const IObjectWithSiteVtbl httprequestObjectSite =
1080 httprequest_ObjectWithSite_QueryInterface,
1081 httprequest_ObjectWithSite_AddRef,
1082 httprequest_ObjectWithSite_Release,
1083 httprequest_ObjectWithSite_SetSite,
1084 httprequest_ObjectWithSite_GetSite
1087 /* IObjectSafety */
1088 static HRESULT WINAPI httprequest_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
1090 httprequest *This = impl_from_IObjectSafety(iface);
1091 return IXMLHTTPRequest_QueryInterface( (IXMLHTTPRequest *)This, riid, ppv );
1094 static ULONG WINAPI httprequest_Safety_AddRef(IObjectSafety *iface)
1096 httprequest *This = impl_from_IObjectSafety(iface);
1097 return IXMLHTTPRequest_AddRef((IXMLHTTPRequest *)This);
1100 static ULONG WINAPI httprequest_Safety_Release(IObjectSafety *iface)
1102 httprequest *This = impl_from_IObjectSafety(iface);
1103 return IXMLHTTPRequest_Release((IXMLHTTPRequest *)This);
1106 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
1108 static HRESULT WINAPI httprequest_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
1109 DWORD *supported, DWORD *enabled)
1111 httprequest *This = impl_from_IObjectSafety(iface);
1113 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
1115 if(!supported || !enabled) return E_POINTER;
1117 *supported = SAFETY_SUPPORTED_OPTIONS;
1118 *enabled = This->safeopt;
1120 return S_OK;
1123 static HRESULT WINAPI httprequest_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
1124 DWORD mask, DWORD enabled)
1126 httprequest *This = impl_from_IObjectSafety(iface);
1127 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
1129 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
1130 return E_FAIL;
1132 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
1134 return S_OK;
1137 #undef SAFETY_SUPPORTED_OPTIONS
1139 static const IObjectSafetyVtbl httprequestObjectSafety = {
1140 httprequest_Safety_QueryInterface,
1141 httprequest_Safety_AddRef,
1142 httprequest_Safety_Release,
1143 httprequest_Safety_GetInterfaceSafetyOptions,
1144 httprequest_Safety_SetInterfaceSafetyOptions
1147 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
1149 httprequest *req;
1150 HRESULT hr = S_OK;
1152 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
1154 req = heap_alloc( sizeof (*req) );
1155 if( !req )
1156 return E_OUTOFMEMORY;
1158 req->IXMLHTTPRequest_iface.lpVtbl = &dimimpl_vtbl;
1159 req->IObjectWithSite_iface.lpVtbl = &httprequestObjectSite;
1160 req->IObjectSafety_iface.lpVtbl = &httprequestObjectSafety;
1161 req->ref = 1;
1163 req->async = FALSE;
1164 req->verb = -1;
1165 req->url = req->user = req->password = NULL;
1167 req->state = READYSTATE_UNINITIALIZED;
1168 req->sink = NULL;
1170 req->bsc = NULL;
1171 req->status = 0;
1172 req->reqheader_size = 0;
1173 list_init(&req->reqheaders);
1174 req->site = NULL;
1175 req->safeopt = 0;
1177 *ppObj = &req->IXMLHTTPRequest_iface;
1179 TRACE("returning iface %p\n", *ppObj);
1181 return hr;
1184 #else
1186 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
1188 MESSAGE("This program tried to use a XMLHTTPRequest object, but\n"
1189 "libxml2 support was not present at compile time.\n");
1190 return E_NOTIMPL;
1193 #endif