msxml3: Add basic bind callback for moniker binding.
[wine] / dlls / msxml3 / httprequest.c
1 /*
2  *    IXMLHTTPRequest implementation
3  *
4  * Copyright 2008 Alistair Leslie-Hughes
5  *
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.
10  *
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.
15  *
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
19  */
20 #define COBJMACROS
21
22 #include "config.h"
23
24 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "ole2.h"
29 #include "msxml6.h"
30
31 #include "msxml_private.h"
32
33 #include "wine/debug.h"
34 #include "wine/list.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
37
38 #ifdef HAVE_LIBXML2
39
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};
43
44 typedef struct BindStatusCallback BindStatusCallback;
45
46 struct reqheader
47 {
48     struct list entry;
49     BSTR header;
50     BSTR value;
51 };
52
53 enum READYSTATE
54 {
55     STATE_UNINITIALIZED = 0,
56     STATE_LOADING       = 1,
57     STATE_LOADED        = 2,
58     STATE_INTERACTIVE   = 3,
59     STATE_COMPLETED     = 4
60 };
61
62 typedef struct
63 {
64     const struct IXMLHTTPRequestVtbl *lpVtbl;
65     LONG ref;
66
67     READYSTATE state;
68
69     /* request */
70     BINDVERB verb;
71     BSTR url;
72     BOOL async;
73     struct list reqheaders;
74
75     /* credentials */
76     BSTR user;
77     BSTR password;
78
79     /* bind callback */
80     BindStatusCallback *bsc;
81 } httprequest;
82
83 static inline httprequest *impl_from_IXMLHTTPRequest( IXMLHTTPRequest *iface )
84 {
85     return (httprequest *)((char*)iface - FIELD_OFFSET(httprequest, lpVtbl));
86 }
87
88 struct BindStatusCallback
89 {
90     const IBindStatusCallbackVtbl *lpBindStatusCallbackVtbl;
91     const IHttpNegotiateVtbl      *lpHttpNegotiateVtbl;
92     LONG ref;
93
94     IBinding *binding;
95     const httprequest *request;
96 };
97
98 static inline BindStatusCallback *impl_from_IBindStatusCallback( IBindStatusCallback *iface )
99 {
100     return (BindStatusCallback *)((char*)iface - FIELD_OFFSET(BindStatusCallback, lpBindStatusCallbackVtbl));
101 }
102
103 static inline BindStatusCallback *impl_from_IHttpNegotiate( IHttpNegotiate *iface )
104 {
105     return (BindStatusCallback *)((char*)iface - FIELD_OFFSET(BindStatusCallback, lpHttpNegotiateVtbl));
106 }
107
108 void BindStatusCallback_Detach(BindStatusCallback *bsc)
109 {
110     if (bsc)
111     {
112         if (bsc->binding) IBinding_Abort(bsc->binding);
113         bsc->request = NULL;
114         IBindStatusCallback_Release((IBindStatusCallback*)bsc);
115     }
116 }
117
118 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
119         REFIID riid, void **ppv)
120 {
121     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
122
123     *ppv = NULL;
124
125     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
126
127     if (IsEqualGUID(&IID_IUnknown, riid) ||
128         IsEqualGUID(&IID_IBindStatusCallback, riid))
129     {
130         *ppv = &This->lpBindStatusCallbackVtbl;
131     }
132     else if (IsEqualGUID(&IID_IServiceProvider, riid) ||
133              IsEqualGUID(&IID_IBindStatusCallbackEx, riid))
134     {
135         return E_NOINTERFACE;
136     }
137
138     if (*ppv)
139     {
140         IBindStatusCallback_AddRef(iface);
141         return S_OK;
142     }
143
144     FIXME("Unsupported riid = %s\n", debugstr_guid(riid));
145
146     return E_NOINTERFACE;
147 }
148
149 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
150 {
151     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
152     LONG ref = InterlockedIncrement(&This->ref);
153
154     TRACE("(%p) ref = %d\n", This, ref);
155
156     return ref;
157 }
158
159 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
160 {
161     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
162     LONG ref = InterlockedDecrement(&This->ref);
163
164     TRACE("(%p) ref = %d\n", This, ref);
165
166     if (!ref)
167     {
168         if (This->binding) IBinding_Release(This->binding);
169         heap_free(This);
170     }
171
172     return ref;
173 }
174
175 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
176         DWORD reserved, IBinding *pbind)
177 {
178     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
179
180     TRACE("(%p)->(%d %p)\n", This, reserved, pbind);
181
182     if (!pbind) return E_INVALIDARG;
183
184     This->binding = pbind;
185     IBinding_AddRef(pbind);
186
187     return S_OK;
188 }
189
190 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pPriority)
191 {
192     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
193
194     TRACE("(%p)->(%p)\n", This, pPriority);
195
196     return E_NOTIMPL;
197 }
198
199 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
200 {
201     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
202
203     TRACE("(%p)->(%d)\n", This, reserved);
204
205     return E_NOTIMPL;
206 }
207
208 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
209         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
210 {
211     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
212
213     TRACE("%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
214             debugstr_w(szStatusText));
215
216     return S_OK;
217 }
218
219 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
220         HRESULT hr, LPCWSTR error)
221 {
222     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
223
224     TRACE("(%p)->(0x%08x %s)\n", This, hr, debugstr_w(error));
225
226     return S_OK;
227 }
228
229 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
230         DWORD *bind_flags, BINDINFO *pbindinfo)
231 {
232     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
233
234     TRACE("(%p)->(%p %p)\n", This, bind_flags, pbindinfo);
235
236     *bind_flags = 0;
237     if (This->request->async) *bind_flags |= BINDF_ASYNCHRONOUS;
238
239     if (This->request->verb != BINDVERB_GET)
240     {
241         FIXME("only GET verb supported. Got %d\n", This->request->verb);
242         return E_FAIL;
243     }
244
245     pbindinfo->dwBindVerb = This->request->verb;
246
247     return S_OK;
248 }
249
250 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
251         DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
252 {
253     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
254
255     FIXME("(%p)->(%08x %d %p %p): stub\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
256
257     return E_NOTIMPL;
258 }
259
260 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
261         REFIID riid, IUnknown *punk)
262 {
263     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
264
265     FIXME("(%p)->(%s %p): stub\n", This, debugstr_guid(riid), punk);
266
267     return E_NOTIMPL;
268 }
269
270 #undef STATUSCLB_THIS
271
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
284 };
285
286 static HRESULT WINAPI BSCHttpNegotiate_QueryInterface(IHttpNegotiate *iface,
287         REFIID riid, void **ppv)
288 {
289     BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
290     return IBindStatusCallback_QueryInterface((IBindStatusCallback*)This, riid, ppv);
291 }
292
293 static ULONG WINAPI BSCHttpNegotiate_AddRef(IHttpNegotiate *iface)
294 {
295     BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
296     return IBindStatusCallback_AddRef((IBindStatusCallback*)This);
297 }
298
299 static ULONG WINAPI BSCHttpNegotiate_Release(IHttpNegotiate *iface)
300 {
301     BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
302     return IBindStatusCallback_Release((IBindStatusCallback*)This);
303 }
304
305 static HRESULT WINAPI BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate *iface,
306         LPCWSTR url, LPCWSTR headers, DWORD reserved, LPWSTR *add_headers)
307 {
308     BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
309
310     FIXME("(%p)->(%s %s %d %p): stub\n", This, debugstr_w(url), debugstr_w(headers), reserved, add_headers);
311
312     *add_headers = NULL;
313
314     return E_NOTIMPL;
315 }
316
317 static HRESULT WINAPI BSCHttpNegotiate_OnResponse(IHttpNegotiate *iface, DWORD code,
318         LPCWSTR resp_headers, LPCWSTR req_headers, LPWSTR *add_reqheaders)
319 {
320     BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
321
322     TRACE("(%p)->(%d %s %s %p)\n", This, code, debugstr_w(resp_headers),
323           debugstr_w(req_headers), add_reqheaders);
324
325     return S_OK;
326 }
327
328 #undef HTTPNEG2_THIS
329
330 static const IHttpNegotiateVtbl BSCHttpNegotiateVtbl = {
331     BSCHttpNegotiate_QueryInterface,
332     BSCHttpNegotiate_AddRef,
333     BSCHttpNegotiate_Release,
334     BSCHttpNegotiate_BeginningTransaction,
335     BSCHttpNegotiate_OnResponse
336 };
337
338 static HRESULT BindStatusCallback_create(const httprequest* This, BindStatusCallback **obj)
339 {
340     BindStatusCallback *bsc;
341     IBindCtx *pbc;
342     HRESULT hr;
343
344     hr = CreateBindCtx(0, &pbc);
345     if (hr != S_OK) return hr;
346
347     bsc = heap_alloc(sizeof(*bsc));
348     if (!bsc)
349     {
350         IBindCtx_Release(pbc);
351         return E_OUTOFMEMORY;
352     }
353
354     bsc->lpBindStatusCallbackVtbl = &BindStatusCallbackVtbl;
355     bsc->lpHttpNegotiateVtbl = &BSCHttpNegotiateVtbl;
356     bsc->ref = 1;
357     bsc->request = This;
358     bsc->binding = NULL;
359
360     hr = RegisterBindStatusCallback(pbc, (IBindStatusCallback*)bsc, NULL, 0);
361     if (hr == S_OK)
362     {
363         IMoniker *moniker;
364
365         hr = CreateURLMoniker(NULL, This->url, &moniker);
366         if (hr == S_OK)
367         {
368             IStream *stream;
369
370             hr = IMoniker_BindToStorage(moniker, pbc, NULL, &IID_IStream, (void**)&stream);
371             IMoniker_Release(moniker);
372             if (stream) IStream_Release(stream);
373         }
374         IBindCtx_Release(pbc);
375     }
376
377     if (FAILED(hr))
378     {
379         IBindStatusCallback_Release((IBindStatusCallback*)bsc);
380         bsc = NULL;
381     }
382
383     *obj = bsc;
384     return hr;
385 }
386
387 /* TODO: process OnChange callback */
388 static void httprequest_setreadystate(httprequest *This, READYSTATE state)
389 {
390     This->state = state;
391 }
392
393 static HRESULT WINAPI httprequest_QueryInterface(IXMLHTTPRequest *iface, REFIID riid, void **ppvObject)
394 {
395     httprequest *This = impl_from_IXMLHTTPRequest( iface );
396     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
397
398     if ( IsEqualGUID( riid, &IID_IXMLHTTPRequest) ||
399          IsEqualGUID( riid, &IID_IDispatch) ||
400          IsEqualGUID( riid, &IID_IUnknown) )
401     {
402         *ppvObject = iface;
403     }
404     else
405     {
406         FIXME("Unsupported interface %s\n", debugstr_guid(riid));
407         return E_NOINTERFACE;
408     }
409
410     IXMLHTTPRequest_AddRef( iface );
411
412     return S_OK;
413 }
414
415 static ULONG WINAPI httprequest_AddRef(IXMLHTTPRequest *iface)
416 {
417     httprequest *This = impl_from_IXMLHTTPRequest( iface );
418     ULONG ref = InterlockedIncrement( &This->ref );
419     TRACE("(%p)->(%u)\n", This, ref );
420     return ref;
421 }
422
423 static ULONG WINAPI httprequest_Release(IXMLHTTPRequest *iface)
424 {
425     httprequest *This = impl_from_IXMLHTTPRequest( iface );
426     ULONG ref = InterlockedDecrement( &This->ref );
427
428     TRACE("(%p)->(%u)\n", This, ref );
429
430     if ( ref == 0 )
431     {
432         struct reqheader *header, *header2;
433
434         SysFreeString(This->url);
435         SysFreeString(This->user);
436         SysFreeString(This->password);
437
438         /* request headers */
439         LIST_FOR_EACH_ENTRY_SAFE(header, header2, &This->reqheaders, struct reqheader, entry)
440         {
441             list_remove(&header->entry);
442             SysFreeString(header->header);
443             SysFreeString(header->value);
444         }
445
446         /* detach callback object */
447         BindStatusCallback_Detach(This->bsc);
448
449         heap_free( This );
450     }
451
452     return ref;
453 }
454
455 static HRESULT WINAPI httprequest_GetTypeInfoCount(IXMLHTTPRequest *iface, UINT *pctinfo)
456 {
457     httprequest *This = impl_from_IXMLHTTPRequest( iface );
458
459     TRACE("(%p)->(%p)\n", This, pctinfo);
460
461     *pctinfo = 1;
462
463     return S_OK;
464 }
465
466 static HRESULT WINAPI httprequest_GetTypeInfo(IXMLHTTPRequest *iface, UINT iTInfo,
467         LCID lcid, ITypeInfo **ppTInfo)
468 {
469     httprequest *This = impl_from_IXMLHTTPRequest( iface );
470     HRESULT hr;
471
472     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
473
474     hr = get_typeinfo(IXMLHTTPRequest_tid, ppTInfo);
475
476     return hr;
477 }
478
479 static HRESULT WINAPI httprequest_GetIDsOfNames(IXMLHTTPRequest *iface, REFIID riid,
480         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
481 {
482     httprequest *This = impl_from_IXMLHTTPRequest( iface );
483     ITypeInfo *typeinfo;
484     HRESULT hr;
485
486     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
487           lcid, rgDispId);
488
489     if(!rgszNames || cNames == 0 || !rgDispId)
490         return E_INVALIDARG;
491
492     hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
493     if(SUCCEEDED(hr))
494     {
495         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
496         ITypeInfo_Release(typeinfo);
497     }
498
499     return hr;
500 }
501
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)
505 {
506     httprequest *This = impl_from_IXMLHTTPRequest( iface );
507     ITypeInfo *typeinfo;
508     HRESULT hr;
509
510     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
511           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
512
513     hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
514     if(SUCCEEDED(hr))
515     {
516         hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
517                 pVarResult, pExcepInfo, puArgErr);
518         ITypeInfo_Release(typeinfo);
519     }
520
521     return hr;
522 }
523
524 static HRESULT WINAPI httprequest_open(IXMLHTTPRequest *iface, BSTR method, BSTR url,
525         VARIANT async, VARIANT user, VARIANT password)
526 {
527     httprequest *This = impl_from_IXMLHTTPRequest( iface );
528     HRESULT hr;
529     VARIANT str;
530
531     TRACE("(%p)->(%s %s)\n", This, debugstr_w(method), debugstr_w(url));
532
533     if (!method || !url) return E_INVALIDARG;
534
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;
540
541     if (lstrcmpiW(method, MethodGetW) == 0)
542     {
543         This->verb = BINDVERB_GET;
544     }
545     else if (lstrcmpiW(method, MethodPutW) == 0)
546     {
547         This->verb = BINDVERB_PUT;
548     }
549     else if (lstrcmpiW(method, MethodPostW) == 0)
550     {
551         This->verb = BINDVERB_POST;
552     }
553     else
554     {
555         FIXME("unsupported request type %s\n", debugstr_w(method));
556         This->verb = -1;
557         return E_FAIL;
558     }
559
560     This->url = SysAllocString(url);
561
562     hr = VariantChangeType(&async, &async, 0, VT_BOOL);
563     This->async = hr == S_OK && V_BOOL(&async) == VARIANT_TRUE;
564
565     VariantInit(&str);
566     hr = VariantChangeType(&str, &user, 0, VT_BSTR);
567     if (hr == S_OK)
568         This->user = V_BSTR(&str);
569
570     hr = VariantChangeType(&str, &password, 0, VT_BSTR);
571     if (hr == S_OK)
572         This->password = V_BSTR(&str);
573
574     httprequest_setreadystate(This, STATE_LOADING);
575
576     return S_OK;
577 }
578
579 static HRESULT WINAPI httprequest_setRequestHeader(IXMLHTTPRequest *iface, BSTR header, BSTR value)
580 {
581     httprequest *This = impl_from_IXMLHTTPRequest( iface );
582     struct reqheader *entry;
583
584     TRACE("(%p)->(%s %s)\n", This, debugstr_w(header), debugstr_w(value));
585
586     if (!header || !*header) return E_INVALIDARG;
587     if (This->state != STATE_LOADING) return E_FAIL;
588     if (!value) return E_INVALIDARG;
589
590     /* replace existing header value if already added */
591     LIST_FOR_EACH_ENTRY(entry, &This->reqheaders, struct reqheader, entry)
592     {
593         if (lstrcmpW(entry->header, header) == 0)
594         {
595             return SysReAllocString(&entry->value, value) ? S_OK : E_OUTOFMEMORY;
596         }
597     }
598
599     entry = heap_alloc(sizeof(*entry));
600     if (!entry) return E_OUTOFMEMORY;
601
602     /* new header */
603     entry->header = SysAllocString(header);
604     entry->value  = SysAllocString(value);
605
606     list_add_head(&This->reqheaders, &entry->entry);
607
608     return S_OK;
609 }
610
611 static HRESULT WINAPI httprequest_getResponseHeader(IXMLHTTPRequest *iface, BSTR bstrHeader, BSTR *pbstrValue)
612 {
613     httprequest *This = impl_from_IXMLHTTPRequest( iface );
614
615     FIXME("stub (%p) %s %p\n", This, debugstr_w(bstrHeader), pbstrValue);
616
617     return E_NOTIMPL;
618 }
619
620 static HRESULT WINAPI httprequest_getAllResponseHeaders(IXMLHTTPRequest *iface, BSTR *pbstrHeaders)
621 {
622     httprequest *This = impl_from_IXMLHTTPRequest( iface );
623
624     FIXME("stub (%p) %p\n", This, pbstrHeaders);
625
626     return E_NOTIMPL;
627 }
628
629 static HRESULT WINAPI httprequest_send(IXMLHTTPRequest *iface, VARIANT varBody)
630 {
631     httprequest *This = impl_from_IXMLHTTPRequest( iface );
632     BindStatusCallback *bsc = NULL;
633     HRESULT hr;
634
635     TRACE("(%p)\n", This);
636
637     if (This->state != STATE_LOADING) return E_FAIL;
638
639     hr = BindStatusCallback_create(This, &bsc);
640     if (FAILED(hr)) return hr;
641
642     BindStatusCallback_Detach(This->bsc);
643     This->bsc = bsc;
644
645     return hr;
646 }
647
648 static HRESULT WINAPI httprequest_abort(IXMLHTTPRequest *iface)
649 {
650     httprequest *This = impl_from_IXMLHTTPRequest( iface );
651
652     FIXME("stub (%p)\n", This);
653
654     return E_NOTIMPL;
655 }
656
657 static HRESULT WINAPI httprequest_get_status(IXMLHTTPRequest *iface, LONG *plStatus)
658 {
659     httprequest *This = impl_from_IXMLHTTPRequest( iface );
660
661     FIXME("stub %p %p\n", This, plStatus);
662
663     return E_NOTIMPL;
664 }
665
666 static HRESULT WINAPI httprequest_get_statusText(IXMLHTTPRequest *iface, BSTR *pbstrStatus)
667 {
668     httprequest *This = impl_from_IXMLHTTPRequest( iface );
669
670     FIXME("stub %p %p\n", This, pbstrStatus);
671
672     return E_NOTIMPL;
673 }
674
675 static HRESULT WINAPI httprequest_get_responseXML(IXMLHTTPRequest *iface, IDispatch **ppBody)
676 {
677     httprequest *This = impl_from_IXMLHTTPRequest( iface );
678
679     FIXME("stub %p %p\n", This, ppBody);
680
681     return E_NOTIMPL;
682 }
683
684 static HRESULT WINAPI httprequest_get_responseText(IXMLHTTPRequest *iface, BSTR *pbstrBody)
685 {
686     httprequest *This = impl_from_IXMLHTTPRequest( iface );
687
688     FIXME("stub %p %p\n", This, pbstrBody);
689
690     return E_NOTIMPL;
691 }
692
693 static HRESULT WINAPI httprequest_get_responseBody(IXMLHTTPRequest *iface, VARIANT *pvarBody)
694 {
695     httprequest *This = impl_from_IXMLHTTPRequest( iface );
696
697     FIXME("stub %p %p\n", This, pvarBody);
698
699     return E_NOTIMPL;
700 }
701
702 static HRESULT WINAPI httprequest_get_responseStream(IXMLHTTPRequest *iface, VARIANT *pvarBody)
703 {
704     httprequest *This = impl_from_IXMLHTTPRequest( iface );
705
706     FIXME("stub %p %p\n", This, pvarBody);
707
708     return E_NOTIMPL;
709 }
710
711 static HRESULT WINAPI httprequest_get_readyState(IXMLHTTPRequest *iface, LONG *state)
712 {
713     httprequest *This = impl_from_IXMLHTTPRequest( iface );
714
715     TRACE("(%p)->(%p)\n", This, state);
716
717     if (!state) return E_INVALIDARG;
718
719     *state = This->state;
720     return S_OK;
721 }
722
723 static HRESULT WINAPI httprequest_put_onreadystatechange(IXMLHTTPRequest *iface, IDispatch *pReadyStateSink)
724 {
725     httprequest *This = impl_from_IXMLHTTPRequest( iface );
726
727     FIXME("stub %p %p\n", This, pReadyStateSink);
728
729     return E_NOTIMPL;
730 }
731
732 static const struct IXMLHTTPRequestVtbl dimimpl_vtbl =
733 {
734     httprequest_QueryInterface,
735     httprequest_AddRef,
736     httprequest_Release,
737     httprequest_GetTypeInfoCount,
738     httprequest_GetTypeInfo,
739     httprequest_GetIDsOfNames,
740     httprequest_Invoke,
741     httprequest_open,
742     httprequest_setRequestHeader,
743     httprequest_getResponseHeader,
744     httprequest_getAllResponseHeaders,
745     httprequest_send,
746     httprequest_abort,
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
755 };
756
757 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
758 {
759     httprequest *req;
760     HRESULT hr = S_OK;
761
762     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
763
764     req = heap_alloc( sizeof (*req) );
765     if( !req )
766         return E_OUTOFMEMORY;
767
768     req->lpVtbl = &dimimpl_vtbl;
769     req->ref = 1;
770
771     req->async = FALSE;
772     req->verb = -1;
773     req->url = req->user = req->password = NULL;
774     req->state = STATE_UNINITIALIZED;
775     req->bsc = NULL;
776     list_init(&req->reqheaders);
777
778     *ppObj = &req->lpVtbl;
779
780     TRACE("returning iface %p\n", *ppObj);
781
782     return hr;
783 }
784
785 #else
786
787 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
788 {
789     MESSAGE("This program tried to use a XMLHTTPRequest object, but\n"
790             "libxml2 support was not present at compile time.\n");
791     return E_NOTIMPL;
792 }
793
794 #endif