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