2 * IXMLHTTPRequest implementation
4 * Copyright 2008 Alistair Leslie-Hughes
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "msxml_private.h"
33 #include "wine/debug.h"
34 #include "wine/list.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
40 static const WCHAR MethodGetW[] = {'G','E','T',0};
41 static const WCHAR MethodPutW[] = {'P','U','T',0};
42 static const WCHAR MethodPostW[] = {'P','O','S','T',0};
44 typedef struct BindStatusCallback BindStatusCallback;
55 STATE_UNINITIALIZED = 0,
58 STATE_INTERACTIVE = 3,
64 const struct IXMLHTTPRequestVtbl *lpVtbl;
73 struct list reqheaders;
80 BindStatusCallback *bsc;
83 static inline httprequest *impl_from_IXMLHTTPRequest( IXMLHTTPRequest *iface )
85 return (httprequest *)((char*)iface - FIELD_OFFSET(httprequest, lpVtbl));
88 struct BindStatusCallback
90 const IBindStatusCallbackVtbl *lpBindStatusCallbackVtbl;
91 const IHttpNegotiateVtbl *lpHttpNegotiateVtbl;
95 const httprequest *request;
98 static inline BindStatusCallback *impl_from_IBindStatusCallback( IBindStatusCallback *iface )
100 return (BindStatusCallback *)((char*)iface - FIELD_OFFSET(BindStatusCallback, lpBindStatusCallbackVtbl));
103 static inline BindStatusCallback *impl_from_IHttpNegotiate( IHttpNegotiate *iface )
105 return (BindStatusCallback *)((char*)iface - FIELD_OFFSET(BindStatusCallback, lpHttpNegotiateVtbl));
108 void BindStatusCallback_Detach(BindStatusCallback *bsc)
112 if (bsc->binding) IBinding_Abort(bsc->binding);
114 IBindStatusCallback_Release((IBindStatusCallback*)bsc);
118 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
119 REFIID riid, void **ppv)
121 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
125 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
127 if (IsEqualGUID(&IID_IUnknown, riid) ||
128 IsEqualGUID(&IID_IBindStatusCallback, riid))
130 *ppv = &This->lpBindStatusCallbackVtbl;
132 else if (IsEqualGUID(&IID_IServiceProvider, riid) ||
133 IsEqualGUID(&IID_IBindStatusCallbackEx, riid))
135 return E_NOINTERFACE;
140 IBindStatusCallback_AddRef(iface);
144 FIXME("Unsupported riid = %s\n", debugstr_guid(riid));
146 return E_NOINTERFACE;
149 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
151 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
152 LONG ref = InterlockedIncrement(&This->ref);
154 TRACE("(%p) ref = %d\n", This, ref);
159 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
161 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
162 LONG ref = InterlockedDecrement(&This->ref);
164 TRACE("(%p) ref = %d\n", This, ref);
168 if (This->binding) IBinding_Release(This->binding);
175 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
176 DWORD reserved, IBinding *pbind)
178 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
180 TRACE("(%p)->(%d %p)\n", This, reserved, pbind);
182 if (!pbind) return E_INVALIDARG;
184 This->binding = pbind;
185 IBinding_AddRef(pbind);
190 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pPriority)
192 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
194 TRACE("(%p)->(%p)\n", This, pPriority);
199 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
201 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
203 TRACE("(%p)->(%d)\n", This, reserved);
208 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
209 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
211 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
213 TRACE("%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
214 debugstr_w(szStatusText));
219 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
220 HRESULT hr, LPCWSTR error)
222 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
224 TRACE("(%p)->(0x%08x %s)\n", This, hr, debugstr_w(error));
229 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
230 DWORD *bind_flags, BINDINFO *pbindinfo)
232 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
234 TRACE("(%p)->(%p %p)\n", This, bind_flags, pbindinfo);
237 if (This->request->async) *bind_flags |= BINDF_ASYNCHRONOUS;
239 if (This->request->verb != BINDVERB_GET)
241 FIXME("only GET verb supported. Got %d\n", This->request->verb);
245 pbindinfo->dwBindVerb = This->request->verb;
250 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
251 DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
253 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
255 FIXME("(%p)->(%08x %d %p %p): stub\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
260 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
261 REFIID riid, IUnknown *punk)
263 BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
265 FIXME("(%p)->(%s %p): stub\n", This, debugstr_guid(riid), punk);
270 #undef STATUSCLB_THIS
272 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
273 BindStatusCallback_QueryInterface,
274 BindStatusCallback_AddRef,
275 BindStatusCallback_Release,
276 BindStatusCallback_OnStartBinding,
277 BindStatusCallback_GetPriority,
278 BindStatusCallback_OnLowResource,
279 BindStatusCallback_OnProgress,
280 BindStatusCallback_OnStopBinding,
281 BindStatusCallback_GetBindInfo,
282 BindStatusCallback_OnDataAvailable,
283 BindStatusCallback_OnObjectAvailable
286 static HRESULT WINAPI BSCHttpNegotiate_QueryInterface(IHttpNegotiate *iface,
287 REFIID riid, void **ppv)
289 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
290 return IBindStatusCallback_QueryInterface((IBindStatusCallback*)This, riid, ppv);
293 static ULONG WINAPI BSCHttpNegotiate_AddRef(IHttpNegotiate *iface)
295 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
296 return IBindStatusCallback_AddRef((IBindStatusCallback*)This);
299 static ULONG WINAPI BSCHttpNegotiate_Release(IHttpNegotiate *iface)
301 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
302 return IBindStatusCallback_Release((IBindStatusCallback*)This);
305 static HRESULT WINAPI BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate *iface,
306 LPCWSTR url, LPCWSTR headers, DWORD reserved, LPWSTR *add_headers)
308 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
310 FIXME("(%p)->(%s %s %d %p): stub\n", This, debugstr_w(url), debugstr_w(headers), reserved, add_headers);
317 static HRESULT WINAPI BSCHttpNegotiate_OnResponse(IHttpNegotiate *iface, DWORD code,
318 LPCWSTR resp_headers, LPCWSTR req_headers, LPWSTR *add_reqheaders)
320 BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
322 TRACE("(%p)->(%d %s %s %p)\n", This, code, debugstr_w(resp_headers),
323 debugstr_w(req_headers), add_reqheaders);
330 static const IHttpNegotiateVtbl BSCHttpNegotiateVtbl = {
331 BSCHttpNegotiate_QueryInterface,
332 BSCHttpNegotiate_AddRef,
333 BSCHttpNegotiate_Release,
334 BSCHttpNegotiate_BeginningTransaction,
335 BSCHttpNegotiate_OnResponse
338 static HRESULT BindStatusCallback_create(const httprequest* This, BindStatusCallback **obj)
340 BindStatusCallback *bsc;
344 hr = CreateBindCtx(0, &pbc);
345 if (hr != S_OK) return hr;
347 bsc = heap_alloc(sizeof(*bsc));
350 IBindCtx_Release(pbc);
351 return E_OUTOFMEMORY;
354 bsc->lpBindStatusCallbackVtbl = &BindStatusCallbackVtbl;
355 bsc->lpHttpNegotiateVtbl = &BSCHttpNegotiateVtbl;
360 hr = RegisterBindStatusCallback(pbc, (IBindStatusCallback*)bsc, NULL, 0);
365 hr = CreateURLMoniker(NULL, This->url, &moniker);
370 hr = IMoniker_BindToStorage(moniker, pbc, NULL, &IID_IStream, (void**)&stream);
371 IMoniker_Release(moniker);
372 if (stream) IStream_Release(stream);
374 IBindCtx_Release(pbc);
379 IBindStatusCallback_Release((IBindStatusCallback*)bsc);
387 /* TODO: process OnChange callback */
388 static void httprequest_setreadystate(httprequest *This, READYSTATE state)
393 static HRESULT WINAPI httprequest_QueryInterface(IXMLHTTPRequest *iface, REFIID riid, void **ppvObject)
395 httprequest *This = impl_from_IXMLHTTPRequest( iface );
396 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
398 if ( IsEqualGUID( riid, &IID_IXMLHTTPRequest) ||
399 IsEqualGUID( riid, &IID_IDispatch) ||
400 IsEqualGUID( riid, &IID_IUnknown) )
406 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
407 return E_NOINTERFACE;
410 IXMLHTTPRequest_AddRef( iface );
415 static ULONG WINAPI httprequest_AddRef(IXMLHTTPRequest *iface)
417 httprequest *This = impl_from_IXMLHTTPRequest( iface );
418 ULONG ref = InterlockedIncrement( &This->ref );
419 TRACE("(%p)->(%u)\n", This, ref );
423 static ULONG WINAPI httprequest_Release(IXMLHTTPRequest *iface)
425 httprequest *This = impl_from_IXMLHTTPRequest( iface );
426 ULONG ref = InterlockedDecrement( &This->ref );
428 TRACE("(%p)->(%u)\n", This, ref );
432 struct reqheader *header, *header2;
434 SysFreeString(This->url);
435 SysFreeString(This->user);
436 SysFreeString(This->password);
438 /* request headers */
439 LIST_FOR_EACH_ENTRY_SAFE(header, header2, &This->reqheaders, struct reqheader, entry)
441 list_remove(&header->entry);
442 SysFreeString(header->header);
443 SysFreeString(header->value);
446 /* detach callback object */
447 BindStatusCallback_Detach(This->bsc);
455 static HRESULT WINAPI httprequest_GetTypeInfoCount(IXMLHTTPRequest *iface, UINT *pctinfo)
457 httprequest *This = impl_from_IXMLHTTPRequest( iface );
459 TRACE("(%p)->(%p)\n", This, pctinfo);
466 static HRESULT WINAPI httprequest_GetTypeInfo(IXMLHTTPRequest *iface, UINT iTInfo,
467 LCID lcid, ITypeInfo **ppTInfo)
469 httprequest *This = impl_from_IXMLHTTPRequest( iface );
472 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
474 hr = get_typeinfo(IXMLHTTPRequest_tid, ppTInfo);
479 static HRESULT WINAPI httprequest_GetIDsOfNames(IXMLHTTPRequest *iface, REFIID riid,
480 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
482 httprequest *This = impl_from_IXMLHTTPRequest( iface );
486 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
489 if(!rgszNames || cNames == 0 || !rgDispId)
492 hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
495 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
496 ITypeInfo_Release(typeinfo);
502 static HRESULT WINAPI httprequest_Invoke(IXMLHTTPRequest *iface, DISPID dispIdMember, REFIID riid,
503 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
504 EXCEPINFO *pExcepInfo, UINT *puArgErr)
506 httprequest *This = impl_from_IXMLHTTPRequest( iface );
510 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
511 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
513 hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
516 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
517 pVarResult, pExcepInfo, puArgErr);
518 ITypeInfo_Release(typeinfo);
524 static HRESULT WINAPI httprequest_open(IXMLHTTPRequest *iface, BSTR method, BSTR url,
525 VARIANT async, VARIANT user, VARIANT password)
527 httprequest *This = impl_from_IXMLHTTPRequest( iface );
531 TRACE("(%p)->(%s %s)\n", This, debugstr_w(method), debugstr_w(url));
533 if (!method || !url) return E_INVALIDARG;
535 /* free previously set data */
536 SysFreeString(This->url);
537 SysFreeString(This->user);
538 SysFreeString(This->password);
539 This->url = This->user = This->password = NULL;
541 if (lstrcmpiW(method, MethodGetW) == 0)
543 This->verb = BINDVERB_GET;
545 else if (lstrcmpiW(method, MethodPutW) == 0)
547 This->verb = BINDVERB_PUT;
549 else if (lstrcmpiW(method, MethodPostW) == 0)
551 This->verb = BINDVERB_POST;
555 FIXME("unsupported request type %s\n", debugstr_w(method));
560 This->url = SysAllocString(url);
562 hr = VariantChangeType(&async, &async, 0, VT_BOOL);
563 This->async = hr == S_OK && V_BOOL(&async) == VARIANT_TRUE;
566 hr = VariantChangeType(&str, &user, 0, VT_BSTR);
568 This->user = V_BSTR(&str);
570 hr = VariantChangeType(&str, &password, 0, VT_BSTR);
572 This->password = V_BSTR(&str);
574 httprequest_setreadystate(This, STATE_LOADING);
579 static HRESULT WINAPI httprequest_setRequestHeader(IXMLHTTPRequest *iface, BSTR header, BSTR value)
581 httprequest *This = impl_from_IXMLHTTPRequest( iface );
582 struct reqheader *entry;
584 TRACE("(%p)->(%s %s)\n", This, debugstr_w(header), debugstr_w(value));
586 if (!header || !*header) return E_INVALIDARG;
587 if (This->state != STATE_LOADING) return E_FAIL;
588 if (!value) return E_INVALIDARG;
590 /* replace existing header value if already added */
591 LIST_FOR_EACH_ENTRY(entry, &This->reqheaders, struct reqheader, entry)
593 if (lstrcmpW(entry->header, header) == 0)
595 return SysReAllocString(&entry->value, value) ? S_OK : E_OUTOFMEMORY;
599 entry = heap_alloc(sizeof(*entry));
600 if (!entry) return E_OUTOFMEMORY;
603 entry->header = SysAllocString(header);
604 entry->value = SysAllocString(value);
606 list_add_head(&This->reqheaders, &entry->entry);
611 static HRESULT WINAPI httprequest_getResponseHeader(IXMLHTTPRequest *iface, BSTR bstrHeader, BSTR *pbstrValue)
613 httprequest *This = impl_from_IXMLHTTPRequest( iface );
615 FIXME("stub (%p) %s %p\n", This, debugstr_w(bstrHeader), pbstrValue);
620 static HRESULT WINAPI httprequest_getAllResponseHeaders(IXMLHTTPRequest *iface, BSTR *pbstrHeaders)
622 httprequest *This = impl_from_IXMLHTTPRequest( iface );
624 FIXME("stub (%p) %p\n", This, pbstrHeaders);
629 static HRESULT WINAPI httprequest_send(IXMLHTTPRequest *iface, VARIANT varBody)
631 httprequest *This = impl_from_IXMLHTTPRequest( iface );
632 BindStatusCallback *bsc = NULL;
635 TRACE("(%p)\n", This);
637 if (This->state != STATE_LOADING) return E_FAIL;
639 hr = BindStatusCallback_create(This, &bsc);
640 if (FAILED(hr)) return hr;
642 BindStatusCallback_Detach(This->bsc);
648 static HRESULT WINAPI httprequest_abort(IXMLHTTPRequest *iface)
650 httprequest *This = impl_from_IXMLHTTPRequest( iface );
652 FIXME("stub (%p)\n", This);
657 static HRESULT WINAPI httprequest_get_status(IXMLHTTPRequest *iface, LONG *plStatus)
659 httprequest *This = impl_from_IXMLHTTPRequest( iface );
661 FIXME("stub %p %p\n", This, plStatus);
666 static HRESULT WINAPI httprequest_get_statusText(IXMLHTTPRequest *iface, BSTR *pbstrStatus)
668 httprequest *This = impl_from_IXMLHTTPRequest( iface );
670 FIXME("stub %p %p\n", This, pbstrStatus);
675 static HRESULT WINAPI httprequest_get_responseXML(IXMLHTTPRequest *iface, IDispatch **ppBody)
677 httprequest *This = impl_from_IXMLHTTPRequest( iface );
679 FIXME("stub %p %p\n", This, ppBody);
684 static HRESULT WINAPI httprequest_get_responseText(IXMLHTTPRequest *iface, BSTR *pbstrBody)
686 httprequest *This = impl_from_IXMLHTTPRequest( iface );
688 FIXME("stub %p %p\n", This, pbstrBody);
693 static HRESULT WINAPI httprequest_get_responseBody(IXMLHTTPRequest *iface, VARIANT *pvarBody)
695 httprequest *This = impl_from_IXMLHTTPRequest( iface );
697 FIXME("stub %p %p\n", This, pvarBody);
702 static HRESULT WINAPI httprequest_get_responseStream(IXMLHTTPRequest *iface, VARIANT *pvarBody)
704 httprequest *This = impl_from_IXMLHTTPRequest( iface );
706 FIXME("stub %p %p\n", This, pvarBody);
711 static HRESULT WINAPI httprequest_get_readyState(IXMLHTTPRequest *iface, LONG *state)
713 httprequest *This = impl_from_IXMLHTTPRequest( iface );
715 TRACE("(%p)->(%p)\n", This, state);
717 if (!state) return E_INVALIDARG;
719 *state = This->state;
723 static HRESULT WINAPI httprequest_put_onreadystatechange(IXMLHTTPRequest *iface, IDispatch *pReadyStateSink)
725 httprequest *This = impl_from_IXMLHTTPRequest( iface );
727 FIXME("stub %p %p\n", This, pReadyStateSink);
732 static const struct IXMLHTTPRequestVtbl dimimpl_vtbl =
734 httprequest_QueryInterface,
737 httprequest_GetTypeInfoCount,
738 httprequest_GetTypeInfo,
739 httprequest_GetIDsOfNames,
742 httprequest_setRequestHeader,
743 httprequest_getResponseHeader,
744 httprequest_getAllResponseHeaders,
747 httprequest_get_status,
748 httprequest_get_statusText,
749 httprequest_get_responseXML,
750 httprequest_get_responseText,
751 httprequest_get_responseBody,
752 httprequest_get_responseStream,
753 httprequest_get_readyState,
754 httprequest_put_onreadystatechange
757 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
762 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
764 req = heap_alloc( sizeof (*req) );
766 return E_OUTOFMEMORY;
768 req->lpVtbl = &dimimpl_vtbl;
773 req->url = req->user = req->password = NULL;
774 req->state = STATE_UNINITIALIZED;
776 list_init(&req->reqheaders);
778 *ppObj = &req->lpVtbl;
780 TRACE("returning iface %p\n", *ppObj);
787 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
789 MESSAGE("This program tried to use a XMLHTTPRequest object, but\n"
790 "libxml2 support was not present at compile time.\n");