jscript: Use prototype for builtin Date properties.
[wine] / dlls / mshtml / navigate.c
1 /*
2  * Copyright 2006-2010 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "winreg.h"
31 #include "ole2.h"
32 #include "hlguids.h"
33 #include "shlguid.h"
34 #include "wininet.h"
35 #include "shlwapi.h"
36 #include "htiface.h"
37 #include "shdeprecated.h"
38
39 #include "wine/debug.h"
40
41 #include "mshtml_private.h"
42 #include "binding.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
45
46 #define CONTENT_LENGTH "Content-Length"
47 #define UTF8_STR "utf-8"
48 #define UTF16_STR "utf-16"
49
50 static const WCHAR emptyW[] = {0};
51
52 struct nsProtocolStream {
53     nsIInputStream nsIInputStream_iface;
54
55     LONG ref;
56
57     char buf[1024];
58     DWORD buf_size;
59 };
60
61 struct BSCallbackVtbl {
62     void (*destroy)(BSCallback*);
63     HRESULT (*init_bindinfo)(BSCallback*);
64     HRESULT (*start_binding)(BSCallback*);
65     HRESULT (*stop_binding)(BSCallback*,HRESULT);
66     HRESULT (*read_data)(BSCallback*,IStream*);
67     HRESULT (*on_progress)(BSCallback*,ULONG,LPCWSTR);
68     HRESULT (*on_response)(BSCallback*,DWORD,LPCWSTR);
69     HRESULT (*beginning_transaction)(BSCallback*,WCHAR**);
70 };
71
72 static inline nsProtocolStream *impl_from_nsIInputStream(nsIInputStream *iface)
73 {
74     return CONTAINING_RECORD(iface, nsProtocolStream, nsIInputStream_iface);
75 }
76
77 static nsresult NSAPI nsInputStream_QueryInterface(nsIInputStream *iface, nsIIDRef riid,
78         void **result)
79 {
80     nsProtocolStream *This = impl_from_nsIInputStream(iface);
81
82     *result = NULL;
83
84     if(IsEqualGUID(&IID_nsISupports, riid)) {
85         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
86         *result  = &This->nsIInputStream_iface;
87     }else if(IsEqualGUID(&IID_nsIInputStream, riid)) {
88         TRACE("(%p)->(IID_nsIInputStream %p)\n", This, result);
89         *result  = &This->nsIInputStream_iface;
90     }
91
92     if(*result) {
93         nsIInputStream_AddRef(&This->nsIInputStream_iface);
94         return NS_OK;
95     }
96
97     WARN("unsupported interface %s\n", debugstr_guid(riid));
98     return NS_NOINTERFACE;
99 }
100
101 static nsrefcnt NSAPI nsInputStream_AddRef(nsIInputStream *iface)
102 {
103     nsProtocolStream *This = impl_from_nsIInputStream(iface);
104     LONG ref = InterlockedIncrement(&This->ref);
105
106     TRACE("(%p) ref=%d\n", This, ref);
107
108     return ref;
109 }
110
111
112 static nsrefcnt NSAPI nsInputStream_Release(nsIInputStream *iface)
113 {
114     nsProtocolStream *This = impl_from_nsIInputStream(iface);
115     LONG ref = InterlockedDecrement(&This->ref);
116
117     TRACE("(%p) ref=%d\n", This, ref);
118
119     if(!ref)
120         heap_free(This);
121
122     return ref;
123 }
124
125 static nsresult NSAPI nsInputStream_Close(nsIInputStream *iface)
126 {
127     nsProtocolStream *This = impl_from_nsIInputStream(iface);
128     FIXME("(%p)\n", This);
129     return NS_ERROR_NOT_IMPLEMENTED;
130 }
131
132 static nsresult NSAPI nsInputStream_Available(nsIInputStream *iface, PRUint32 *_retval)
133 {
134     nsProtocolStream *This = impl_from_nsIInputStream(iface);
135     FIXME("(%p)->(%p)\n", This, _retval);
136     return NS_ERROR_NOT_IMPLEMENTED;
137 }
138
139 static nsresult NSAPI nsInputStream_Read(nsIInputStream *iface, char *aBuf, PRUint32 aCount,
140                                          PRUint32 *_retval)
141 {
142     nsProtocolStream *This = impl_from_nsIInputStream(iface);
143     DWORD read = aCount;
144
145     TRACE("(%p)->(%p %d %p)\n", This, aBuf, aCount, _retval);
146
147     if(read > This->buf_size)
148         read = This->buf_size;
149
150     if(read) {
151         memcpy(aBuf, This->buf, read);
152         if(read < This->buf_size)
153             memmove(This->buf, This->buf+read, This->buf_size-read);
154         This->buf_size -= read;
155     }
156
157     *_retval = read;
158     return NS_OK;
159 }
160
161 static nsresult NSAPI nsInputStream_ReadSegments(nsIInputStream *iface,
162         nsresult (WINAPI *aWriter)(nsIInputStream*,void*,const char*,PRUint32,PRUint32,PRUint32*),
163         void *aClousure, PRUint32 aCount, PRUint32 *_retval)
164 {
165     nsProtocolStream *This = impl_from_nsIInputStream(iface);
166     PRUint32 written = 0;
167     nsresult nsres;
168
169     TRACE("(%p)->(%p %p %d %p)\n", This, aWriter, aClousure, aCount, _retval);
170
171     if(!This->buf_size)
172         return S_OK;
173
174     if(aCount > This->buf_size)
175         aCount = This->buf_size;
176
177     nsres = aWriter(&This->nsIInputStream_iface, aClousure, This->buf, 0, aCount, &written);
178     if(NS_FAILED(nsres))
179         TRACE("aWritter failed: %08x\n", nsres);
180     else if(written != This->buf_size)
181         FIXME("written %d != buf_size %d\n", written, This->buf_size);
182
183     This->buf_size -= written; 
184
185     *_retval = written;
186     return nsres;
187 }
188
189 static nsresult NSAPI nsInputStream_IsNonBlocking(nsIInputStream *iface, cpp_bool *_retval)
190 {
191     nsProtocolStream *This = impl_from_nsIInputStream(iface);
192     FIXME("(%p)->(%p)\n", This, _retval);
193     return NS_ERROR_NOT_IMPLEMENTED;
194 }
195
196 static const nsIInputStreamVtbl nsInputStreamVtbl = {
197     nsInputStream_QueryInterface,
198     nsInputStream_AddRef,
199     nsInputStream_Release,
200     nsInputStream_Close,
201     nsInputStream_Available,
202     nsInputStream_Read,
203     nsInputStream_ReadSegments,
204     nsInputStream_IsNonBlocking
205 };
206
207 static nsProtocolStream *create_nsprotocol_stream(void)
208 {
209     nsProtocolStream *ret = heap_alloc(sizeof(nsProtocolStream));
210
211     ret->nsIInputStream_iface.lpVtbl = &nsInputStreamVtbl;
212     ret->ref = 1;
213     ret->buf_size = 0;
214
215     return ret;
216 }
217
218 static inline BSCallback *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
219 {
220     return CONTAINING_RECORD(iface, BSCallback, IBindStatusCallback_iface);
221 }
222
223 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
224         REFIID riid, void **ppv)
225 {
226     BSCallback *This = impl_from_IBindStatusCallback(iface);
227
228     *ppv = NULL;
229     if(IsEqualGUID(&IID_IUnknown, riid)) {
230         TRACE("(%p)->(IID_IUnknown, %p)\n", This, ppv);
231         *ppv = &This->IBindStatusCallback_iface;
232     }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) {
233         TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This, ppv);
234         *ppv = &This->IBindStatusCallback_iface;
235     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
236         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
237         *ppv = &This->IServiceProvider_iface;
238     }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
239         TRACE("(%p)->(IID_IHttpNegotiate %p)\n", This, ppv);
240         *ppv = &This->IHttpNegotiate2_iface;
241     }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
242         TRACE("(%p)->(IID_IHttpNegotiate2 %p)\n", This, ppv);
243         *ppv = &This->IHttpNegotiate2_iface;
244     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
245         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
246         *ppv = &This->IInternetBindInfo_iface;
247     }
248
249     if(*ppv) {
250         IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
251         return S_OK;
252     }
253
254     TRACE("Unsupported riid = %s\n", debugstr_guid(riid));
255     return E_NOINTERFACE;
256 }
257
258 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
259 {
260     BSCallback *This = impl_from_IBindStatusCallback(iface);
261     LONG ref = InterlockedIncrement(&This->ref);
262
263     TRACE("(%p) ref = %d\n", This, ref);
264
265     return ref;
266 }
267
268 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
269 {
270     BSCallback *This = impl_from_IBindStatusCallback(iface);
271     LONG ref = InterlockedDecrement(&This->ref);
272
273     TRACE("(%p) ref = %d\n", This, ref);
274
275     if(!ref) {
276         if(This->post_data)
277             GlobalFree(This->post_data);
278         if(This->mon)
279             IMoniker_Release(This->mon);
280         if(This->binding)
281             IBinding_Release(This->binding);
282         list_remove(&This->entry);
283         list_init(&This->entry);
284         heap_free(This->headers);
285
286         This->vtbl->destroy(This);
287     }
288
289     return ref;
290 }
291
292 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
293         DWORD dwReserved, IBinding *pbind)
294 {
295     BSCallback *This = impl_from_IBindStatusCallback(iface);
296
297     TRACE("(%p)->(%d %p)\n", This, dwReserved, pbind);
298
299     IBinding_AddRef(pbind);
300     This->binding = pbind;
301
302     if(This->window)
303         list_add_head(&This->window->bindings, &This->entry);
304
305     return This->vtbl->start_binding(This);
306 }
307
308 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
309 {
310     BSCallback *This = impl_from_IBindStatusCallback(iface);
311     FIXME("(%p)->(%p)\n", This, pnPriority);
312     return E_NOTIMPL;
313 }
314
315 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
316 {
317     BSCallback *This = impl_from_IBindStatusCallback(iface);
318     FIXME("(%p)->(%d)\n", This, reserved);
319     return E_NOTIMPL;
320 }
321
322 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
323         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
324 {
325     BSCallback *This = impl_from_IBindStatusCallback(iface);
326
327     TRACE("%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
328             debugstr_w(szStatusText));
329
330     return This->vtbl->on_progress(This, ulStatusCode, szStatusText);
331 }
332
333 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
334         HRESULT hresult, LPCWSTR szError)
335 {
336     BSCallback *This = impl_from_IBindStatusCallback(iface);
337     HRESULT hres;
338
339     TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
340
341     /* NOTE: IE7 calls GetBindResult here */
342
343     hres = This->vtbl->stop_binding(This, hresult);
344
345     if(This->binding) {
346         IBinding_Release(This->binding);
347         This->binding = NULL;
348     }
349
350     list_remove(&This->entry);
351     list_init(&This->entry);
352     This->window = NULL;
353
354     return hres;
355 }
356
357 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
358         DWORD *grfBINDF, BINDINFO *pbindinfo)
359 {
360     BSCallback *This = impl_from_IBindStatusCallback(iface);
361     DWORD size;
362
363     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
364
365     if(!This->bindinfo_ready) {
366         HRESULT hres;
367
368         hres = This->vtbl->init_bindinfo(This);
369         if(FAILED(hres))
370             return hres;
371
372         This->bindinfo_ready = TRUE;
373     }
374
375     *grfBINDF = This->bindf;
376
377     size = pbindinfo->cbSize;
378     memset(pbindinfo, 0, size);
379     pbindinfo->cbSize = size;
380
381     pbindinfo->cbstgmedData = This->post_data_len;
382     pbindinfo->dwCodePage = CP_UTF8;
383     pbindinfo->dwOptions = 0x80000;
384
385     if(This->post_data) {
386         pbindinfo->dwBindVerb = BINDVERB_POST;
387
388         pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
389         pbindinfo->stgmedData.u.hGlobal = This->post_data;
390         pbindinfo->stgmedData.pUnkForRelease = (IUnknown*)&This->IBindStatusCallback_iface;
391         IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
392     }
393
394     return S_OK;
395 }
396
397 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
398         DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
399 {
400     BSCallback *This = impl_from_IBindStatusCallback(iface);
401
402     TRACE("(%p)->(%08x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
403
404     return This->vtbl->read_data(This, pstgmed->u.pstm);
405 }
406
407 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
408         REFIID riid, IUnknown *punk)
409 {
410     BSCallback *This = impl_from_IBindStatusCallback(iface);
411     FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), punk);
412     return E_NOTIMPL;
413 }
414
415 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
416     BindStatusCallback_QueryInterface,
417     BindStatusCallback_AddRef,
418     BindStatusCallback_Release,
419     BindStatusCallback_OnStartBinding,
420     BindStatusCallback_GetPriority,
421     BindStatusCallback_OnLowResource,
422     BindStatusCallback_OnProgress,
423     BindStatusCallback_OnStopBinding,
424     BindStatusCallback_GetBindInfo,
425     BindStatusCallback_OnDataAvailable,
426     BindStatusCallback_OnObjectAvailable
427 };
428
429 static inline BSCallback *impl_from_IHttpNegotiate2(IHttpNegotiate2 *iface)
430 {
431     return CONTAINING_RECORD(iface, BSCallback, IHttpNegotiate2_iface);
432 }
433
434 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface,
435                                                    REFIID riid, void **ppv)
436 {
437     BSCallback *This = impl_from_IHttpNegotiate2(iface);
438     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
439 }
440
441 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate2 *iface)
442 {
443     BSCallback *This = impl_from_IHttpNegotiate2(iface);
444     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
445 }
446
447 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface)
448 {
449     BSCallback *This = impl_from_IHttpNegotiate2(iface);
450     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
451 }
452
453 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface,
454         LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
455 {
456     BSCallback *This = impl_from_IHttpNegotiate2(iface);
457     HRESULT hres;
458
459     TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders),
460           dwReserved, pszAdditionalHeaders);
461
462     *pszAdditionalHeaders = NULL;
463
464     hres = This->vtbl->beginning_transaction(This, pszAdditionalHeaders);
465     if(hres != S_FALSE)
466         return hres;
467
468     if(This->headers) {
469         DWORD size;
470
471         size = (strlenW(This->headers)+1)*sizeof(WCHAR);
472         *pszAdditionalHeaders = CoTaskMemAlloc(size);
473         if(!*pszAdditionalHeaders)
474             return E_OUTOFMEMORY;
475         memcpy(*pszAdditionalHeaders, This->headers, size);
476     }
477
478     return S_OK;
479 }
480
481 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
482         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
483 {
484     BSCallback *This = impl_from_IHttpNegotiate2(iface);
485
486     TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
487           debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
488
489     return This->vtbl->on_response(This, dwResponseCode, szResponseHeaders);
490 }
491
492 static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
493         BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
494 {
495     BSCallback *This = impl_from_IHttpNegotiate2(iface);
496     FIXME("(%p)->(%p %p %ld)\n", This, pbSecurityId, pcbSecurityId, dwReserved);
497     return E_NOTIMPL;
498 }
499
500 static const IHttpNegotiate2Vtbl HttpNegotiate2Vtbl = {
501     HttpNegotiate_QueryInterface,
502     HttpNegotiate_AddRef,
503     HttpNegotiate_Release,
504     HttpNegotiate_BeginningTransaction,
505     HttpNegotiate_OnResponse,
506     HttpNegotiate_GetRootSecurityId
507 };
508
509 static inline BSCallback *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
510 {
511     return CONTAINING_RECORD(iface, BSCallback, IInternetBindInfo_iface);
512 }
513
514 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
515                                                       REFIID riid, void **ppv)
516 {
517     BSCallback *This = impl_from_IInternetBindInfo(iface);
518     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
519 }
520
521 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
522 {
523     BSCallback *This = impl_from_IInternetBindInfo(iface);
524     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
525 }
526
527 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
528 {
529     BSCallback *This = impl_from_IInternetBindInfo(iface);
530     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
531 }
532
533 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
534                                                    DWORD *grfBINDF, BINDINFO *pbindinfo)
535 {
536     BSCallback *This = impl_from_IInternetBindInfo(iface);
537     FIXME("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
538     return E_NOTIMPL;
539 }
540
541 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
542         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
543 {
544     BSCallback *This = impl_from_IInternetBindInfo(iface);
545     FIXME("(%p)->(%u %p %u %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
546     return E_NOTIMPL;
547 }
548
549 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
550     InternetBindInfo_QueryInterface,
551     InternetBindInfo_AddRef,
552     InternetBindInfo_Release,
553     InternetBindInfo_GetBindInfo,
554     InternetBindInfo_GetBindString
555 };
556
557 static inline BSCallback *impl_from_IServiceProvider(IServiceProvider *iface)
558 {
559     return CONTAINING_RECORD(iface, BSCallback, IServiceProvider_iface);
560 }
561
562 static HRESULT WINAPI BSCServiceProvider_QueryInterface(IServiceProvider *iface,
563                                                         REFIID riid, void **ppv)
564 {
565     BSCallback *This = impl_from_IServiceProvider(iface);
566     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
567 }
568
569 static ULONG WINAPI BSCServiceProvider_AddRef(IServiceProvider *iface)
570 {
571     BSCallback *This = impl_from_IServiceProvider(iface);
572     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
573 }
574
575 static ULONG WINAPI BSCServiceProvider_Release(IServiceProvider *iface)
576 {
577     BSCallback *This = impl_from_IServiceProvider(iface);
578     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
579 }
580
581 static HRESULT WINAPI BSCServiceProvider_QueryService(IServiceProvider *iface,
582         REFGUID guidService, REFIID riid, void **ppv)
583 {
584     BSCallback *This = impl_from_IServiceProvider(iface);
585
586     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
587
588     if(This->window && IsEqualGUID(guidService, &IID_IWindowForBindingUI))
589         return IServiceProvider_QueryService(&This->window->base.IServiceProvider_iface, guidService, riid, ppv);
590     return E_NOINTERFACE;
591 }
592
593 static const IServiceProviderVtbl ServiceProviderVtbl = {
594     BSCServiceProvider_QueryInterface,
595     BSCServiceProvider_AddRef,
596     BSCServiceProvider_Release,
597     BSCServiceProvider_QueryService
598 };
599
600 static void init_bscallback(BSCallback *This, const BSCallbackVtbl *vtbl, IMoniker *mon, DWORD bindf)
601 {
602     This->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl;
603     This->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
604     This->IHttpNegotiate2_iface.lpVtbl = &HttpNegotiate2Vtbl;
605     This->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl;
606     This->vtbl = vtbl;
607     This->ref = 1;
608     This->bindf = bindf;
609
610     list_init(&This->entry);
611
612     if(mon)
613         IMoniker_AddRef(mon);
614     This->mon = mon;
615 }
616
617 static void parse_content_type(nsChannelBSC *This, const WCHAR *value)
618 {
619     const WCHAR *ptr;
620     size_t len;
621
622     static const WCHAR charsetW[] = {'c','h','a','r','s','e','t','='};
623
624     ptr = strchrW(value, ';');
625     if(!ptr)
626         return;
627
628     ptr++;
629     while(*ptr && isspaceW(*ptr))
630         ptr++;
631
632     len = strlenW(value);
633     if(ptr + sizeof(charsetW)/sizeof(WCHAR) < value+len && !memicmpW(ptr, charsetW, sizeof(charsetW)/sizeof(WCHAR))) {
634         size_t charset_len, lena;
635         nsACString charset_str;
636         const WCHAR *charset;
637         char *charseta;
638
639         ptr += sizeof(charsetW)/sizeof(WCHAR);
640
641         if(*ptr == '\'') {
642             FIXME("Quoted value\n");
643             return;
644         }else {
645             charset = ptr;
646             while(*ptr && *ptr != ',')
647                 ptr++;
648             charset_len = ptr-charset;
649         }
650
651         lena = WideCharToMultiByte(CP_ACP, 0, charset, charset_len, NULL, 0, NULL, NULL);
652         charseta = heap_alloc(lena+1);
653         if(!charseta)
654             return;
655
656         WideCharToMultiByte(CP_ACP, 0, charset, charset_len, charseta, lena, NULL, NULL);
657         charseta[lena] = 0;
658
659         nsACString_InitDepend(&charset_str, charseta);
660         nsIHttpChannel_SetContentCharset(&This->nschannel->nsIHttpChannel_iface, &charset_str);
661         nsACString_Finish(&charset_str);
662         heap_free(charseta);
663     }else {
664         FIXME("unhandled: %s\n", debugstr_wn(ptr, len - (ptr-value)));
665     }
666 }
667
668 static HRESULT parse_headers(const WCHAR *headers, struct list *headers_list)
669 {
670     const WCHAR *header, *header_end, *colon, *value;
671     HRESULT hres;
672
673     header = headers;
674     while(*header) {
675         if(header[0] == '\r' && header[1] == '\n' && !header[2])
676             break;
677         for(colon = header; *colon && *colon != ':' && *colon != '\r'; colon++);
678         if(*colon != ':')
679             return E_FAIL;
680
681         value = colon+1;
682         while(*value == ' ')
683             value++;
684         if(!*value)
685             return E_FAIL;
686
687         for(header_end = value+1; *header_end && *header_end != '\r'; header_end++);
688
689         hres = set_http_header(headers_list, header, colon-header, value, header_end-value);
690         if(FAILED(hres))
691             return hres;
692
693         header = header_end;
694         if(header[0] == '\r' && header[1] == '\n')
695             header += 2;
696     }
697
698     return S_OK;
699 }
700
701 static HRESULT process_response_headers(nsChannelBSC *This, const WCHAR *headers)
702 {
703     http_header_t *iter;
704     HRESULT hres;
705
706     static const WCHAR content_typeW[] = {'c','o','n','t','e','n','t','-','t','y','p','e',0};
707
708     hres = parse_headers(headers, &This->nschannel->response_headers);
709     if(FAILED(hres))
710         return hres;
711
712     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->response_headers, http_header_t, entry) {
713         if(!strcmpiW(iter->header, content_typeW))
714             parse_content_type(This, iter->data);
715     }
716
717     return S_OK;
718 }
719
720 HRESULT start_binding(HTMLInnerWindow *inner_window, BSCallback *bscallback, IBindCtx *bctx)
721 {
722     IStream *str = NULL;
723     HRESULT hres;
724
725     TRACE("(%p %p %p)\n", inner_window, bscallback, bctx);
726
727     bscallback->window = inner_window;
728
729     /* NOTE: IE7 calls IsSystemMoniker here*/
730
731     if(bctx) {
732         RegisterBindStatusCallback(bctx, &bscallback->IBindStatusCallback_iface, NULL, 0);
733         IBindCtx_AddRef(bctx);
734     }else {
735         hres = CreateAsyncBindCtx(0, &bscallback->IBindStatusCallback_iface, NULL, &bctx);
736         if(FAILED(hres)) {
737             WARN("CreateAsyncBindCtx failed: %08x\n", hres);
738             bscallback->vtbl->stop_binding(bscallback, hres);
739             return hres;
740         }
741     }
742
743     hres = IMoniker_BindToStorage(bscallback->mon, bctx, NULL, &IID_IStream, (void**)&str);
744     IBindCtx_Release(bctx);
745     if(FAILED(hres)) {
746         WARN("BindToStorage failed: %08x\n", hres);
747         bscallback->vtbl->stop_binding(bscallback, hres);
748         return hres;
749     }
750
751     if(str)
752         IStream_Release(str);
753
754     IMoniker_Release(bscallback->mon);
755     bscallback->mon = NULL;
756
757     return S_OK;
758 }
759
760 typedef struct {
761     BSCallback bsc;
762
763     DWORD size;
764     BYTE *buf;
765     HRESULT hres;
766 } BufferBSC;
767
768 static inline BufferBSC *BufferBSC_from_BSCallback(BSCallback *iface)
769 {
770     return CONTAINING_RECORD(iface, BufferBSC, bsc);
771 }
772
773 static void BufferBSC_destroy(BSCallback *bsc)
774 {
775     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
776
777     heap_free(This->buf);
778     heap_free(This);
779 }
780
781 static HRESULT BufferBSC_init_bindinfo(BSCallback *bsc)
782 {
783     return S_OK;
784 }
785
786 static HRESULT BufferBSC_start_binding(BSCallback *bsc)
787 {
788     return S_OK;
789 }
790
791 static HRESULT BufferBSC_stop_binding(BSCallback *bsc, HRESULT result)
792 {
793     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
794
795     This->hres = result;
796
797     if(FAILED(result)) {
798         heap_free(This->buf);
799         This->buf = NULL;
800         This->size = 0;
801     }
802
803     return S_OK;
804 }
805
806 static HRESULT BufferBSC_read_data(BSCallback *bsc, IStream *stream)
807 {
808     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
809     DWORD readed;
810     HRESULT hres;
811
812     if(!This->buf) {
813         This->size = 128;
814         This->buf = heap_alloc(This->size);
815     }
816
817     do {
818         if(This->bsc.readed == This->size) {
819             This->size <<= 1;
820             This->buf = heap_realloc(This->buf, This->size);
821         }
822
823         readed = 0;
824         hres = IStream_Read(stream, This->buf+This->bsc.readed, This->size-This->bsc.readed, &readed);
825         This->bsc.readed += readed;
826     }while(hres == S_OK);
827
828     return S_OK;
829 }
830
831 static HRESULT BufferBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
832 {
833     return S_OK;
834 }
835
836 static HRESULT BufferBSC_on_response(BSCallback *bsc, DWORD response_code,
837         LPCWSTR response_headers)
838 {
839     return S_OK;
840 }
841
842 static HRESULT BufferBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
843 {
844     return S_FALSE;
845 }
846
847 static const BSCallbackVtbl BufferBSCVtbl = {
848     BufferBSC_destroy,
849     BufferBSC_init_bindinfo,
850     BufferBSC_start_binding,
851     BufferBSC_stop_binding,
852     BufferBSC_read_data,
853     BufferBSC_on_progress,
854     BufferBSC_on_response,
855     BufferBSC_beginning_transaction
856 };
857
858
859 static BufferBSC *create_bufferbsc(IMoniker *mon)
860 {
861     BufferBSC *ret = heap_alloc_zero(sizeof(*ret));
862
863     init_bscallback(&ret->bsc, &BufferBSCVtbl, mon, 0);
864     ret->hres = E_FAIL;
865
866     return ret;
867 }
868
869 HRESULT bind_mon_to_buffer(HTMLInnerWindow *window, IMoniker *mon, void **buf, DWORD *size)
870 {
871     BufferBSC *bsc = create_bufferbsc(mon);
872     HRESULT hres;
873
874     *buf = NULL;
875
876     hres = start_binding(window, &bsc->bsc, NULL);
877     if(SUCCEEDED(hres)) {
878         hres = bsc->hres;
879         if(SUCCEEDED(hres)) {
880             *buf = bsc->buf;
881             bsc->buf = NULL;
882             *size = bsc->bsc.readed;
883             bsc->size = 0;
884         }
885     }
886
887     IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
888
889     return hres;
890 }
891
892 static HRESULT read_post_data_stream(nsChannelBSC *This, nsChannel *nschannel)
893 {
894     PRUint32 data_len = 0, available = 0;
895     char *data, *post_data;
896     nsresult nsres;
897     HRESULT hres = S_OK;
898
899     if(!nschannel->post_data_stream)
900         return S_OK;
901
902     nsres =  nsIInputStream_Available(nschannel->post_data_stream, &available);
903     if(NS_FAILED(nsres))
904         return E_FAIL;
905
906     post_data = data = GlobalAlloc(0, available);
907     if(!data)
908         return E_OUTOFMEMORY;
909
910     nsres = nsIInputStream_Read(nschannel->post_data_stream, data, available, &data_len);
911     if(NS_FAILED(nsres)) {
912         GlobalFree(data);
913         return E_FAIL;
914     }
915
916     if(nschannel->post_data_contains_headers) {
917         if(data_len >= 2 && data[0] == '\r' && data[1] == '\n') {
918             post_data = data+2;
919             data_len -= 2;
920         }else {
921             WCHAR *headers;
922             DWORD size;
923             char *ptr;
924
925             post_data += data_len;
926             for(ptr = data; ptr+4 < data+data_len; ptr++) {
927                 if(!memcmp(ptr, "\r\n\r\n", 4)) {
928                     post_data = ptr+4;
929                     break;
930                 }
931             }
932
933             data_len -= post_data-data;
934
935             size = MultiByteToWideChar(CP_ACP, 0, data, post_data-data, NULL, 0);
936             headers = heap_alloc((size+1)*sizeof(WCHAR));
937             if(headers) {
938                 MultiByteToWideChar(CP_ACP, 0, data, post_data-data, headers, size);
939                 headers[size] = 0;
940                 hres = parse_headers(headers , &nschannel->request_headers);
941                 if(SUCCEEDED(hres))
942                     This->bsc.headers = headers;
943                 else
944                     heap_free(headers);
945             }else {
946                 hres = E_OUTOFMEMORY;
947             }
948         }
949     }
950
951     if(FAILED(hres)) {
952         GlobalFree(data);
953         return hres;
954     }
955
956     if(!data_len) {
957         GlobalFree(data);
958         post_data = NULL;
959     }else if(post_data != data) {
960         char *new_data;
961
962         new_data = GlobalAlloc(0, data_len);
963         if(new_data)
964             memcpy(new_data, post_data, data_len);
965         GlobalFree(data);
966         if(!new_data)
967             return E_OUTOFMEMORY;
968         post_data = new_data;
969     }
970
971     This->bsc.post_data = post_data;
972     This->bsc.post_data_len = data_len;
973     TRACE("post_data = %s\n", debugstr_a(This->bsc.post_data));
974     return S_OK;
975 }
976
977 static HRESULT on_start_nsrequest(nsChannelBSC *This)
978 {
979     nsresult nsres;
980
981     /* FIXME: it's needed for http connections from BindToObject. */
982     if(!This->nschannel->response_status)
983         This->nschannel->response_status = 200;
984
985     nsres = nsIStreamListener_OnStartRequest(This->nslistener,
986             (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext);
987     if(NS_FAILED(nsres)) {
988         FIXME("OnStartRequest failed: %08x\n", nsres);
989         return E_FAIL;
990     }
991
992     if(This->is_doc_channel) {
993         update_window_doc(This->bsc.window);
994         if(This->bsc.window->base.outer_window->readystate != READYSTATE_LOADING)
995             set_ready_state(This->bsc.window->base.outer_window, READYSTATE_LOADING);
996     }
997
998     return S_OK;
999 }
1000
1001 static void on_stop_nsrequest(nsChannelBSC *This, HRESULT result)
1002 {
1003     nsresult nsres, request_result;
1004
1005     switch(result) {
1006     case S_OK:
1007         request_result = NS_OK;
1008         break;
1009     case E_ABORT:
1010         request_result = NS_BINDING_ABORTED;
1011         break;
1012     default:
1013         request_result = NS_ERROR_FAILURE;
1014     }
1015
1016     if(This->nslistener) {
1017         nsres = nsIStreamListener_OnStopRequest(This->nslistener,
1018                  (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext,
1019                  request_result);
1020         if(NS_FAILED(nsres))
1021             WARN("OnStopRequest failed: %08x\n", nsres);
1022     }
1023
1024     if(This->nschannel->load_group) {
1025         nsres = nsILoadGroup_RemoveRequest(This->nschannel->load_group,
1026                 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, NULL, request_result);
1027         if(NS_FAILED(nsres))
1028             ERR("RemoveRequest failed: %08x\n", nsres);
1029     }
1030 }
1031
1032 static HRESULT read_stream_data(nsChannelBSC *This, IStream *stream)
1033 {
1034     static const WCHAR mimeTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
1035
1036     DWORD read;
1037     nsresult nsres;
1038     HRESULT hres;
1039
1040     if(!This->nslistener) {
1041         BYTE buf[1024];
1042
1043         do {
1044             read = 0;
1045             hres = IStream_Read(stream, buf, sizeof(buf), &read);
1046         }while(hres == S_OK && read);
1047
1048         return S_OK;
1049     }
1050
1051     if(!This->nsstream)
1052         This->nsstream = create_nsprotocol_stream();
1053
1054     do {
1055         read = 0;
1056         hres = IStream_Read(stream, This->nsstream->buf+This->nsstream->buf_size,
1057                 sizeof(This->nsstream->buf)-This->nsstream->buf_size, &read);
1058         if(!read)
1059             break;
1060
1061         This->nsstream->buf_size += read;
1062
1063         if(!This->bsc.readed) {
1064             if(This->nsstream->buf_size >= 2
1065                && (BYTE)This->nsstream->buf[0] == 0xff
1066                && (BYTE)This->nsstream->buf[1] == 0xfe)
1067                 This->nschannel->charset = heap_strdupA(UTF16_STR);
1068             if(This->nsstream->buf_size >= 3
1069                && (BYTE)This->nsstream->buf[0] == 0xef
1070                && (BYTE)This->nsstream->buf[1] == 0xbb
1071                && (BYTE)This->nsstream->buf[2] == 0xbf)
1072                 This->nschannel->charset = heap_strdupA(UTF8_STR);
1073
1074             if(!This->nschannel->content_type) {
1075                 WCHAR *mime;
1076
1077                 hres = FindMimeFromData(NULL, NULL, This->nsstream->buf, This->nsstream->buf_size,
1078                         This->is_doc_channel ? mimeTextHtml : NULL, 0, &mime, 0);
1079                 if(FAILED(hres))
1080                     return hres;
1081
1082                 TRACE("Found MIME %s\n", debugstr_w(mime));
1083
1084                 This->nschannel->content_type = heap_strdupWtoA(mime);
1085                 CoTaskMemFree(mime);
1086                 if(!This->nschannel->content_type)
1087                     return E_OUTOFMEMORY;
1088             }
1089
1090             on_start_nsrequest(This);
1091         }
1092
1093         This->bsc.readed += This->nsstream->buf_size;
1094
1095         nsres = nsIStreamListener_OnDataAvailable(This->nslistener,
1096                 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext,
1097                 &This->nsstream->nsIInputStream_iface, This->bsc.readed-This->nsstream->buf_size,
1098                 This->nsstream->buf_size);
1099         if(NS_FAILED(nsres))
1100             ERR("OnDataAvailable failed: %08x\n", nsres);
1101
1102         if(This->nsstream->buf_size == sizeof(This->nsstream->buf)) {
1103             ERR("buffer is full\n");
1104             break;
1105         }
1106     }while(hres == S_OK);
1107
1108     return S_OK;
1109 }
1110
1111 typedef struct {
1112     nsIAsyncVerifyRedirectCallback nsIAsyncVerifyRedirectCallback_iface;
1113
1114     LONG ref;
1115
1116     nsChannel *nschannel;
1117     nsChannelBSC *bsc;
1118 } nsRedirectCallback;
1119
1120 static nsRedirectCallback *impl_from_nsIAsyncVerifyRedirectCallback(nsIAsyncVerifyRedirectCallback *iface)
1121 {
1122     return CONTAINING_RECORD(iface, nsRedirectCallback, nsIAsyncVerifyRedirectCallback_iface);
1123 }
1124
1125 static nsresult NSAPI nsAsyncVerifyRedirectCallback_QueryInterface(nsIAsyncVerifyRedirectCallback *iface,
1126         nsIIDRef riid, void **result)
1127 {
1128     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1129
1130     if(IsEqualGUID(&IID_nsISupports, riid)) {
1131         TRACE("(%p)->(IID_nsISuports %p)\n", This, result);
1132         *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1133     }else if(IsEqualGUID(&IID_nsIAsyncVerifyRedirectCallback, riid)) {
1134         TRACE("(%p)->(IID_nsIAsyncVerifyRedirectCallback %p)\n", This, result);
1135         *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1136     }else {
1137         *result = NULL;
1138         WARN("unimplemented iface %s\n", debugstr_guid(riid));
1139         return NS_NOINTERFACE;
1140     }
1141
1142     nsISupports_AddRef((nsISupports*)*result);
1143     return NS_OK;
1144 }
1145
1146 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_AddRef(nsIAsyncVerifyRedirectCallback *iface)
1147 {
1148     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1149     LONG ref = InterlockedIncrement(&This->ref);
1150
1151     TRACE("(%p) ref=%d\n", This, ref);
1152
1153     return ref;
1154 }
1155
1156 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_Release(nsIAsyncVerifyRedirectCallback *iface)
1157 {
1158     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1159     LONG ref = InterlockedDecrement(&This->ref);
1160
1161     TRACE("(%p) ref=%d\n", This, ref);
1162
1163     if(!ref) {
1164         IBindStatusCallback_Release(&This->bsc->bsc.IBindStatusCallback_iface);
1165         nsIChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1166         heap_free(This);
1167     }
1168
1169     return ref;
1170 }
1171
1172 static nsresult NSAPI nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect(nsIAsyncVerifyRedirectCallback *iface, nsresult result)
1173 {
1174     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1175     nsChannel *old_nschannel;
1176     nsresult nsres;
1177
1178     TRACE("(%p)->(%08x)\n", This, result);
1179
1180     old_nschannel = This->bsc->nschannel;
1181     nsIChannel_AddRef(&This->nschannel->nsIHttpChannel_iface);
1182     This->bsc->nschannel = This->nschannel;
1183
1184     if(This->nschannel->load_group) {
1185         nsres = nsILoadGroup_AddRequest(This->nschannel->load_group, (nsIRequest*)&This->nschannel->nsIHttpChannel_iface,
1186                 NULL);
1187         if(NS_FAILED(nsres))
1188             ERR("AddRequest failed: %08x\n", nsres);
1189     }
1190
1191     if(This->bsc->is_doc_channel) {
1192         IUri *uri = nsuri_get_uri(This->nschannel->uri);
1193
1194         if(uri) {
1195             set_current_uri(This->bsc->bsc.window->base.outer_window, uri);
1196             IUri_Release(uri);
1197         }else {
1198             WARN("Could not get IUri from nsWineURI\n");
1199         }
1200     }
1201
1202     if(old_nschannel) {
1203         nsres = nsILoadGroup_RemoveRequest(old_nschannel->load_group,
1204                 (nsIRequest*)&old_nschannel->nsIHttpChannel_iface, NULL, NS_OK);
1205         if(NS_FAILED(nsres))
1206             ERR("RemoveRequest failed: %08x\n", nsres);
1207         nsIHttpChannel_Release(&old_nschannel->nsIHttpChannel_iface);
1208     }
1209
1210     return NS_OK;
1211 }
1212
1213 static const nsIAsyncVerifyRedirectCallbackVtbl nsAsyncVerifyRedirectCallbackVtbl = {
1214     nsAsyncVerifyRedirectCallback_QueryInterface,
1215     nsAsyncVerifyRedirectCallback_AddRef,
1216     nsAsyncVerifyRedirectCallback_Release,
1217     nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect
1218 };
1219
1220 static HRESULT create_redirect_callback(nsChannel *nschannel, nsChannelBSC *bsc, nsRedirectCallback **ret)
1221 {
1222     nsRedirectCallback *callback;
1223
1224     callback = heap_alloc(sizeof(*callback));
1225     if(!callback)
1226         return E_OUTOFMEMORY;
1227
1228     callback->nsIAsyncVerifyRedirectCallback_iface.lpVtbl = &nsAsyncVerifyRedirectCallbackVtbl;
1229     callback->ref = 1;
1230
1231     nsIChannel_AddRef(&nschannel->nsIHttpChannel_iface);
1232     callback->nschannel = nschannel;
1233
1234     IBindStatusCallback_AddRef(&bsc->bsc.IBindStatusCallback_iface);
1235     callback->bsc = bsc;
1236
1237     *ret = callback;
1238     return S_OK;
1239 }
1240
1241 static inline nsChannelBSC *nsChannelBSC_from_BSCallback(BSCallback *iface)
1242 {
1243     return CONTAINING_RECORD(iface, nsChannelBSC, bsc);
1244 }
1245
1246 static void nsChannelBSC_destroy(BSCallback *bsc)
1247 {
1248     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1249
1250     if(This->nschannel)
1251         nsIChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1252     if(This->nslistener)
1253         nsIStreamListener_Release(This->nslistener);
1254     if(This->nscontext)
1255         nsISupports_Release(This->nscontext);
1256     if(This->nsstream)
1257         nsIInputStream_Release(&This->nsstream->nsIInputStream_iface);
1258     heap_free(This);
1259 }
1260
1261 static HRESULT nsChannelBSC_start_binding(BSCallback *bsc)
1262 {
1263     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1264
1265     if(This->is_doc_channel)
1266         This->bsc.window->base.outer_window->base.inner_window->doc->skip_mutation_notif = FALSE;
1267
1268     return S_OK;
1269 }
1270
1271 static HRESULT nsChannelBSC_init_bindinfo(BSCallback *bsc)
1272 {
1273     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1274     HRESULT hres;
1275
1276     if(This->nschannel && This->nschannel->post_data_stream) {
1277         hres = read_post_data_stream(This, This->nschannel);
1278         if(FAILED(hres))
1279             return hres;
1280     }
1281
1282     return S_OK;
1283 }
1284
1285 typedef struct {
1286     task_t header;
1287     nsChannelBSC *bsc;
1288 } stop_request_task_t;
1289
1290 static void stop_request_proc(task_t *_task)
1291 {
1292     stop_request_task_t *task = (stop_request_task_t*)_task;
1293
1294     TRACE("(%p)\n", task->bsc);
1295
1296     list_remove(&task->bsc->bsc.entry);
1297     list_init(&task->bsc->bsc.entry);
1298     on_stop_nsrequest(task->bsc, S_OK);
1299 }
1300
1301 static void stop_request_task_destr(task_t *_task)
1302 {
1303     stop_request_task_t *task = (stop_request_task_t*)_task;
1304
1305     IBindStatusCallback_Release(&task->bsc->bsc.IBindStatusCallback_iface);
1306     heap_free(task);
1307 }
1308
1309 static HRESULT async_stop_request(nsChannelBSC *This)
1310 {
1311     stop_request_task_t *task;
1312
1313     if(!This->bsc.readed) {
1314         TRACE("No data read, calling OnStartRequest\n");
1315         on_start_nsrequest(This);
1316     }
1317
1318     task = heap_alloc(sizeof(*task));
1319     if(!task)
1320         return E_OUTOFMEMORY;
1321
1322     IBindStatusCallback_AddRef(&This->bsc.IBindStatusCallback_iface);
1323     task->bsc = This;
1324
1325     push_task(&task->header, stop_request_proc, stop_request_task_destr, This->bsc.window->task_magic);
1326     return S_OK;
1327 }
1328
1329 static void handle_navigation_error(nsChannelBSC *This, DWORD result)
1330 {
1331     HTMLOuterWindow *outer_window;
1332     HTMLDocumentObj *doc;
1333     IOleCommandTarget *olecmd;
1334     BOOL is_error_url;
1335     SAFEARRAY *sa;
1336     SAFEARRAYBOUND bound;
1337     VARIANT var, varOut;
1338     LONG ind;
1339     BSTR unk;
1340     HRESULT hres;
1341
1342     if(!This->is_doc_channel || !This->bsc.window)
1343         return;
1344
1345     outer_window = This->bsc.window->base.outer_window;
1346
1347     doc = outer_window->doc_obj;
1348     if(!doc || !doc->doc_object_service || !doc->client)
1349         return;
1350
1351     hres = IDocObjectService_IsErrorUrl(doc->doc_object_service,
1352             outer_window->url, &is_error_url);
1353     if(FAILED(hres) || is_error_url)
1354         return;
1355
1356     hres = IOleClientSite_QueryInterface(doc->client,
1357             &IID_IOleCommandTarget, (void**)&olecmd);
1358     if(FAILED(hres))
1359         return;
1360
1361     bound.lLbound = 0;
1362     bound.cElements = 8;
1363     sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1364     if(!sa) {
1365         IOleCommandTarget_Release(olecmd);
1366         return;
1367     }
1368
1369     ind = 0;
1370     V_VT(&var) = VT_I4;
1371     V_I4(&var) = result;
1372     SafeArrayPutElement(sa, &ind, &var);
1373
1374     ind = 1;
1375     V_VT(&var) = VT_BSTR;
1376     V_BSTR(&var) = outer_window->url;
1377     SafeArrayPutElement(sa, &ind, &var);
1378
1379     ind = 3;
1380     V_VT(&var) = VT_UNKNOWN;
1381     V_UNKNOWN(&var) = (IUnknown*)&outer_window->base.IHTMLWindow2_iface;
1382     SafeArrayPutElement(sa, &ind, &var);
1383
1384     /* FIXME: what are the following fields for? */
1385     ind = 2;
1386     V_VT(&var) = VT_UNKNOWN;
1387     V_UNKNOWN(&var) = NULL;
1388     SafeArrayPutElement(sa, &ind, &var);
1389
1390     ind = 4;
1391     V_VT(&var) = VT_BOOL;
1392     V_BOOL(&var) = FALSE;
1393     SafeArrayPutElement(sa, &ind, &var);
1394
1395     ind = 5;
1396     V_VT(&var) = VT_BOOL;
1397     V_BOOL(&var) = FALSE;
1398     SafeArrayPutElement(sa, &ind, &var);
1399
1400     ind = 6;
1401     V_VT(&var) = VT_BSTR;
1402     unk = SysAllocString(NULL);
1403     V_BSTR(&var) = unk;
1404     SafeArrayPutElement(sa, &ind, &var);
1405
1406     ind = 7;
1407     V_VT(&var) = VT_UNKNOWN;
1408     V_UNKNOWN(&var) = NULL;
1409     SafeArrayPutElement(sa, &ind, &var);
1410
1411     V_VT(&var) = VT_ARRAY;
1412     V_ARRAY(&var) = sa;
1413     V_VT(&varOut) = VT_BOOL;
1414     V_BOOL(&varOut) = VARIANT_TRUE;
1415     IOleCommandTarget_Exec(olecmd, &CGID_DocHostCmdPriv, 1, 0, &var, FAILED(hres)?NULL:&varOut);
1416
1417     SysFreeString(unk);
1418     SafeArrayDestroy(sa);
1419     IOleCommandTarget_Release(olecmd);
1420 }
1421
1422 static HRESULT nsChannelBSC_stop_binding(BSCallback *bsc, HRESULT result)
1423 {
1424     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1425
1426     if(result != E_ABORT) {
1427         if(FAILED(result))
1428             handle_navigation_error(This, result);
1429         else if(This->is_doc_channel) {
1430             result = async_stop_request(This);
1431             if(SUCCEEDED(result))
1432                 return S_OK;
1433         }
1434     }
1435
1436     on_stop_nsrequest(This, result);
1437     return S_OK;
1438 }
1439
1440 static HRESULT nsChannelBSC_read_data(BSCallback *bsc, IStream *stream)
1441 {
1442     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1443
1444     return read_stream_data(This, stream);
1445 }
1446
1447 static HRESULT handle_redirect(nsChannelBSC *This, const WCHAR *new_url)
1448 {
1449     nsRedirectCallback *callback;
1450     nsIChannelEventSink *sink;
1451     nsChannel *new_channel;
1452     nsresult nsres;
1453     HRESULT hres;
1454
1455     TRACE("(%p)->(%s)\n", This, debugstr_w(new_url));
1456
1457     if(!This->nschannel || !This->nschannel->notif_callback)
1458         return S_OK;
1459
1460     nsres = nsIInterfaceRequestor_GetInterface(This->nschannel->notif_callback, &IID_nsIChannelEventSink, (void**)&sink);
1461     if(NS_FAILED(nsres))
1462         return S_OK;
1463
1464     hres = create_redirect_nschannel(new_url, This->nschannel, &new_channel);
1465     if(SUCCEEDED(hres)) {
1466         TRACE("%p %p->%p\n", This, This->nschannel, new_channel);
1467
1468         hres = create_redirect_callback(new_channel, This, &callback);
1469         nsIChannel_Release(&new_channel->nsIHttpChannel_iface);
1470     }
1471
1472     if(SUCCEEDED(hres)) {
1473         nsres = nsIChannelEventSink_AsyncOnChannelRedirect(sink, (nsIChannel*)&This->nschannel->nsIHttpChannel_iface,
1474                 (nsIChannel*)&callback->nschannel->nsIHttpChannel_iface, REDIRECT_TEMPORARY, /* FIXME */
1475                 &callback->nsIAsyncVerifyRedirectCallback_iface);
1476
1477         if(NS_FAILED(nsres))
1478             FIXME("AsyncOnChannelRedirect failed: %08x\n", hres);
1479         else if(This->nschannel != callback->nschannel)
1480             FIXME("nschannel not updated\n");
1481
1482         nsIAsyncVerifyRedirectCallback_Release(&callback->nsIAsyncVerifyRedirectCallback_iface);
1483     }
1484
1485     nsIChannelEventSink_Release(sink);
1486     return hres;
1487 }
1488
1489 static HRESULT nsChannelBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
1490 {
1491     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1492
1493     switch(status_code) {
1494     case BINDSTATUS_MIMETYPEAVAILABLE:
1495         if(!This->nschannel)
1496             return S_OK;
1497
1498         heap_free(This->nschannel->content_type);
1499         This->nschannel->content_type = heap_strdupWtoA(status_text);
1500         break;
1501     case BINDSTATUS_REDIRECTING:
1502         return handle_redirect(This, status_text);
1503     case BINDSTATUS_BEGINDOWNLOADDATA: {
1504         IWinInetHttpInfo *http_info;
1505         DWORD status, size = sizeof(DWORD);
1506         HRESULT hres;
1507
1508         if(!This->bsc.binding)
1509             break;
1510
1511         hres = IBinding_QueryInterface(This->bsc.binding, &IID_IWinInetHttpInfo, (void**)&http_info);
1512         if(FAILED(hres))
1513             break;
1514
1515         hres = IWinInetHttpInfo_QueryInfo(http_info,
1516                 HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL, NULL);
1517         IWinInetHttpInfo_Release(http_info);
1518         if(FAILED(hres) || status == HTTP_STATUS_OK)
1519             break;
1520
1521         handle_navigation_error(This, status);
1522     }
1523     }
1524
1525     return S_OK;
1526 }
1527
1528 static HRESULT nsChannelBSC_on_response(BSCallback *bsc, DWORD response_code,
1529         LPCWSTR response_headers)
1530 {
1531     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1532     HRESULT hres;
1533
1534     This->nschannel->response_status = response_code;
1535
1536     if(response_headers) {
1537         const WCHAR *headers;
1538
1539         headers = strchrW(response_headers, '\r');
1540         if(headers && headers[1] == '\n') {
1541             headers += 2;
1542             hres = process_response_headers(This, headers);
1543             if(FAILED(hres)) {
1544                 WARN("parsing headers failed: %08x\n", hres);
1545                 return hres;
1546             }
1547         }
1548     }
1549
1550     return S_OK;
1551 }
1552
1553 static HRESULT nsChannelBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
1554 {
1555     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1556     http_header_t *iter;
1557     DWORD len = 0;
1558     WCHAR *ptr;
1559
1560     static const WCHAR content_lengthW[] =
1561         {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0};
1562
1563     if(!This->nschannel)
1564         return S_FALSE;
1565
1566     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->request_headers, http_header_t, entry) {
1567         if(strcmpW(iter->header, content_lengthW))
1568             len += strlenW(iter->header) + 2 /* ": " */ + strlenW(iter->data) + 2 /* "\r\n" */;
1569     }
1570
1571     if(!len)
1572         return S_OK;
1573
1574     *additional_headers = ptr = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
1575     if(!ptr)
1576         return E_OUTOFMEMORY;
1577
1578     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->request_headers, http_header_t, entry) {
1579         if(!strcmpW(iter->header, content_lengthW))
1580             continue;
1581
1582         len = strlenW(iter->header);
1583         memcpy(ptr, iter->header, len*sizeof(WCHAR));
1584         ptr += len;
1585
1586         *ptr++ = ':';
1587         *ptr++ = ' ';
1588
1589         len = strlenW(iter->data);
1590         memcpy(ptr, iter->data, len*sizeof(WCHAR));
1591         ptr += len;
1592
1593         *ptr++ = '\r';
1594         *ptr++ = '\n';
1595     }
1596
1597     *ptr = 0;
1598
1599     return S_OK;
1600 }
1601
1602 static const BSCallbackVtbl nsChannelBSCVtbl = {
1603     nsChannelBSC_destroy,
1604     nsChannelBSC_init_bindinfo,
1605     nsChannelBSC_start_binding,
1606     nsChannelBSC_stop_binding,
1607     nsChannelBSC_read_data,
1608     nsChannelBSC_on_progress,
1609     nsChannelBSC_on_response,
1610     nsChannelBSC_beginning_transaction
1611 };
1612
1613 HRESULT create_channelbsc(IMoniker *mon, const WCHAR *headers, BYTE *post_data, DWORD post_data_size,
1614         BOOL is_doc_binding, nsChannelBSC **retval)
1615 {
1616     nsChannelBSC *ret;
1617
1618     ret = heap_alloc_zero(sizeof(*ret));
1619     if(!ret)
1620         return E_OUTOFMEMORY;
1621
1622     init_bscallback(&ret->bsc, &nsChannelBSCVtbl, mon, BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA);
1623     ret->is_doc_channel = is_doc_binding;
1624
1625     if(headers) {
1626         ret->bsc.headers = heap_strdupW(headers);
1627         if(!ret->bsc.headers) {
1628             IBindStatusCallback_Release(&ret->bsc.IBindStatusCallback_iface);
1629             return E_OUTOFMEMORY;
1630         }
1631     }
1632
1633     if(post_data) {
1634         ret->bsc.post_data = GlobalAlloc(0, post_data_size);
1635         if(!ret->bsc.post_data) {
1636             heap_free(ret->bsc.headers);
1637             IBindStatusCallback_Release(&ret->bsc.IBindStatusCallback_iface);
1638             return E_OUTOFMEMORY;
1639         }
1640
1641         memcpy(ret->bsc.post_data, post_data, post_data_size);
1642         ret->bsc.post_data_len = post_data_size;
1643     }
1644
1645     *retval = ret;
1646     return S_OK;
1647 }
1648
1649 typedef struct {
1650     task_t header;
1651     HTMLOuterWindow *window;
1652     HTMLInnerWindow *pending_window;
1653 } start_doc_binding_task_t;
1654
1655 static void start_doc_binding_proc(task_t *_task)
1656 {
1657     start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task;
1658
1659     set_current_mon(task->window, task->pending_window->bscallback->bsc.mon);
1660     start_binding(task->pending_window, &task->pending_window->bscallback->bsc, NULL);
1661 }
1662
1663 static void start_doc_binding_task_destr(task_t *_task)
1664 {
1665     start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task;
1666
1667     IHTMLWindow2_Release(&task->pending_window->base.IHTMLWindow2_iface);
1668     heap_free(task);
1669 }
1670
1671 HRESULT async_start_doc_binding(HTMLOuterWindow *window, HTMLInnerWindow *pending_window)
1672 {
1673     start_doc_binding_task_t *task;
1674
1675     TRACE("%p\n", pending_window);
1676
1677     task = heap_alloc(sizeof(start_doc_binding_task_t));
1678     if(!task)
1679         return E_OUTOFMEMORY;
1680
1681     task->window = window;
1682     task->pending_window = pending_window;
1683     IHTMLWindow2_AddRef(&pending_window->base.IHTMLWindow2_iface);
1684
1685     push_task(&task->header, start_doc_binding_proc, start_doc_binding_task_destr, pending_window->task_magic);
1686     return S_OK;
1687 }
1688
1689 void abort_window_bindings(HTMLInnerWindow *window)
1690 {
1691     BSCallback *iter;
1692
1693     remove_target_tasks(window->task_magic);
1694
1695     while(!list_empty(&window->bindings)) {
1696         iter = LIST_ENTRY(window->bindings.next, BSCallback, entry);
1697
1698         TRACE("Aborting %p\n", iter);
1699
1700         IBindStatusCallback_AddRef(&iter->IBindStatusCallback_iface);
1701
1702         if(iter->binding)
1703             IBinding_Abort(iter->binding);
1704         else
1705             iter->vtbl->stop_binding(iter, E_ABORT);
1706
1707         iter->window = NULL;
1708         list_remove(&iter->entry);
1709         list_init(&iter->entry);
1710
1711         IBindStatusCallback_Release(&iter->IBindStatusCallback_iface);
1712     }
1713
1714     if(window->bscallback) {
1715         IBindStatusCallback_Release(&window->bscallback->bsc.IBindStatusCallback_iface);
1716         window->bscallback = NULL;
1717     }
1718 }
1719
1720 HRESULT channelbsc_load_stream(HTMLInnerWindow *pending_window, IStream *stream)
1721 {
1722     nsChannelBSC *bscallback = pending_window->bscallback;
1723     HRESULT hres = S_OK;
1724
1725     if(!bscallback->nschannel) {
1726         ERR("NULL nschannel\n");
1727         return E_FAIL;
1728     }
1729
1730     bscallback->nschannel->content_type = heap_strdupA("text/html");
1731     if(!bscallback->nschannel->content_type)
1732         return E_OUTOFMEMORY;
1733
1734     bscallback->bsc.window = pending_window;
1735     if(stream)
1736         hres = read_stream_data(bscallback, stream);
1737     if(SUCCEEDED(hres))
1738         hres = async_stop_request(bscallback);
1739     if(FAILED(hres))
1740         IBindStatusCallback_OnStopBinding(&bscallback->bsc.IBindStatusCallback_iface, hres,
1741                 ERROR_SUCCESS);
1742
1743     return hres;
1744 }
1745
1746 void channelbsc_set_channel(nsChannelBSC *This, nsChannel *channel, nsIStreamListener *listener, nsISupports *context)
1747 {
1748     nsIChannel_AddRef(&channel->nsIHttpChannel_iface);
1749     This->nschannel = channel;
1750
1751     nsIStreamListener_AddRef(listener);
1752     This->nslistener = listener;
1753
1754     if(context) {
1755         nsISupports_AddRef(context);
1756         This->nscontext = context;
1757     }
1758
1759     if(This->bsc.headers) {
1760         HRESULT hres;
1761
1762         hres = parse_headers(This->bsc.headers, &channel->request_headers);
1763         heap_free(This->bsc.headers);
1764         This->bsc.headers = NULL;
1765         if(FAILED(hres))
1766             WARN("parse_headers failed: %08x\n", hres);
1767     }
1768 }
1769
1770 typedef struct {
1771     task_t header;
1772     HTMLOuterWindow *window;
1773     IUri *uri;
1774 } navigate_javascript_task_t;
1775
1776 static void navigate_javascript_proc(task_t *_task)
1777 {
1778     navigate_javascript_task_t *task = (navigate_javascript_task_t*)_task;
1779     HTMLOuterWindow *window = task->window;
1780     VARIANT v;
1781     BSTR code;
1782     HRESULT hres;
1783
1784     static const WCHAR jscriptW[] = {'j','s','c','r','i','p','t',0};
1785
1786     task->window->readystate = READYSTATE_COMPLETE;
1787
1788     hres = IUri_GetPath(task->uri, &code);
1789     if(FAILED(hres))
1790         return;
1791
1792     hres = UrlUnescapeW(code, NULL, NULL, URL_UNESCAPE_INPLACE);
1793     if(FAILED(hres)) {
1794         SysFreeString(code);
1795         return;
1796     }
1797
1798     set_download_state(window->doc_obj, 1);
1799
1800     V_VT(&v) = VT_EMPTY;
1801     hres = exec_script(window->base.inner_window, code, jscriptW, &v);
1802     SysFreeString(code);
1803     if(SUCCEEDED(hres) && V_VT(&v) != VT_EMPTY) {
1804         FIXME("javascirpt URL returned %s\n", debugstr_variant(&v));
1805         VariantClear(&v);
1806     }
1807
1808     if(window->doc_obj->view_sink)
1809         IAdviseSink_OnViewChange(window->doc_obj->view_sink, DVASPECT_CONTENT, -1);
1810
1811     set_download_state(window->doc_obj, 0);
1812 }
1813
1814 static void navigate_javascript_task_destr(task_t *_task)
1815 {
1816     navigate_javascript_task_t *task = (navigate_javascript_task_t*)_task;
1817
1818     IUri_Release(task->uri);
1819     heap_free(task);
1820 }
1821
1822 typedef struct {
1823     task_t header;
1824     HTMLOuterWindow *window;
1825     nsChannelBSC *bscallback;
1826     IMoniker *mon;
1827 } navigate_task_t;
1828
1829 static void navigate_proc(task_t *_task)
1830 {
1831     navigate_task_t *task = (navigate_task_t*)_task;
1832     HRESULT hres;
1833
1834     hres = set_moniker(&task->window->doc_obj->basedoc, task->mon, NULL, task->bscallback, TRUE);
1835     if(SUCCEEDED(hres)) {
1836         set_current_mon(task->window, task->bscallback->bsc.mon);
1837         start_binding(task->window->pending_window, &task->bscallback->bsc, NULL);
1838     }
1839 }
1840
1841 static void navigate_task_destr(task_t *_task)
1842 {
1843     navigate_task_t *task = (navigate_task_t*)_task;
1844
1845     IBindStatusCallback_Release(&task->bscallback->bsc.IBindStatusCallback_iface);
1846     IMoniker_Release(task->mon);
1847     heap_free(task);
1848 }
1849
1850 static HRESULT navigate_fragment(HTMLOuterWindow *window, IUri *uri)
1851 {
1852     nsIDOMLocation *nslocation;
1853     nsAString nsfrag_str;
1854     BSTR frag;
1855     nsresult nsres;
1856     HRESULT hres;
1857
1858     set_current_uri(window, uri);
1859
1860     nsres = nsIDOMWindow_GetLocation(window->nswindow, &nslocation);
1861     if(FAILED(nsres) || !nslocation)
1862         return E_FAIL;
1863
1864     hres = IUri_GetFragment(uri, &frag);
1865     if(FAILED(hres)) {
1866         nsIDOMLocation_Release(nslocation);
1867         return hres;
1868     }
1869
1870     nsAString_InitDepend(&nsfrag_str, frag);
1871     nsres = nsIDOMLocation_SetHash(nslocation, &nsfrag_str);
1872     nsAString_Finish(&nsfrag_str);
1873     nsIDOMLocation_Release(nslocation);
1874     SysFreeString(frag);
1875     if(NS_FAILED(nsres)) {
1876         ERR("SetHash failed: %08x\n", nsres);
1877         return E_FAIL;
1878     }
1879
1880     if(window->doc_obj->doc_object_service) {
1881         IDocObjectService_FireNavigateComplete2(window->doc_obj->doc_object_service, &window->base.IHTMLWindow2_iface, 0x10);
1882         IDocObjectService_FireDocumentComplete(window->doc_obj->doc_object_service, &window->base.IHTMLWindow2_iface, 0);
1883
1884     }
1885
1886     return S_OK;
1887 }
1888
1889 HRESULT super_navigate(HTMLOuterWindow *window, IUri *uri, const WCHAR *headers, BYTE *post_data, DWORD post_data_size)
1890 {
1891     nsChannelBSC *bsc;
1892     IMoniker *mon;
1893     DWORD scheme;
1894     HRESULT hres;
1895
1896     if(window->doc_obj->client) {
1897         IOleCommandTarget *cmdtrg;
1898
1899         hres = IOleClientSite_QueryInterface(window->doc_obj->client, &IID_IOleCommandTarget, (void**)&cmdtrg);
1900         if(SUCCEEDED(hres)) {
1901             VARIANT in, out;
1902             BSTR url_str;
1903
1904             hres = IUri_GetDisplayUri(uri, &url_str);
1905             if(SUCCEEDED(hres)) {
1906                 V_VT(&in) = VT_BSTR;
1907                 V_BSTR(&in) = url_str;
1908                 V_VT(&out) = VT_BOOL;
1909                 V_BOOL(&out) = VARIANT_TRUE;
1910                 hres = IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 67, 0, &in, &out);
1911                 IOleCommandTarget_Release(cmdtrg);
1912                 if(SUCCEEDED(hres))
1913                     VariantClear(&out);
1914                 SysFreeString(url_str);
1915             }
1916         }
1917     }
1918
1919     if(window->uri && !post_data_size && compare_ignoring_frag(window->uri, uri)) {
1920         TRACE("fragment navigate\n");
1921         return navigate_fragment(window, uri);
1922     }
1923
1924     hres = CreateURLMonikerEx2(NULL, uri, &mon, URL_MK_UNIFORM);
1925     if(FAILED(hres))
1926         return hres;
1927
1928     /* FIXME: Why not set_ready_state? */
1929     window->readystate = READYSTATE_UNINITIALIZED;
1930
1931     hres = create_channelbsc(mon, headers, post_data, post_data_size, TRUE, &bsc);
1932     if(FAILED(hres)) {
1933         IMoniker_Release(mon);
1934         return hres;
1935     }
1936
1937     prepare_for_binding(&window->doc_obj->basedoc, mon, TRUE);
1938
1939     hres = IUri_GetScheme(uri, &scheme);
1940     if(SUCCEEDED(hres) && scheme != URL_SCHEME_JAVASCRIPT) {
1941         navigate_task_t *task;
1942
1943         task = heap_alloc(sizeof(*task));
1944         if(!task) {
1945             IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
1946             IMoniker_Release(mon);
1947             return E_OUTOFMEMORY;
1948         }
1949
1950         /* Silently and repeated when real loading starts? */
1951         window->readystate = READYSTATE_LOADING;
1952         call_docview_84(window->doc_obj);
1953
1954         task->window = window;
1955         task->bscallback = bsc;
1956         task->mon = mon;
1957         push_task(&task->header, navigate_proc, navigate_task_destr, window->task_magic);
1958
1959     }else {
1960         navigate_javascript_task_t *task;
1961
1962         IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
1963         IMoniker_Release(mon);
1964
1965         task = heap_alloc(sizeof(*task));
1966         if(!task)
1967             return E_OUTOFMEMORY;
1968
1969         /* Why silently? */
1970         window->readystate = READYSTATE_COMPLETE;
1971         call_docview_84(window->doc_obj);
1972
1973         IUri_AddRef(uri);
1974         task->window = window;
1975         task->uri = uri;
1976         push_task(&task->header, navigate_javascript_proc, navigate_javascript_task_destr, window->task_magic);
1977     }
1978
1979     return S_OK;
1980 }
1981
1982 HRESULT navigate_new_window(HTMLOuterWindow *window, IUri *uri, const WCHAR *name, IHTMLWindow2 **ret)
1983 {
1984     IWebBrowser2 *web_browser;
1985     IHTMLWindow2 *new_window;
1986     IBindCtx *bind_ctx;
1987     nsChannelBSC *bsc;
1988     HRESULT hres;
1989
1990     hres = create_channelbsc(NULL, NULL, NULL, 0, FALSE, &bsc);
1991     if(FAILED(hres))
1992         return hres;
1993
1994     hres = CreateAsyncBindCtx(0, &bsc->bsc.IBindStatusCallback_iface, NULL, &bind_ctx);
1995     if(FAILED(hres)) {
1996         IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
1997         return hres;
1998     }
1999
2000     hres = CoCreateInstance(&CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER,
2001             &IID_IWebBrowser2, (void**)&web_browser);
2002     if(SUCCEEDED(hres)) {
2003         ITargetFramePriv2 *target_frame_priv;
2004
2005         hres = IWebBrowser_QueryInterface(web_browser, &IID_ITargetFramePriv2, (void**)&target_frame_priv);
2006         if(SUCCEEDED(hres)) {
2007             hres = ITargetFramePriv2_AggregatedNavigation2(target_frame_priv,
2008                     HLNF_DISABLEWINDOWRESTRICTIONS|HLNF_OPENINNEWWINDOW, bind_ctx, &bsc->bsc.IBindStatusCallback_iface,
2009                     name, uri, emptyW);
2010             ITargetFramePriv2_Release(target_frame_priv);
2011
2012             if(SUCCEEDED(hres))
2013                 hres = do_query_service((IUnknown*)web_browser, &SID_SHTMLWindow, &IID_IHTMLWindow2, (void**)&new_window);
2014         }
2015         if(FAILED(hres)) {
2016             IWebBrowser2_Quit(web_browser);
2017             IWebBrowser2_Release(web_browser);
2018         }
2019     }else {
2020         WARN("Could not create InternetExplorer instance: %08x\n", hres);
2021     }
2022
2023     IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
2024     IBindCtx_Release(bind_ctx);
2025     if(FAILED(hres))
2026         return hres;
2027
2028     IWebBrowser2_put_Visible(web_browser, VARIANT_TRUE);
2029     IWebBrowser2_Release(web_browser);
2030
2031     if(ret)
2032         *ret = new_window;
2033     else
2034         IHTMLWindow2_Release(new_window);
2035     return S_OK;
2036 }
2037
2038 HRESULT hlink_frame_navigate(HTMLDocument *doc, LPCWSTR url, nsChannel *nschannel, DWORD hlnf, BOOL *cancel)
2039 {
2040     IHlinkFrame *hlink_frame;
2041     nsChannelBSC *callback;
2042     IBindCtx *bindctx;
2043     IMoniker *mon;
2044     IHlink *hlink;
2045     HRESULT hres;
2046
2047     *cancel = FALSE;
2048
2049     hres = do_query_service((IUnknown*)doc->doc_obj->client, &IID_IHlinkFrame, &IID_IHlinkFrame,
2050             (void**)&hlink_frame);
2051     if(FAILED(hres))
2052         return S_OK;
2053
2054     hres = create_channelbsc(NULL, NULL, NULL, 0, FALSE, &callback);
2055     if(FAILED(hres)) {
2056         IHlinkFrame_Release(hlink_frame);
2057         return hres;
2058     }
2059
2060     if(nschannel)
2061         read_post_data_stream(callback, nschannel);
2062
2063     hres = CreateAsyncBindCtx(0, &callback->bsc.IBindStatusCallback_iface, NULL, &bindctx);
2064     if(SUCCEEDED(hres))
2065         hres = CoCreateInstance(&CLSID_StdHlink, NULL, CLSCTX_INPROC_SERVER,
2066                 &IID_IHlink, (LPVOID*)&hlink);
2067
2068     if(SUCCEEDED(hres))
2069         hres = CreateURLMoniker(NULL, url, &mon);
2070
2071     if(SUCCEEDED(hres)) {
2072         IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET, mon, NULL);
2073
2074         if(hlnf & HLNF_OPENINNEWWINDOW) {
2075             static const WCHAR wszBlank[] = {'_','b','l','a','n','k',0};
2076             IHlink_SetTargetFrameName(hlink, wszBlank); /* FIXME */
2077         }
2078
2079         hres = IHlinkFrame_Navigate(hlink_frame, hlnf, bindctx,
2080                 &callback->bsc.IBindStatusCallback_iface, hlink);
2081         IMoniker_Release(mon);
2082         *cancel = hres == S_OK;
2083         hres = S_OK;
2084     }
2085
2086     IHlinkFrame_Release(hlink_frame);
2087     IBindCtx_Release(bindctx);
2088     IBindStatusCallback_Release(&callback->bsc.IBindStatusCallback_iface);
2089     return hres;
2090 }
2091
2092 HRESULT navigate_url(HTMLOuterWindow *window, const WCHAR *new_url, const WCHAR *base_url)
2093 {
2094     WCHAR url[INTERNET_MAX_URL_LENGTH];
2095     nsWineURI *uri;
2096     HRESULT hres;
2097
2098     if(!new_url) {
2099         *url = 0;
2100     }else if(base_url) {
2101         DWORD len = 0;
2102
2103         hres = CoInternetCombineUrl(base_url, new_url, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO,
2104                 url, sizeof(url)/sizeof(WCHAR), &len, 0);
2105         if(FAILED(hres))
2106             return hres;
2107     }else {
2108         strcpyW(url, new_url);
2109     }
2110
2111     if(window->doc_obj && window->doc_obj->hostui) {
2112         OLECHAR *translated_url = NULL;
2113
2114         hres = IDocHostUIHandler_TranslateUrl(window->doc_obj->hostui, 0, url,
2115                 &translated_url);
2116         if(hres == S_OK) {
2117             TRACE("%08x %s -> %s\n", hres, debugstr_w(url), debugstr_w(translated_url));
2118             strcpyW(url, translated_url);
2119             CoTaskMemFree(translated_url);
2120         }
2121     }
2122
2123     if(window->doc_obj && window->doc_obj->is_webbrowser && window == window->doc_obj->basedoc.window) {
2124         BOOL cancel = FALSE;
2125         IUri *uri;
2126
2127         hres = IDocObjectService_FireBeforeNavigate2(window->doc_obj->doc_object_service, NULL, url, 0x40,
2128                 NULL, NULL, 0, NULL, TRUE, &cancel);
2129         if(SUCCEEDED(hres) && cancel) {
2130             TRACE("Navigation canceled\n");
2131             return S_OK;
2132         }
2133
2134         hres = CreateUri(url, 0, 0, &uri);
2135         if(FAILED(hres))
2136             return hres;
2137
2138         hres = super_navigate(window, uri, NULL, NULL, 0);
2139         IUri_Release(uri);
2140         return hres;
2141     }
2142
2143     if(window->doc_obj && window == window->doc_obj->basedoc.window) {
2144         BOOL cancel;
2145
2146         hres = hlink_frame_navigate(&window->base.inner_window->doc->basedoc, url, NULL, 0, &cancel);
2147         if(FAILED(hres))
2148             return hres;
2149
2150         if(cancel) {
2151             TRACE("Navigation handled by hlink frame\n");
2152             return S_OK;
2153         }
2154     }
2155
2156     hres = create_doc_uri(window, url, &uri);
2157     if(FAILED(hres))
2158         return hres;
2159
2160     hres = load_nsuri(window, uri, NULL, LOAD_FLAGS_NONE);
2161     nsISupports_Release((nsISupports*)uri);
2162     return hres;
2163 }