d3d9: Don't expose wined3d internal flags to the application.
[wine] / dlls / msxml3 / httprequest.c
1 /*
2  *    IXMLHTTPRequest implementation
3  *
4  * Copyright 2008 Alistair Leslie-Hughes
5  * Copyright 2010-2012 Nikolay Sivov for CodeWeavers
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #define COBJMACROS
23 #define NONAMELESSUNION
24
25 #include "config.h"
26
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
33
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winuser.h"
37 #include "ole2.h"
38 #include "msxml6.h"
39 #include "objsafe.h"
40
41 #include "msxml_private.h"
42
43 #include "wine/debug.h"
44 #include "wine/list.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
47
48 #ifdef HAVE_LIBXML2
49
50 static const WCHAR colspaceW[] = {':',' ',0};
51 static const WCHAR crlfW[] = {'\r','\n',0};
52
53 typedef struct BindStatusCallback BindStatusCallback;
54
55 struct httpheader
56 {
57     struct list entry;
58     BSTR header;
59     BSTR value;
60 };
61
62 typedef struct
63 {
64     IXMLHTTPRequest IXMLHTTPRequest_iface;
65     IObjectWithSite IObjectWithSite_iface;
66     IObjectSafety   IObjectSafety_iface;
67     LONG ref;
68
69     READYSTATE state;
70     IDispatch *sink;
71
72     /* request */
73     BINDVERB verb;
74     BSTR custom;
75     BSTR url;
76     BOOL async;
77     struct list reqheaders;
78     /* cached resulting custom request headers string length in WCHARs */
79     LONG reqheader_size;
80     /* use UTF-8 content type */
81     BOOL use_utf8_content;
82
83     /* response headers */
84     struct list respheaders;
85     BSTR raw_respheaders;
86
87     /* credentials */
88     BSTR user;
89     BSTR password;
90
91     /* bind callback */
92     BindStatusCallback *bsc;
93     LONG status;
94
95     /* IObjectWithSite*/
96     IUnknown *site;
97
98     /* IObjectSafety */
99     DWORD safeopt;
100 } httprequest;
101
102 static inline httprequest *impl_from_IXMLHTTPRequest( IXMLHTTPRequest *iface )
103 {
104     return CONTAINING_RECORD(iface, httprequest, IXMLHTTPRequest_iface);
105 }
106
107 static inline httprequest *impl_from_IObjectWithSite(IObjectWithSite *iface)
108 {
109     return CONTAINING_RECORD(iface, httprequest, IObjectWithSite_iface);
110 }
111
112 static inline httprequest *impl_from_IObjectSafety(IObjectSafety *iface)
113 {
114     return CONTAINING_RECORD(iface, httprequest, IObjectSafety_iface);
115 }
116
117 static void httprequest_setreadystate(httprequest *This, READYSTATE state)
118 {
119     READYSTATE last = This->state;
120
121     This->state = state;
122
123     if (This->sink && last != state)
124     {
125         DISPPARAMS params;
126
127         memset(&params, 0, sizeof(params));
128         IDispatch_Invoke(This->sink, 0, &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &params, 0, 0, 0);
129     }
130 }
131
132 static void free_response_headers(httprequest *This)
133 {
134     struct httpheader *header, *header2;
135
136     LIST_FOR_EACH_ENTRY_SAFE(header, header2, &This->respheaders, struct httpheader, entry)
137     {
138         list_remove(&header->entry);
139         SysFreeString(header->header);
140         SysFreeString(header->value);
141         heap_free(header);
142     }
143
144     SysFreeString(This->raw_respheaders);
145     This->raw_respheaders = NULL;
146 }
147
148 struct BindStatusCallback
149 {
150     IBindStatusCallback IBindStatusCallback_iface;
151     IHttpNegotiate      IHttpNegotiate_iface;
152     IAuthenticate       IAuthenticate_iface;
153     LONG ref;
154
155     IBinding *binding;
156     httprequest *request;
157
158     /* response data */
159     IStream *stream;
160
161     /* request body data */
162     HGLOBAL body;
163 };
164
165 static inline BindStatusCallback *impl_from_IBindStatusCallback( IBindStatusCallback *iface )
166 {
167     return CONTAINING_RECORD(iface, BindStatusCallback, IBindStatusCallback_iface);
168 }
169
170 static inline BindStatusCallback *impl_from_IHttpNegotiate( IHttpNegotiate *iface )
171 {
172     return CONTAINING_RECORD(iface, BindStatusCallback, IHttpNegotiate_iface);
173 }
174
175 static inline BindStatusCallback *impl_from_IAuthenticate( IAuthenticate *iface )
176 {
177     return CONTAINING_RECORD(iface, BindStatusCallback, IAuthenticate_iface);
178 }
179
180 static void BindStatusCallback_Detach(BindStatusCallback *bsc)
181 {
182     if (bsc)
183     {
184         if (bsc->binding) IBinding_Abort(bsc->binding);
185         bsc->request = NULL;
186         IBindStatusCallback_Release(&bsc->IBindStatusCallback_iface);
187     }
188 }
189
190 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
191         REFIID riid, void **ppv)
192 {
193     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
194
195     *ppv = NULL;
196
197     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
198
199     if (IsEqualGUID(&IID_IUnknown, riid) ||
200         IsEqualGUID(&IID_IBindStatusCallback, riid))
201     {
202         *ppv = &This->IBindStatusCallback_iface;
203     }
204     else if (IsEqualGUID(&IID_IHttpNegotiate, riid))
205     {
206         *ppv = &This->IHttpNegotiate_iface;
207     }
208     else if (IsEqualGUID(&IID_IAuthenticate, riid))
209     {
210         *ppv = &This->IAuthenticate_iface;
211     }
212     else if (IsEqualGUID(&IID_IServiceProvider, riid) ||
213              IsEqualGUID(&IID_IBindStatusCallbackEx, riid) ||
214              IsEqualGUID(&IID_IInternetProtocol, riid) ||
215              IsEqualGUID(&IID_IHttpNegotiate2, riid))
216     {
217         return E_NOINTERFACE;
218     }
219
220     if (*ppv)
221     {
222         IBindStatusCallback_AddRef(iface);
223         return S_OK;
224     }
225
226     FIXME("Unsupported riid = %s\n", debugstr_guid(riid));
227
228     return E_NOINTERFACE;
229 }
230
231 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
232 {
233     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
234     LONG ref = InterlockedIncrement(&This->ref);
235
236     TRACE("(%p) ref = %d\n", This, ref);
237
238     return ref;
239 }
240
241 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
242 {
243     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
244     LONG ref = InterlockedDecrement(&This->ref);
245
246     TRACE("(%p) ref = %d\n", This, ref);
247
248     if (!ref)
249     {
250         if (This->binding) IBinding_Release(This->binding);
251         if (This->stream) IStream_Release(This->stream);
252         if (This->body) GlobalFree(This->body);
253         heap_free(This);
254     }
255
256     return ref;
257 }
258
259 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
260         DWORD reserved, IBinding *pbind)
261 {
262     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
263
264     TRACE("(%p)->(%d %p)\n", This, reserved, pbind);
265
266     if (!pbind) return E_INVALIDARG;
267
268     This->binding = pbind;
269     IBinding_AddRef(pbind);
270
271     httprequest_setreadystate(This->request, READYSTATE_LOADED);
272
273     return CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
274 }
275
276 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pPriority)
277 {
278     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
279
280     TRACE("(%p)->(%p)\n", This, pPriority);
281
282     return E_NOTIMPL;
283 }
284
285 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
286 {
287     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
288
289     TRACE("(%p)->(%d)\n", This, reserved);
290
291     return E_NOTIMPL;
292 }
293
294 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
295         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
296 {
297     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
298
299     TRACE("(%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
300             debugstr_w(szStatusText));
301
302     return S_OK;
303 }
304
305 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
306         HRESULT hr, LPCWSTR error)
307 {
308     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
309
310     TRACE("(%p)->(0x%08x %s)\n", This, hr, debugstr_w(error));
311
312     if (This->binding)
313     {
314         IBinding_Release(This->binding);
315         This->binding = NULL;
316     }
317
318     if (hr == S_OK)
319         httprequest_setreadystate(This->request, READYSTATE_COMPLETE);
320
321     return S_OK;
322 }
323
324 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
325         DWORD *bind_flags, BINDINFO *pbindinfo)
326 {
327     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
328
329     TRACE("(%p)->(%p %p)\n", This, bind_flags, pbindinfo);
330
331     *bind_flags = 0;
332     if (This->request->async) *bind_flags |= BINDF_ASYNCHRONOUS;
333
334     if (This->request->verb != BINDVERB_GET && This->body)
335     {
336         pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
337         pbindinfo->stgmedData.u.hGlobal = This->body;
338         pbindinfo->cbstgmedData = GlobalSize(This->body);
339         /* callback owns passed body pointer */
340         IBindStatusCallback_QueryInterface(iface, &IID_IUnknown, (void**)&pbindinfo->stgmedData.pUnkForRelease);
341     }
342
343     pbindinfo->dwBindVerb = This->request->verb;
344     if (This->request->verb == BINDVERB_CUSTOM)
345     {
346         pbindinfo->szCustomVerb = CoTaskMemAlloc(SysStringByteLen(This->request->custom));
347         strcpyW(pbindinfo->szCustomVerb, This->request->custom);
348     }
349
350     return S_OK;
351 }
352
353 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
354         DWORD flags, DWORD size, FORMATETC *format, STGMEDIUM *stgmed)
355 {
356     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
357     DWORD read, written;
358     BYTE buf[4096];
359     HRESULT hr;
360
361     TRACE("(%p)->(%08x %d %p %p)\n", This, flags, size, format, stgmed);
362
363     do
364     {
365         hr = IStream_Read(stgmed->u.pstm, buf, sizeof(buf), &read);
366         if (hr != S_OK) break;
367
368         hr = IStream_Write(This->stream, buf, read, &written);
369     } while((hr == S_OK) && written != 0 && read != 0);
370
371     httprequest_setreadystate(This->request, READYSTATE_INTERACTIVE);
372
373     return S_OK;
374 }
375
376 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
377         REFIID riid, IUnknown *punk)
378 {
379     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
380
381     FIXME("(%p)->(%s %p): stub\n", This, debugstr_guid(riid), punk);
382
383     return E_NOTIMPL;
384 }
385
386 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
387     BindStatusCallback_QueryInterface,
388     BindStatusCallback_AddRef,
389     BindStatusCallback_Release,
390     BindStatusCallback_OnStartBinding,
391     BindStatusCallback_GetPriority,
392     BindStatusCallback_OnLowResource,
393     BindStatusCallback_OnProgress,
394     BindStatusCallback_OnStopBinding,
395     BindStatusCallback_GetBindInfo,
396     BindStatusCallback_OnDataAvailable,
397     BindStatusCallback_OnObjectAvailable
398 };
399
400 static HRESULT WINAPI BSCHttpNegotiate_QueryInterface(IHttpNegotiate *iface,
401         REFIID riid, void **ppv)
402 {
403     BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
404     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
405 }
406
407 static ULONG WINAPI BSCHttpNegotiate_AddRef(IHttpNegotiate *iface)
408 {
409     BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
410     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
411 }
412
413 static ULONG WINAPI BSCHttpNegotiate_Release(IHttpNegotiate *iface)
414 {
415     BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
416     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
417 }
418
419 static HRESULT WINAPI BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate *iface,
420         LPCWSTR url, LPCWSTR headers, DWORD reserved, LPWSTR *add_headers)
421 {
422     static const WCHAR content_type_utf8W[] = {'C','o','n','t','e','n','t','-','T','y','p','e',':',' ',
423         't','e','x','t','/','p','l','a','i','n',';','c','h','a','r','s','e','t','=','u','t','f','-','8','\r','\n',0};
424
425     BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
426     const struct httpheader *entry;
427     WCHAR *buff, *ptr;
428     int size = 0;
429
430     TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(url), debugstr_w(headers), reserved, add_headers);
431
432     *add_headers = NULL;
433
434     if (This->request->use_utf8_content)
435         size = sizeof(content_type_utf8W);
436
437     if (!list_empty(&This->request->reqheaders))
438         size += This->request->reqheader_size*sizeof(WCHAR);
439
440     if (!size) return S_OK;
441
442     buff = CoTaskMemAlloc(size);
443     if (!buff) return E_OUTOFMEMORY;
444
445     ptr = buff;
446     if (This->request->use_utf8_content)
447     {
448         lstrcpyW(ptr, content_type_utf8W);
449         ptr += sizeof(content_type_utf8W)/sizeof(WCHAR)-1;
450     }
451
452     /* user headers */
453     LIST_FOR_EACH_ENTRY(entry, &This->request->reqheaders, struct httpheader, entry)
454     {
455         lstrcpyW(ptr, entry->header);
456         ptr += SysStringLen(entry->header);
457
458         lstrcpyW(ptr, colspaceW);
459         ptr += sizeof(colspaceW)/sizeof(WCHAR)-1;
460
461         lstrcpyW(ptr, entry->value);
462         ptr += SysStringLen(entry->value);
463
464         lstrcpyW(ptr, crlfW);
465         ptr += sizeof(crlfW)/sizeof(WCHAR)-1;
466     }
467
468     *add_headers = buff;
469
470     return S_OK;
471 }
472
473 static void add_response_header(httprequest *This, const WCHAR *data, int len)
474 {
475     struct httpheader *entry;
476     const WCHAR *ptr = data;
477     BSTR header, value;
478
479     while (*ptr)
480     {
481         if (*ptr == ':')
482         {
483             header = SysAllocStringLen(data, ptr-data);
484             /* skip leading spaces for a value */
485             while (*++ptr == ' ')
486                 ;
487             value = SysAllocStringLen(ptr, len-(ptr-data));
488             break;
489         }
490         ptr++;
491     }
492
493     if (!*ptr) return;
494
495     /* new header */
496     TRACE("got header %s:%s\n", debugstr_w(header), debugstr_w(value));
497
498     entry = heap_alloc(sizeof(*header));
499     entry->header = header;
500     entry->value  = value;
501     list_add_head(&This->respheaders, &entry->entry);
502 }
503
504 static HRESULT WINAPI BSCHttpNegotiate_OnResponse(IHttpNegotiate *iface, DWORD code,
505         LPCWSTR resp_headers, LPCWSTR req_headers, LPWSTR *add_reqheaders)
506 {
507     BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
508
509     TRACE("(%p)->(%d %s %s %p)\n", This, code, debugstr_w(resp_headers),
510           debugstr_w(req_headers), add_reqheaders);
511
512     This->request->status = code;
513     /* store headers */
514     free_response_headers(This->request);
515     if (resp_headers)
516     {
517         const WCHAR *ptr, *line;
518
519         ptr = line = resp_headers;
520
521         /* skip status line */
522         while (*ptr)
523         {
524             if (*ptr == '\r' && *(ptr+1) == '\n')
525             {
526                 line = ++ptr+1;
527                 break;
528             }
529             ptr++;
530         }
531
532         /* store as unparsed string for now */
533         This->request->raw_respheaders = SysAllocString(line);
534     }
535
536     return S_OK;
537 }
538
539 static const IHttpNegotiateVtbl BSCHttpNegotiateVtbl = {
540     BSCHttpNegotiate_QueryInterface,
541     BSCHttpNegotiate_AddRef,
542     BSCHttpNegotiate_Release,
543     BSCHttpNegotiate_BeginningTransaction,
544     BSCHttpNegotiate_OnResponse
545 };
546
547 static HRESULT WINAPI Authenticate_QueryInterface(IAuthenticate *iface,
548         REFIID riid, void **ppv)
549 {
550     BindStatusCallback *This = impl_from_IAuthenticate(iface);
551     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
552 }
553
554 static ULONG WINAPI Authenticate_AddRef(IAuthenticate *iface)
555 {
556     BindStatusCallback *This = impl_from_IAuthenticate(iface);
557     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
558 }
559
560 static ULONG WINAPI Authenticate_Release(IAuthenticate *iface)
561 {
562     BindStatusCallback *This = impl_from_IAuthenticate(iface);
563     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
564 }
565
566 static HRESULT WINAPI Authenticate_Authenticate(IAuthenticate *iface,
567     HWND *hwnd, LPWSTR *username, LPWSTR *password)
568 {
569     BindStatusCallback *This = impl_from_IAuthenticate(iface);
570     FIXME("(%p)->(%p %p %p)\n", This, hwnd, username, password);
571     return E_NOTIMPL;
572 }
573
574 static const IAuthenticateVtbl AuthenticateVtbl = {
575     Authenticate_QueryInterface,
576     Authenticate_AddRef,
577     Authenticate_Release,
578     Authenticate_Authenticate
579 };
580
581 static HRESULT BindStatusCallback_create(httprequest* This, BindStatusCallback **obj, const VARIANT *body)
582 {
583     BindStatusCallback *bsc;
584     IBindCtx *pbc;
585     HRESULT hr;
586     int size;
587
588     hr = CreateBindCtx(0, &pbc);
589     if (hr != S_OK) return hr;
590
591     bsc = heap_alloc(sizeof(*bsc));
592     if (!bsc)
593     {
594         IBindCtx_Release(pbc);
595         return E_OUTOFMEMORY;
596     }
597
598     bsc->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl;
599     bsc->IHttpNegotiate_iface.lpVtbl = &BSCHttpNegotiateVtbl;
600     bsc->IAuthenticate_iface.lpVtbl = &AuthenticateVtbl;
601     bsc->ref = 1;
602     bsc->request = This;
603     bsc->binding = NULL;
604     bsc->stream = NULL;
605     bsc->body = NULL;
606
607     TRACE("(%p)->(%p)\n", This, bsc);
608
609     This->use_utf8_content = FALSE;
610
611     if (This->verb != BINDVERB_GET)
612     {
613         void *send_data, *ptr;
614         SAFEARRAY *sa = NULL;
615
616         if (V_VT(body) == (VT_VARIANT|VT_BYREF))
617             body = V_VARIANTREF(body);
618
619         switch (V_VT(body))
620         {
621         case VT_BSTR:
622         {
623             int len = SysStringLen(V_BSTR(body));
624             const WCHAR *str = V_BSTR(body);
625             UINT i, cp = CP_ACP;
626
627             for (i = 0; i < len; i++)
628             {
629                 if (str[i] > 127)
630                 {
631                     cp = CP_UTF8;
632                     break;
633                 }
634             }
635
636             size = WideCharToMultiByte(cp, 0, str, len, NULL, 0, NULL, NULL);
637             if (!(ptr = heap_alloc(size)))
638             {
639                 heap_free(bsc);
640                 return E_OUTOFMEMORY;
641             }
642             WideCharToMultiByte(cp, 0, str, len, ptr, size, NULL, NULL);
643             if (cp == CP_UTF8) This->use_utf8_content = TRUE;
644             break;
645         }
646         case VT_ARRAY|VT_UI1:
647         {
648             sa = V_ARRAY(body);
649             if ((hr = SafeArrayAccessData(sa, (void **)&ptr)) != S_OK) return hr;
650             if ((hr = SafeArrayGetUBound(sa, 1, &size) != S_OK))
651             {
652                 SafeArrayUnaccessData(sa);
653                 return hr;
654             }
655             size++;
656             break;
657         }
658         case VT_EMPTY:
659             ptr = NULL;
660             size = 0;
661             break;
662         default:
663             FIXME("unsupported body data type %d\n", V_VT(body));
664             break;
665         }
666
667         bsc->body = GlobalAlloc(GMEM_FIXED, size);
668         if (!bsc->body)
669         {
670             if (V_VT(body) == VT_BSTR)
671                 heap_free(ptr);
672             else if (V_VT(body) == (VT_ARRAY|VT_UI1))
673                 SafeArrayUnaccessData(sa);
674
675             heap_free(bsc);
676             return E_OUTOFMEMORY;
677         }
678
679         send_data = GlobalLock(bsc->body);
680         memcpy(send_data, ptr, size);
681         GlobalUnlock(bsc->body);
682
683         if (V_VT(body) == VT_BSTR)
684             heap_free(ptr);
685         else if (V_VT(body) == (VT_ARRAY|VT_UI1))
686             SafeArrayUnaccessData(sa);
687     }
688
689     hr = RegisterBindStatusCallback(pbc, &bsc->IBindStatusCallback_iface, NULL, 0);
690     if (hr == S_OK)
691     {
692         IMoniker *moniker;
693
694         hr = CreateURLMoniker(NULL, This->url, &moniker);
695         if (hr == S_OK)
696         {
697             IStream *stream;
698
699             hr = IMoniker_BindToStorage(moniker, pbc, NULL, &IID_IStream, (void**)&stream);
700             IMoniker_Release(moniker);
701             if (stream) IStream_Release(stream);
702         }
703         IBindCtx_Release(pbc);
704     }
705
706     if (FAILED(hr))
707     {
708         IBindStatusCallback_Release(&bsc->IBindStatusCallback_iface);
709         bsc = NULL;
710     }
711
712     *obj = bsc;
713     return hr;
714 }
715
716 static HRESULT WINAPI httprequest_QueryInterface(IXMLHTTPRequest *iface, REFIID riid, void **ppvObject)
717 {
718     httprequest *This = impl_from_IXMLHTTPRequest( iface );
719     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
720
721     if ( IsEqualGUID( riid, &IID_IXMLHTTPRequest) ||
722          IsEqualGUID( riid, &IID_IDispatch) ||
723          IsEqualGUID( riid, &IID_IUnknown) )
724     {
725         *ppvObject = iface;
726     }
727     else if (IsEqualGUID(&IID_IObjectWithSite, riid))
728     {
729         *ppvObject = &This->IObjectWithSite_iface;
730     }
731     else if (IsEqualGUID(&IID_IObjectSafety, riid))
732     {
733         *ppvObject = &This->IObjectSafety_iface;
734     }
735     else
736     {
737         TRACE("Unsupported interface %s\n", debugstr_guid(riid));
738         *ppvObject = NULL;
739         return E_NOINTERFACE;
740     }
741
742     IXMLHTTPRequest_AddRef( iface );
743
744     return S_OK;
745 }
746
747 static ULONG WINAPI httprequest_AddRef(IXMLHTTPRequest *iface)
748 {
749     httprequest *This = impl_from_IXMLHTTPRequest( iface );
750     ULONG ref = InterlockedIncrement( &This->ref );
751     TRACE("(%p)->(%u)\n", This, ref );
752     return ref;
753 }
754
755 static ULONG WINAPI httprequest_Release(IXMLHTTPRequest *iface)
756 {
757     httprequest *This = impl_from_IXMLHTTPRequest( iface );
758     ULONG ref = InterlockedDecrement( &This->ref );
759
760     TRACE("(%p)->(%u)\n", This, ref );
761
762     if ( ref == 0 )
763     {
764         struct httpheader *header, *header2;
765
766         if (This->site)
767             IUnknown_Release( This->site );
768
769         SysFreeString(This->custom);
770         SysFreeString(This->url);
771         SysFreeString(This->user);
772         SysFreeString(This->password);
773
774         /* request headers */
775         LIST_FOR_EACH_ENTRY_SAFE(header, header2, &This->reqheaders, struct httpheader, entry)
776         {
777             list_remove(&header->entry);
778             SysFreeString(header->header);
779             SysFreeString(header->value);
780             heap_free(header);
781         }
782         /* response headers */
783         free_response_headers(This);
784
785         /* detach callback object */
786         BindStatusCallback_Detach(This->bsc);
787
788         if (This->sink) IDispatch_Release(This->sink);
789
790         heap_free( This );
791     }
792
793     return ref;
794 }
795
796 static HRESULT WINAPI httprequest_GetTypeInfoCount(IXMLHTTPRequest *iface, UINT *pctinfo)
797 {
798     httprequest *This = impl_from_IXMLHTTPRequest( iface );
799
800     TRACE("(%p)->(%p)\n", This, pctinfo);
801
802     *pctinfo = 1;
803
804     return S_OK;
805 }
806
807 static HRESULT WINAPI httprequest_GetTypeInfo(IXMLHTTPRequest *iface, UINT iTInfo,
808         LCID lcid, ITypeInfo **ppTInfo)
809 {
810     httprequest *This = impl_from_IXMLHTTPRequest( iface );
811
812     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
813
814     return get_typeinfo(IXMLHTTPRequest_tid, ppTInfo);
815 }
816
817 static HRESULT WINAPI httprequest_GetIDsOfNames(IXMLHTTPRequest *iface, REFIID riid,
818         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
819 {
820     httprequest *This = impl_from_IXMLHTTPRequest( iface );
821     ITypeInfo *typeinfo;
822     HRESULT hr;
823
824     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
825           lcid, rgDispId);
826
827     if(!rgszNames || cNames == 0 || !rgDispId)
828         return E_INVALIDARG;
829
830     hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
831     if(SUCCEEDED(hr))
832     {
833         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
834         ITypeInfo_Release(typeinfo);
835     }
836
837     return hr;
838 }
839
840 static HRESULT WINAPI httprequest_Invoke(IXMLHTTPRequest *iface, DISPID dispIdMember, REFIID riid,
841         LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
842         EXCEPINFO *pExcepInfo, UINT *puArgErr)
843 {
844     httprequest *This = impl_from_IXMLHTTPRequest( iface );
845     ITypeInfo *typeinfo;
846     HRESULT hr;
847
848     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
849           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
850
851     hr = get_typeinfo(IXMLHTTPRequest_tid, &typeinfo);
852     if(SUCCEEDED(hr))
853     {
854         hr = ITypeInfo_Invoke(typeinfo, &This->IXMLHTTPRequest_iface, dispIdMember, wFlags,
855                 pDispParams, pVarResult, pExcepInfo, puArgErr);
856         ITypeInfo_Release(typeinfo);
857     }
858
859     return hr;
860 }
861
862 static HRESULT WINAPI httprequest_open(IXMLHTTPRequest *iface, BSTR method, BSTR url,
863         VARIANT async, VARIANT user, VARIANT password)
864 {
865     static const WCHAR MethodGetW[] = {'G','E','T',0};
866     static const WCHAR MethodPutW[] = {'P','U','T',0};
867     static const WCHAR MethodPostW[] = {'P','O','S','T',0};
868     static const WCHAR MethodDeleteW[] = {'D','E','L','E','T','E',0};
869
870     httprequest *This = impl_from_IXMLHTTPRequest( iface );
871     VARIANT str, is_async;
872     HRESULT hr;
873
874     TRACE("(%p)->(%s %s %s)\n", This, debugstr_w(method), debugstr_w(url),
875         debugstr_variant(&async));
876
877     if (!method || !url) return E_INVALIDARG;
878
879     /* free previously set data */
880     SysFreeString(This->url);
881     SysFreeString(This->user);
882     SysFreeString(This->password);
883     This->url = This->user = This->password = NULL;
884
885     if (!strcmpiW(method, MethodGetW))
886     {
887         This->verb = BINDVERB_GET;
888     }
889     else if (!strcmpiW(method, MethodPutW))
890     {
891         This->verb = BINDVERB_PUT;
892     }
893     else if (!strcmpiW(method, MethodPostW))
894     {
895         This->verb = BINDVERB_POST;
896     }
897     else if (!strcmpiW(method, MethodDeleteW))
898     {
899         This->verb = BINDVERB_CUSTOM;
900         SysReAllocString(&This->custom, method);
901     }
902     else
903     {
904         FIXME("unsupported request type %s\n", debugstr_w(method));
905         This->verb = -1;
906         return E_FAIL;
907     }
908
909     This->url = SysAllocString(url);
910
911     VariantInit(&is_async);
912     hr = VariantChangeType(&is_async, &async, 0, VT_BOOL);
913     This->async = hr == S_OK && V_BOOL(&is_async) == VARIANT_TRUE;
914
915     VariantInit(&str);
916     hr = VariantChangeType(&str, &user, 0, VT_BSTR);
917     if (hr == S_OK)
918         This->user = V_BSTR(&str);
919
920     VariantInit(&str);
921     hr = VariantChangeType(&str, &password, 0, VT_BSTR);
922     if (hr == S_OK)
923         This->password = V_BSTR(&str);
924
925     httprequest_setreadystate(This, READYSTATE_LOADING);
926
927     return S_OK;
928 }
929
930 static HRESULT WINAPI httprequest_setRequestHeader(IXMLHTTPRequest *iface, BSTR header, BSTR value)
931 {
932     httprequest *This = impl_from_IXMLHTTPRequest( iface );
933     struct httpheader *entry;
934
935     TRACE("(%p)->(%s %s)\n", This, debugstr_w(header), debugstr_w(value));
936
937     if (!header || !*header) return E_INVALIDARG;
938     if (This->state != READYSTATE_LOADING) return E_FAIL;
939     if (!value) return E_INVALIDARG;
940
941     /* replace existing header value if already added */
942     LIST_FOR_EACH_ENTRY(entry, &This->reqheaders, struct httpheader, entry)
943     {
944         if (lstrcmpW(entry->header, header) == 0)
945         {
946             LONG length = SysStringLen(entry->value);
947             HRESULT hr;
948
949             hr = SysReAllocString(&entry->value, value) ? S_OK : E_OUTOFMEMORY;
950
951             if (hr == S_OK)
952                 This->reqheader_size += (SysStringLen(entry->value) - length);
953
954             return hr;
955         }
956     }
957
958     entry = heap_alloc(sizeof(*entry));
959     if (!entry) return E_OUTOFMEMORY;
960
961     /* new header */
962     entry->header = SysAllocString(header);
963     entry->value  = SysAllocString(value);
964
965     /* header length including null terminator */
966     This->reqheader_size += SysStringLen(entry->header) + sizeof(colspaceW)/sizeof(WCHAR) +
967                             SysStringLen(entry->value)  + sizeof(crlfW)/sizeof(WCHAR) - 1;
968
969     list_add_head(&This->reqheaders, &entry->entry);
970
971     return S_OK;
972 }
973
974 static HRESULT WINAPI httprequest_getResponseHeader(IXMLHTTPRequest *iface, BSTR header, BSTR *value)
975 {
976     httprequest *This = impl_from_IXMLHTTPRequest( iface );
977     struct httpheader *entry;
978
979     TRACE("(%p)->(%s %p)\n", This, debugstr_w(header), value);
980
981     if (!header || !value) return E_INVALIDARG;
982
983     if (This->raw_respheaders && list_empty(&This->respheaders))
984     {
985         WCHAR *ptr, *line;
986
987         ptr = line = This->raw_respheaders;
988         while (*ptr)
989         {
990             if (*ptr == '\r' && *(ptr+1) == '\n')
991             {
992                 add_response_header(This, line, ptr-line);
993                 ptr++; line = ++ptr;
994                 continue;
995             }
996             ptr++;
997         }
998     }
999
1000     LIST_FOR_EACH_ENTRY(entry, &This->respheaders, struct httpheader, entry)
1001     {
1002         if (!strcmpiW(entry->header, header))
1003         {
1004             *value = SysAllocString(entry->value);
1005             TRACE("header value %s\n", debugstr_w(*value));
1006             return S_OK;
1007         }
1008     }
1009
1010     return S_FALSE;
1011 }
1012
1013 static HRESULT WINAPI httprequest_getAllResponseHeaders(IXMLHTTPRequest *iface, BSTR *respheaders)
1014 {
1015     httprequest *This = impl_from_IXMLHTTPRequest( iface );
1016
1017     TRACE("(%p)->(%p)\n", This, respheaders);
1018
1019     if (!respheaders) return E_INVALIDARG;
1020
1021     *respheaders = SysAllocString(This->raw_respheaders);
1022
1023     return S_OK;
1024 }
1025
1026 static HRESULT WINAPI httprequest_send(IXMLHTTPRequest *iface, VARIANT body)
1027 {
1028     httprequest *This = impl_from_IXMLHTTPRequest( iface );
1029     BindStatusCallback *bsc = NULL;
1030     HRESULT hr;
1031
1032     TRACE("(%p)->(%s)\n", This, debugstr_variant(&body));
1033
1034     if (This->state != READYSTATE_LOADING) return E_FAIL;
1035
1036     hr = BindStatusCallback_create(This, &bsc, &body);
1037     if (FAILED(hr)) return hr;
1038
1039     BindStatusCallback_Detach(This->bsc);
1040     This->bsc = bsc;
1041
1042     return hr;
1043 }
1044
1045 static HRESULT WINAPI httprequest_abort(IXMLHTTPRequest *iface)
1046 {
1047     httprequest *This = impl_from_IXMLHTTPRequest( iface );
1048
1049     TRACE("(%p)\n", This);
1050
1051     BindStatusCallback_Detach(This->bsc);
1052     This->bsc = NULL;
1053
1054     httprequest_setreadystate(This, READYSTATE_UNINITIALIZED);
1055
1056     return S_OK;
1057 }
1058
1059 static HRESULT WINAPI httprequest_get_status(IXMLHTTPRequest *iface, LONG *status)
1060 {
1061     httprequest *This = impl_from_IXMLHTTPRequest( iface );
1062
1063     TRACE("(%p)->(%p)\n", This, status);
1064
1065     if (!status) return E_INVALIDARG;
1066     if (This->state != READYSTATE_COMPLETE) return E_FAIL;
1067
1068     *status = This->status;
1069
1070     return S_OK;
1071 }
1072
1073 static HRESULT WINAPI httprequest_get_statusText(IXMLHTTPRequest *iface, BSTR *pbstrStatus)
1074 {
1075     httprequest *This = impl_from_IXMLHTTPRequest( iface );
1076
1077     FIXME("stub %p %p\n", This, pbstrStatus);
1078
1079     return E_NOTIMPL;
1080 }
1081
1082 static HRESULT WINAPI httprequest_get_responseXML(IXMLHTTPRequest *iface, IDispatch **body)
1083 {
1084     httprequest *This = impl_from_IXMLHTTPRequest( iface );
1085     IXMLDOMDocument3 *doc;
1086     HRESULT hr;
1087     BSTR str;
1088
1089     TRACE("(%p)->(%p)\n", This, body);
1090
1091     if (!body) return E_INVALIDARG;
1092     if (This->state != READYSTATE_COMPLETE) return E_FAIL;
1093
1094     hr = DOMDocument_create(MSXML_DEFAULT, NULL, (void**)&doc);
1095     if (hr != S_OK) return hr;
1096
1097     hr = IXMLHTTPRequest_get_responseText(iface, &str);
1098     if (hr == S_OK)
1099     {
1100         VARIANT_BOOL ok;
1101
1102         hr = IXMLDOMDocument3_loadXML(doc, str, &ok);
1103         SysFreeString(str);
1104     }
1105
1106     IXMLDOMDocument3_QueryInterface(doc, &IID_IDispatch, (void**)body);
1107     IXMLDOMDocument3_Release(doc);
1108
1109     return hr;
1110 }
1111
1112 static HRESULT WINAPI httprequest_get_responseText(IXMLHTTPRequest *iface, BSTR *body)
1113 {
1114     httprequest *This = impl_from_IXMLHTTPRequest( iface );
1115     HGLOBAL hglobal;
1116     HRESULT hr;
1117
1118     TRACE("(%p)->(%p)\n", This, body);
1119
1120     if (!body) return E_INVALIDARG;
1121     if (This->state != READYSTATE_COMPLETE) return E_FAIL;
1122
1123     hr = GetHGlobalFromStream(This->bsc->stream, &hglobal);
1124     if (hr == S_OK)
1125     {
1126         xmlChar *ptr = GlobalLock(hglobal);
1127         DWORD size = GlobalSize(hglobal);
1128         xmlCharEncoding encoding = XML_CHAR_ENCODING_UTF8;
1129
1130         /* try to determine data encoding */
1131         if (size >= 4)
1132         {
1133             encoding = xmlDetectCharEncoding(ptr, 4);
1134             TRACE("detected encoding: %s\n", debugstr_a(xmlGetCharEncodingName(encoding)));
1135             if ( encoding != XML_CHAR_ENCODING_UTF8 &&
1136                  encoding != XML_CHAR_ENCODING_UTF16LE &&
1137                  encoding != XML_CHAR_ENCODING_NONE )
1138             {
1139                 FIXME("unsupported encoding: %s\n", debugstr_a(xmlGetCharEncodingName(encoding)));
1140                 GlobalUnlock(hglobal);
1141                 return E_FAIL;
1142             }
1143         }
1144
1145         /* without BOM assume UTF-8 */
1146         if (encoding == XML_CHAR_ENCODING_UTF8 ||
1147             encoding == XML_CHAR_ENCODING_NONE )
1148         {
1149             DWORD length = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)ptr, size, NULL, 0);
1150
1151             *body = SysAllocStringLen(NULL, length);
1152             if (*body)
1153                 MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)ptr, size, *body, length);
1154         }
1155         else
1156             *body = SysAllocStringByteLen((LPCSTR)ptr, size);
1157
1158         if (!*body) hr = E_OUTOFMEMORY;
1159         GlobalUnlock(hglobal);
1160     }
1161
1162     return hr;
1163 }
1164
1165 static HRESULT WINAPI httprequest_get_responseBody(IXMLHTTPRequest *iface, VARIANT *body)
1166 {
1167     httprequest *This = impl_from_IXMLHTTPRequest( iface );
1168     HGLOBAL hglobal;
1169     HRESULT hr;
1170
1171     TRACE("(%p)->(%p)\n", This, body);
1172
1173     if (!body) return E_INVALIDARG;
1174     V_VT(body) = VT_EMPTY;
1175
1176     if (This->state != READYSTATE_COMPLETE) return E_PENDING;
1177
1178     hr = GetHGlobalFromStream(This->bsc->stream, &hglobal);
1179     if (hr == S_OK)
1180     {
1181         void *ptr = GlobalLock(hglobal);
1182         DWORD size = GlobalSize(hglobal);
1183
1184         SAFEARRAYBOUND bound;
1185         SAFEARRAY *array;
1186
1187         bound.lLbound = 0;
1188         bound.cElements = size;
1189         array = SafeArrayCreate(VT_UI1, 1, &bound);
1190
1191         if (array)
1192         {
1193             void *dest;
1194
1195             V_VT(body) = VT_ARRAY | VT_UI1;
1196             V_ARRAY(body) = array;
1197
1198             hr = SafeArrayAccessData(array, &dest);
1199             if (hr == S_OK)
1200             {
1201                 memcpy(dest, ptr, size);
1202                 SafeArrayUnaccessData(array);
1203             }
1204             else
1205             {
1206                 VariantClear(body);
1207             }
1208         }
1209         else
1210             hr = E_FAIL;
1211
1212         GlobalUnlock(hglobal);
1213     }
1214
1215     return hr;
1216 }
1217
1218 static HRESULT WINAPI httprequest_get_responseStream(IXMLHTTPRequest *iface, VARIANT *body)
1219 {
1220     httprequest *This = impl_from_IXMLHTTPRequest( iface );
1221     LARGE_INTEGER move;
1222     IStream *stream;
1223     HRESULT hr;
1224
1225     TRACE("(%p)->(%p)\n", This, body);
1226
1227     if (!body) return E_INVALIDARG;
1228     V_VT(body) = VT_EMPTY;
1229
1230     if (This->state != READYSTATE_COMPLETE) return E_PENDING;
1231
1232     hr = IStream_Clone(This->bsc->stream, &stream);
1233
1234     move.QuadPart = 0;
1235     IStream_Seek(stream, move, STREAM_SEEK_SET, NULL);
1236
1237     V_VT(body) = VT_UNKNOWN;
1238     V_UNKNOWN(body) = (IUnknown*)stream;
1239
1240     return hr;
1241 }
1242
1243 static HRESULT WINAPI httprequest_get_readyState(IXMLHTTPRequest *iface, LONG *state)
1244 {
1245     httprequest *This = impl_from_IXMLHTTPRequest( iface );
1246
1247     TRACE("(%p)->(%p)\n", This, state);
1248
1249     if (!state) return E_INVALIDARG;
1250
1251     *state = This->state;
1252     return S_OK;
1253 }
1254
1255 static HRESULT WINAPI httprequest_put_onreadystatechange(IXMLHTTPRequest *iface, IDispatch *sink)
1256 {
1257     httprequest *This = impl_from_IXMLHTTPRequest( iface );
1258
1259     TRACE("(%p)->(%p)\n", This, sink);
1260
1261     if (This->sink) IDispatch_Release(This->sink);
1262     if ((This->sink = sink)) IDispatch_AddRef(This->sink);
1263
1264     return S_OK;
1265 }
1266
1267 static const struct IXMLHTTPRequestVtbl XMLHTTPRequestVtbl =
1268 {
1269     httprequest_QueryInterface,
1270     httprequest_AddRef,
1271     httprequest_Release,
1272     httprequest_GetTypeInfoCount,
1273     httprequest_GetTypeInfo,
1274     httprequest_GetIDsOfNames,
1275     httprequest_Invoke,
1276     httprequest_open,
1277     httprequest_setRequestHeader,
1278     httprequest_getResponseHeader,
1279     httprequest_getAllResponseHeaders,
1280     httprequest_send,
1281     httprequest_abort,
1282     httprequest_get_status,
1283     httprequest_get_statusText,
1284     httprequest_get_responseXML,
1285     httprequest_get_responseText,
1286     httprequest_get_responseBody,
1287     httprequest_get_responseStream,
1288     httprequest_get_readyState,
1289     httprequest_put_onreadystatechange
1290 };
1291
1292 /* IObjectWithSite */
1293 static HRESULT WINAPI
1294 httprequest_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
1295 {
1296     httprequest *This = impl_from_IObjectWithSite(iface);
1297     return IXMLHTTPRequest_QueryInterface( (IXMLHTTPRequest *)This, riid, ppvObject );
1298 }
1299
1300 static ULONG WINAPI httprequest_ObjectWithSite_AddRef( IObjectWithSite* iface )
1301 {
1302     httprequest *This = impl_from_IObjectWithSite(iface);
1303     return IXMLHTTPRequest_AddRef((IXMLHTTPRequest *)This);
1304 }
1305
1306 static ULONG WINAPI httprequest_ObjectWithSite_Release( IObjectWithSite* iface )
1307 {
1308     httprequest *This = impl_from_IObjectWithSite(iface);
1309     return IXMLHTTPRequest_Release((IXMLHTTPRequest *)This);
1310 }
1311
1312 static HRESULT WINAPI httprequest_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
1313 {
1314     httprequest *This = impl_from_IObjectWithSite(iface);
1315
1316     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
1317
1318     if ( !This->site )
1319         return E_FAIL;
1320
1321     return IUnknown_QueryInterface( This->site, iid, ppvSite );
1322 }
1323
1324 static HRESULT WINAPI httprequest_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
1325 {
1326     httprequest *This = impl_from_IObjectWithSite(iface);
1327
1328     TRACE("(%p)->(%p)\n", iface, punk);
1329
1330     if (punk)
1331         IUnknown_AddRef( punk );
1332
1333     if(This->site)
1334         IUnknown_Release( This->site );
1335
1336     This->site = punk;
1337
1338     return S_OK;
1339 }
1340
1341 static const IObjectWithSiteVtbl ObjectWithSiteVtbl =
1342 {
1343     httprequest_ObjectWithSite_QueryInterface,
1344     httprequest_ObjectWithSite_AddRef,
1345     httprequest_ObjectWithSite_Release,
1346     httprequest_ObjectWithSite_SetSite,
1347     httprequest_ObjectWithSite_GetSite
1348 };
1349
1350 /* IObjectSafety */
1351 static HRESULT WINAPI httprequest_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
1352 {
1353     httprequest *This = impl_from_IObjectSafety(iface);
1354     return IXMLHTTPRequest_QueryInterface( (IXMLHTTPRequest *)This, riid, ppv );
1355 }
1356
1357 static ULONG WINAPI httprequest_Safety_AddRef(IObjectSafety *iface)
1358 {
1359     httprequest *This = impl_from_IObjectSafety(iface);
1360     return IXMLHTTPRequest_AddRef((IXMLHTTPRequest *)This);
1361 }
1362
1363 static ULONG WINAPI httprequest_Safety_Release(IObjectSafety *iface)
1364 {
1365     httprequest *This = impl_from_IObjectSafety(iface);
1366     return IXMLHTTPRequest_Release((IXMLHTTPRequest *)This);
1367 }
1368
1369 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
1370
1371 static HRESULT WINAPI httprequest_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
1372         DWORD *supported, DWORD *enabled)
1373 {
1374     httprequest *This = impl_from_IObjectSafety(iface);
1375
1376     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
1377
1378     if(!supported || !enabled) return E_POINTER;
1379
1380     *supported = SAFETY_SUPPORTED_OPTIONS;
1381     *enabled = This->safeopt;
1382
1383     return S_OK;
1384 }
1385
1386 static HRESULT WINAPI httprequest_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
1387         DWORD mask, DWORD enabled)
1388 {
1389     httprequest *This = impl_from_IObjectSafety(iface);
1390     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
1391
1392     if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
1393         return E_FAIL;
1394
1395     This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
1396
1397     return S_OK;
1398 }
1399
1400 #undef SAFETY_SUPPORTED_OPTIONS
1401
1402 static const IObjectSafetyVtbl ObjectSafetyVtbl = {
1403     httprequest_Safety_QueryInterface,
1404     httprequest_Safety_AddRef,
1405     httprequest_Safety_Release,
1406     httprequest_Safety_GetInterfaceSafetyOptions,
1407     httprequest_Safety_SetInterfaceSafetyOptions
1408 };
1409
1410 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
1411 {
1412     httprequest *req;
1413     HRESULT hr = S_OK;
1414
1415     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
1416
1417     req = heap_alloc( sizeof (*req) );
1418     if( !req )
1419         return E_OUTOFMEMORY;
1420
1421     req->IXMLHTTPRequest_iface.lpVtbl = &XMLHTTPRequestVtbl;
1422     req->IObjectWithSite_iface.lpVtbl = &ObjectWithSiteVtbl;
1423     req->IObjectSafety_iface.lpVtbl = &ObjectSafetyVtbl;
1424     req->ref = 1;
1425
1426     req->async = FALSE;
1427     req->verb = -1;
1428     req->custom = NULL;
1429     req->url = req->user = req->password = NULL;
1430
1431     req->state = READYSTATE_UNINITIALIZED;
1432     req->sink = NULL;
1433
1434     req->bsc = NULL;
1435     req->status = 0;
1436     req->reqheader_size = 0;
1437     req->raw_respheaders = NULL;
1438     req->use_utf8_content = FALSE;
1439
1440     list_init(&req->reqheaders);
1441     list_init(&req->respheaders);
1442
1443     req->site = NULL;
1444     req->safeopt = 0;
1445
1446     *ppObj = &req->IXMLHTTPRequest_iface;
1447
1448     TRACE("returning iface %p\n", *ppObj);
1449
1450     return hr;
1451 }
1452
1453 #else
1454
1455 HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
1456 {
1457     MESSAGE("This program tried to use a XMLHTTPRequest object, but\n"
1458             "libxml2 support was not present at compile time.\n");
1459     return E_NOTIMPL;
1460 }
1461
1462 #endif