Release 1.5.29.
[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, UINT64 *_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, UINT32 aCount,
149                                          UINT32 *_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*,UINT32,UINT32,UINT32*),
172         void *aClousure, UINT32 aCount, UINT32 *_retval)
173 {
174     nsProtocolStream *This = impl_from_nsIInputStream(iface);
175     UINT32 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         hres = RegisterBindStatusCallback(bctx, &bscallback->IBindStatusCallback_iface, NULL, 0);
804         if(SUCCEEDED(hres))
805             IBindCtx_AddRef(bctx);
806     }else {
807         hres = CreateAsyncBindCtx(0, &bscallback->IBindStatusCallback_iface, NULL, &bctx);
808     }
809
810     if(FAILED(hres)) {
811         bscallback->vtbl->stop_binding(bscallback, hres);
812         return hres;
813     }
814
815     hres = IMoniker_BindToStorage(bscallback->mon, bctx, NULL, &IID_IStream, (void**)&str);
816     IBindCtx_Release(bctx);
817     if(FAILED(hres)) {
818         WARN("BindToStorage failed: %08x\n", hres);
819         bscallback->vtbl->stop_binding(bscallback, hres);
820         return hres;
821     }
822
823     if(str)
824         IStream_Release(str);
825
826     IMoniker_Release(bscallback->mon);
827     bscallback->mon = NULL;
828
829     return S_OK;
830 }
831
832 typedef struct {
833     BSCallback bsc;
834
835     DWORD size;
836     char *buf;
837     HRESULT hres;
838 } BufferBSC;
839
840 static inline BufferBSC *BufferBSC_from_BSCallback(BSCallback *iface)
841 {
842     return CONTAINING_RECORD(iface, BufferBSC, bsc);
843 }
844
845 static void BufferBSC_destroy(BSCallback *bsc)
846 {
847     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
848
849     heap_free(This->buf);
850     heap_free(This);
851 }
852
853 static HRESULT BufferBSC_init_bindinfo(BSCallback *bsc)
854 {
855     return S_OK;
856 }
857
858 static HRESULT BufferBSC_start_binding(BSCallback *bsc)
859 {
860     return S_OK;
861 }
862
863 static HRESULT BufferBSC_stop_binding(BSCallback *bsc, HRESULT result)
864 {
865     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
866
867     This->hres = result;
868
869     if(FAILED(result)) {
870         heap_free(This->buf);
871         This->buf = NULL;
872         This->size = 0;
873     }
874
875     return S_OK;
876 }
877
878 static HRESULT BufferBSC_read_data(BSCallback *bsc, IStream *stream)
879 {
880     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
881     DWORD readed;
882     HRESULT hres;
883
884     if(!This->buf) {
885         This->buf = heap_alloc(128);
886         if(!This->buf)
887             return E_OUTOFMEMORY;
888         This->size = 128;
889     }
890
891     do {
892         if(This->bsc.readed >= This->size) {
893             This->size <<= 1;
894             This->buf = heap_realloc(This->buf, This->size);
895         }
896
897         hres = read_stream(&This->bsc, stream, This->buf+This->bsc.readed, This->size-This->bsc.readed, &readed);
898     }while(hres == S_OK);
899
900     return S_OK;
901 }
902
903 static HRESULT BufferBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
904 {
905     return S_OK;
906 }
907
908 static HRESULT BufferBSC_on_response(BSCallback *bsc, DWORD response_code,
909         LPCWSTR response_headers)
910 {
911     return S_OK;
912 }
913
914 static HRESULT BufferBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
915 {
916     return S_FALSE;
917 }
918
919 static const BSCallbackVtbl BufferBSCVtbl = {
920     BufferBSC_destroy,
921     BufferBSC_init_bindinfo,
922     BufferBSC_start_binding,
923     BufferBSC_stop_binding,
924     BufferBSC_read_data,
925     BufferBSC_on_progress,
926     BufferBSC_on_response,
927     BufferBSC_beginning_transaction
928 };
929
930
931 HRESULT bind_mon_to_wstr(HTMLInnerWindow *window, IMoniker *mon, WCHAR **ret)
932 {
933     BufferBSC *bsc;
934     int cp = CP_ACP;
935     WCHAR *text;
936     HRESULT hres;
937
938     bsc = heap_alloc_zero(sizeof(*bsc));
939     if(!bsc)
940         return E_OUTOFMEMORY;
941
942     init_bscallback(&bsc->bsc, &BufferBSCVtbl, mon, 0);
943     bsc->hres = E_FAIL;
944
945     hres = start_binding(window, &bsc->bsc, NULL);
946     if(SUCCEEDED(hres))
947         hres = bsc->hres;
948     if(FAILED(hres)) {
949         IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
950         return hres;
951     }
952
953     if(!bsc->bsc.readed) {
954         *ret = NULL;
955         return S_OK;
956     }
957
958     switch(bsc->bsc.bom) {
959     case BOM_UTF16:
960         if(bsc->bsc.readed % sizeof(WCHAR)) {
961             FIXME("The buffer is not a valid utf16 string\n");
962             hres = E_FAIL;
963             break;
964         }
965
966         text = heap_alloc(bsc->bsc.readed+sizeof(WCHAR));
967         if(!text) {
968             hres = E_OUTOFMEMORY;
969             break;
970         }
971
972         memcpy(text, bsc->buf, bsc->bsc.readed);
973         text[bsc->bsc.readed/sizeof(WCHAR)] = 0;
974         break;
975
976     case BOM_UTF8:
977         cp = CP_UTF8;
978         /* fallthrough */
979     default: {
980         DWORD len;
981
982         len = MultiByteToWideChar(cp, 0, bsc->buf, bsc->bsc.readed, NULL, 0);
983         text = heap_alloc((len+1)*sizeof(WCHAR));
984         if(!text) {
985             hres = E_OUTOFMEMORY;
986             break;
987         }
988
989         MultiByteToWideChar(CP_ACP, 0, bsc->buf, bsc->bsc.readed, text, len);
990         text[len] = 0;
991     }
992     }
993
994     IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
995     if(FAILED(hres))
996         return hres;
997
998     *ret = text;
999     return S_OK;
1000 }
1001
1002 static HRESULT read_post_data_stream(nsChannelBSC *This, nsChannel *nschannel)
1003 {
1004     UINT64 available = 0;
1005     UINT32 data_len = 0;
1006     char *data, *post_data;
1007     nsresult nsres;
1008     HRESULT hres = S_OK;
1009
1010     if(!nschannel->post_data_stream)
1011         return S_OK;
1012
1013     nsres =  nsIInputStream_Available(nschannel->post_data_stream, &available);
1014     if(NS_FAILED(nsres))
1015         return E_FAIL;
1016
1017     post_data = data = GlobalAlloc(0, available);
1018     if(!data)
1019         return E_OUTOFMEMORY;
1020
1021     nsres = nsIInputStream_Read(nschannel->post_data_stream, data, available, &data_len);
1022     if(NS_FAILED(nsres)) {
1023         GlobalFree(data);
1024         return E_FAIL;
1025     }
1026
1027     if(nschannel->post_data_contains_headers) {
1028         if(data_len >= 2 && data[0] == '\r' && data[1] == '\n') {
1029             post_data = data+2;
1030             data_len -= 2;
1031         }else {
1032             WCHAR *headers;
1033             DWORD size;
1034             char *ptr;
1035
1036             post_data += data_len;
1037             for(ptr = data; ptr+4 < data+data_len; ptr++) {
1038                 if(!memcmp(ptr, "\r\n\r\n", 4)) {
1039                     post_data = ptr+4;
1040                     break;
1041                 }
1042             }
1043
1044             data_len -= post_data-data;
1045
1046             size = MultiByteToWideChar(CP_ACP, 0, data, post_data-data, NULL, 0);
1047             headers = heap_alloc((size+1)*sizeof(WCHAR));
1048             if(headers) {
1049                 MultiByteToWideChar(CP_ACP, 0, data, post_data-data, headers, size);
1050                 headers[size] = 0;
1051                 hres = parse_headers(headers , &nschannel->request_headers);
1052                 if(SUCCEEDED(hres))
1053                     This->bsc.headers = headers;
1054                 else
1055                     heap_free(headers);
1056             }else {
1057                 hres = E_OUTOFMEMORY;
1058             }
1059         }
1060     }
1061
1062     if(FAILED(hres)) {
1063         GlobalFree(data);
1064         return hres;
1065     }
1066
1067     if(!data_len) {
1068         GlobalFree(data);
1069         post_data = NULL;
1070     }else if(post_data != data) {
1071         char *new_data;
1072
1073         new_data = GlobalAlloc(0, data_len);
1074         if(new_data)
1075             memcpy(new_data, post_data, data_len);
1076         GlobalFree(data);
1077         if(!new_data)
1078             return E_OUTOFMEMORY;
1079         post_data = new_data;
1080     }
1081
1082     This->bsc.post_data = post_data;
1083     This->bsc.post_data_len = data_len;
1084     TRACE("post_data = %s\n", debugstr_a(This->bsc.post_data));
1085     return S_OK;
1086 }
1087
1088 static HRESULT on_start_nsrequest(nsChannelBSC *This)
1089 {
1090     nsresult nsres;
1091
1092     /* FIXME: it's needed for http connections from BindToObject. */
1093     if(!This->nschannel->response_status)
1094         This->nschannel->response_status = 200;
1095
1096     nsres = nsIStreamListener_OnStartRequest(This->nslistener,
1097             (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext);
1098     if(NS_FAILED(nsres)) {
1099         FIXME("OnStartRequest failed: %08x\n", nsres);
1100         return E_FAIL;
1101     }
1102
1103     if(This->is_doc_channel) {
1104         update_window_doc(This->bsc.window);
1105         if(This->bsc.window->base.outer_window->readystate != READYSTATE_LOADING)
1106             set_ready_state(This->bsc.window->base.outer_window, READYSTATE_LOADING);
1107     }
1108
1109     return S_OK;
1110 }
1111
1112 static void on_stop_nsrequest(nsChannelBSC *This, HRESULT result)
1113 {
1114     nsresult nsres, request_result;
1115
1116     switch(result) {
1117     case S_OK:
1118         request_result = NS_OK;
1119         break;
1120     case E_ABORT:
1121         request_result = NS_BINDING_ABORTED;
1122         break;
1123     default:
1124         request_result = NS_ERROR_FAILURE;
1125     }
1126
1127     if(This->nslistener) {
1128         nsres = nsIStreamListener_OnStopRequest(This->nslistener,
1129                  (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext,
1130                  request_result);
1131         if(NS_FAILED(nsres))
1132             WARN("OnStopRequest failed: %08x\n", nsres);
1133     }
1134
1135     if(This->nschannel->load_group) {
1136         nsres = nsILoadGroup_RemoveRequest(This->nschannel->load_group,
1137                 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, NULL, request_result);
1138         if(NS_FAILED(nsres))
1139             ERR("RemoveRequest failed: %08x\n", nsres);
1140     }
1141 }
1142
1143 static HRESULT read_stream_data(nsChannelBSC *This, IStream *stream)
1144 {
1145     DWORD read;
1146     nsresult nsres;
1147     HRESULT hres;
1148
1149     if(!This->response_processed) {
1150         IWinInetHttpInfo *wininet_info;
1151
1152         This->response_processed = TRUE;
1153         if(This->bsc.binding) {
1154             hres = IBinding_QueryInterface(This->bsc.binding, &IID_IWinInetHttpInfo, (void**)&wininet_info);
1155             if(SUCCEEDED(hres)) {
1156                 query_http_info(This, wininet_info);
1157                 IWinInetHttpInfo_Release(wininet_info);
1158             }
1159         }
1160     }
1161
1162     if(!This->nslistener) {
1163         BYTE buf[1024];
1164
1165         do {
1166             hres = read_stream(&This->bsc, stream, buf, sizeof(buf), &read);
1167         }while(hres == S_OK && read);
1168
1169         return S_OK;
1170     }
1171
1172     if(!This->nsstream) {
1173         This->nsstream = create_nsprotocol_stream();
1174         if(!This->nsstream)
1175             return E_OUTOFMEMORY;
1176     }
1177
1178     do {
1179         BOOL first_read = !This->bsc.readed;
1180
1181         hres = read_stream(&This->bsc, stream, This->nsstream->buf+This->nsstream->buf_size,
1182                 sizeof(This->nsstream->buf)-This->nsstream->buf_size, &read);
1183         if(!read)
1184             break;
1185
1186         This->nsstream->buf_size += read;
1187
1188         if(first_read) {
1189             switch(This->bsc.bom) {
1190             case BOM_UTF8:
1191                 This->nschannel->charset = heap_strdupA(UTF8_STR);
1192                 break;
1193             case BOM_UTF16:
1194                 This->nschannel->charset = heap_strdupA(UTF16_STR);
1195             }
1196
1197             if(!This->nschannel->content_type) {
1198                 WCHAR *mime;
1199
1200                 hres = FindMimeFromData(NULL, NULL, This->nsstream->buf, This->nsstream->buf_size,
1201                         This->is_doc_channel ? text_htmlW : NULL, 0, &mime, 0);
1202                 if(FAILED(hres))
1203                     return hres;
1204
1205                 TRACE("Found MIME %s\n", debugstr_w(mime));
1206
1207                 This->nschannel->content_type = heap_strdupWtoA(mime);
1208                 CoTaskMemFree(mime);
1209                 if(!This->nschannel->content_type)
1210                     return E_OUTOFMEMORY;
1211             }
1212
1213             on_start_nsrequest(This);
1214         }
1215
1216         nsres = nsIStreamListener_OnDataAvailable(This->nslistener,
1217                 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext,
1218                 &This->nsstream->nsIInputStream_iface, This->bsc.readed-This->nsstream->buf_size,
1219                 This->nsstream->buf_size);
1220         if(NS_FAILED(nsres))
1221             ERR("OnDataAvailable failed: %08x\n", nsres);
1222
1223         if(This->nsstream->buf_size == sizeof(This->nsstream->buf)) {
1224             ERR("buffer is full\n");
1225             break;
1226         }
1227     }while(hres == S_OK);
1228
1229     return S_OK;
1230 }
1231
1232 typedef struct {
1233     nsIAsyncVerifyRedirectCallback nsIAsyncVerifyRedirectCallback_iface;
1234
1235     LONG ref;
1236
1237     nsChannel *nschannel;
1238     nsChannelBSC *bsc;
1239 } nsRedirectCallback;
1240
1241 static nsRedirectCallback *impl_from_nsIAsyncVerifyRedirectCallback(nsIAsyncVerifyRedirectCallback *iface)
1242 {
1243     return CONTAINING_RECORD(iface, nsRedirectCallback, nsIAsyncVerifyRedirectCallback_iface);
1244 }
1245
1246 static nsresult NSAPI nsAsyncVerifyRedirectCallback_QueryInterface(nsIAsyncVerifyRedirectCallback *iface,
1247         nsIIDRef riid, void **result)
1248 {
1249     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1250
1251     if(IsEqualGUID(&IID_nsISupports, riid)) {
1252         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
1253         *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1254     }else if(IsEqualGUID(&IID_nsIAsyncVerifyRedirectCallback, riid)) {
1255         TRACE("(%p)->(IID_nsIAsyncVerifyRedirectCallback %p)\n", This, result);
1256         *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1257     }else {
1258         *result = NULL;
1259         WARN("unimplemented iface %s\n", debugstr_guid(riid));
1260         return NS_NOINTERFACE;
1261     }
1262
1263     nsISupports_AddRef((nsISupports*)*result);
1264     return NS_OK;
1265 }
1266
1267 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_AddRef(nsIAsyncVerifyRedirectCallback *iface)
1268 {
1269     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1270     LONG ref = InterlockedIncrement(&This->ref);
1271
1272     TRACE("(%p) ref=%d\n", This, ref);
1273
1274     return ref;
1275 }
1276
1277 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_Release(nsIAsyncVerifyRedirectCallback *iface)
1278 {
1279     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1280     LONG ref = InterlockedDecrement(&This->ref);
1281
1282     TRACE("(%p) ref=%d\n", This, ref);
1283
1284     if(!ref) {
1285         IBindStatusCallback_Release(&This->bsc->bsc.IBindStatusCallback_iface);
1286         nsIHttpChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1287         heap_free(This);
1288     }
1289
1290     return ref;
1291 }
1292
1293 static nsresult NSAPI nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect(nsIAsyncVerifyRedirectCallback *iface, nsresult result)
1294 {
1295     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1296     nsChannel *old_nschannel;
1297     nsresult nsres;
1298
1299     TRACE("(%p)->(%08x)\n", This, result);
1300
1301     old_nschannel = This->bsc->nschannel;
1302     nsIHttpChannel_AddRef(&This->nschannel->nsIHttpChannel_iface);
1303     This->bsc->nschannel = This->nschannel;
1304
1305     if(This->nschannel->load_group) {
1306         nsres = nsILoadGroup_AddRequest(This->nschannel->load_group, (nsIRequest*)&This->nschannel->nsIHttpChannel_iface,
1307                 NULL);
1308         if(NS_FAILED(nsres))
1309             ERR("AddRequest failed: %08x\n", nsres);
1310     }
1311
1312     if(This->bsc->is_doc_channel) {
1313         IUri *uri = nsuri_get_uri(This->nschannel->uri);
1314
1315         if(uri) {
1316             set_current_uri(This->bsc->bsc.window->base.outer_window, uri);
1317             IUri_Release(uri);
1318         }else {
1319             WARN("Could not get IUri from nsWineURI\n");
1320         }
1321     }
1322
1323     if(old_nschannel) {
1324         if(old_nschannel->load_group) {
1325             nsres = nsILoadGroup_RemoveRequest(old_nschannel->load_group,
1326                     (nsIRequest*)&old_nschannel->nsIHttpChannel_iface, NULL, NS_OK);
1327             if(NS_FAILED(nsres))
1328                 ERR("RemoveRequest failed: %08x\n", nsres);
1329         }
1330         nsIHttpChannel_Release(&old_nschannel->nsIHttpChannel_iface);
1331     }
1332
1333     return NS_OK;
1334 }
1335
1336 static const nsIAsyncVerifyRedirectCallbackVtbl nsAsyncVerifyRedirectCallbackVtbl = {
1337     nsAsyncVerifyRedirectCallback_QueryInterface,
1338     nsAsyncVerifyRedirectCallback_AddRef,
1339     nsAsyncVerifyRedirectCallback_Release,
1340     nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect
1341 };
1342
1343 static HRESULT create_redirect_callback(nsChannel *nschannel, nsChannelBSC *bsc, nsRedirectCallback **ret)
1344 {
1345     nsRedirectCallback *callback;
1346
1347     callback = heap_alloc(sizeof(*callback));
1348     if(!callback)
1349         return E_OUTOFMEMORY;
1350
1351     callback->nsIAsyncVerifyRedirectCallback_iface.lpVtbl = &nsAsyncVerifyRedirectCallbackVtbl;
1352     callback->ref = 1;
1353
1354     nsIHttpChannel_AddRef(&nschannel->nsIHttpChannel_iface);
1355     callback->nschannel = nschannel;
1356
1357     IBindStatusCallback_AddRef(&bsc->bsc.IBindStatusCallback_iface);
1358     callback->bsc = bsc;
1359
1360     *ret = callback;
1361     return S_OK;
1362 }
1363
1364 static inline nsChannelBSC *nsChannelBSC_from_BSCallback(BSCallback *iface)
1365 {
1366     return CONTAINING_RECORD(iface, nsChannelBSC, bsc);
1367 }
1368
1369 static void nsChannelBSC_destroy(BSCallback *bsc)
1370 {
1371     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1372
1373     if(This->nschannel)
1374         nsIHttpChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1375     if(This->nslistener)
1376         nsIStreamListener_Release(This->nslistener);
1377     if(This->nscontext)
1378         nsISupports_Release(This->nscontext);
1379     if(This->nsstream)
1380         nsIInputStream_Release(&This->nsstream->nsIInputStream_iface);
1381     heap_free(This);
1382 }
1383
1384 static HRESULT nsChannelBSC_start_binding(BSCallback *bsc)
1385 {
1386     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1387
1388     if(This->is_doc_channel)
1389         This->bsc.window->base.outer_window->base.inner_window->doc->skip_mutation_notif = FALSE;
1390
1391     return S_OK;
1392 }
1393
1394 static HRESULT nsChannelBSC_init_bindinfo(BSCallback *bsc)
1395 {
1396     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1397     HRESULT hres;
1398
1399     if(This->nschannel && This->nschannel->post_data_stream) {
1400         hres = read_post_data_stream(This, This->nschannel);
1401         if(FAILED(hres))
1402             return hres;
1403     }
1404
1405     return S_OK;
1406 }
1407
1408 typedef struct {
1409     task_t header;
1410     nsChannelBSC *bsc;
1411 } stop_request_task_t;
1412
1413 static void stop_request_proc(task_t *_task)
1414 {
1415     stop_request_task_t *task = (stop_request_task_t*)_task;
1416
1417     TRACE("(%p)\n", task->bsc);
1418
1419     list_remove(&task->bsc->bsc.entry);
1420     list_init(&task->bsc->bsc.entry);
1421     on_stop_nsrequest(task->bsc, S_OK);
1422 }
1423
1424 static void stop_request_task_destr(task_t *_task)
1425 {
1426     stop_request_task_t *task = (stop_request_task_t*)_task;
1427
1428     IBindStatusCallback_Release(&task->bsc->bsc.IBindStatusCallback_iface);
1429     heap_free(task);
1430 }
1431
1432 static HRESULT async_stop_request(nsChannelBSC *This)
1433 {
1434     stop_request_task_t *task;
1435
1436     if(!This->bsc.readed) {
1437         TRACE("No data read, calling OnStartRequest\n");
1438         on_start_nsrequest(This);
1439     }
1440
1441     task = heap_alloc(sizeof(*task));
1442     if(!task)
1443         return E_OUTOFMEMORY;
1444
1445     IBindStatusCallback_AddRef(&This->bsc.IBindStatusCallback_iface);
1446     task->bsc = This;
1447
1448     return push_task(&task->header, stop_request_proc, stop_request_task_destr, This->bsc.window->task_magic);
1449 }
1450
1451 static void handle_navigation_error(nsChannelBSC *This, DWORD result)
1452 {
1453     HTMLOuterWindow *outer_window;
1454     HTMLDocumentObj *doc;
1455     BOOL is_error_url;
1456     SAFEARRAY *sa;
1457     SAFEARRAYBOUND bound;
1458     VARIANT var, varOut;
1459     LONG ind;
1460     BSTR unk;
1461     HRESULT hres;
1462
1463     if(!This->is_doc_channel || !This->bsc.window)
1464         return;
1465
1466     outer_window = This->bsc.window->base.outer_window;
1467
1468     doc = outer_window->doc_obj;
1469     if(!doc || !doc->doc_object_service || !doc->client)
1470         return;
1471
1472     hres = IDocObjectService_IsErrorUrl(doc->doc_object_service,
1473             outer_window->url, &is_error_url);
1474     if(FAILED(hres) || is_error_url)
1475         return;
1476
1477     if(!doc->client_cmdtrg)
1478         return;
1479
1480     bound.lLbound = 0;
1481     bound.cElements = 8;
1482     sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1483     if(!sa)
1484         return;
1485
1486     ind = 0;
1487     V_VT(&var) = VT_I4;
1488     V_I4(&var) = result;
1489     SafeArrayPutElement(sa, &ind, &var);
1490
1491     ind = 1;
1492     V_VT(&var) = VT_BSTR;
1493     V_BSTR(&var) = outer_window->url;
1494     SafeArrayPutElement(sa, &ind, &var);
1495
1496     ind = 3;
1497     V_VT(&var) = VT_UNKNOWN;
1498     V_UNKNOWN(&var) = (IUnknown*)&outer_window->base.IHTMLWindow2_iface;
1499     SafeArrayPutElement(sa, &ind, &var);
1500
1501     /* FIXME: what are the following fields for? */
1502     ind = 2;
1503     V_VT(&var) = VT_UNKNOWN;
1504     V_UNKNOWN(&var) = NULL;
1505     SafeArrayPutElement(sa, &ind, &var);
1506
1507     ind = 4;
1508     V_VT(&var) = VT_BOOL;
1509     V_BOOL(&var) = FALSE;
1510     SafeArrayPutElement(sa, &ind, &var);
1511
1512     ind = 5;
1513     V_VT(&var) = VT_BOOL;
1514     V_BOOL(&var) = FALSE;
1515     SafeArrayPutElement(sa, &ind, &var);
1516
1517     ind = 6;
1518     V_VT(&var) = VT_BSTR;
1519     unk = SysAllocString(NULL);
1520     V_BSTR(&var) = unk;
1521     SafeArrayPutElement(sa, &ind, &var);
1522
1523     ind = 7;
1524     V_VT(&var) = VT_UNKNOWN;
1525     V_UNKNOWN(&var) = NULL;
1526     SafeArrayPutElement(sa, &ind, &var);
1527
1528     V_VT(&var) = VT_ARRAY;
1529     V_ARRAY(&var) = sa;
1530     V_VT(&varOut) = VT_BOOL;
1531     V_BOOL(&varOut) = VARIANT_TRUE;
1532     IOleCommandTarget_Exec(doc->client_cmdtrg, &CGID_DocHostCmdPriv, 1, 0, &var, FAILED(hres)?NULL:&varOut);
1533
1534     SysFreeString(unk);
1535     SafeArrayDestroy(sa);
1536 }
1537
1538 static HRESULT nsChannelBSC_stop_binding(BSCallback *bsc, HRESULT result)
1539 {
1540     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1541
1542     if(result != E_ABORT) {
1543         if(FAILED(result))
1544             handle_navigation_error(This, result);
1545         else if(This->is_doc_channel) {
1546             result = async_stop_request(This);
1547             if(SUCCEEDED(result))
1548                 return S_OK;
1549         }
1550     }
1551
1552     on_stop_nsrequest(This, result);
1553     return S_OK;
1554 }
1555
1556 static HRESULT nsChannelBSC_read_data(BSCallback *bsc, IStream *stream)
1557 {
1558     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1559
1560     return read_stream_data(This, stream);
1561 }
1562
1563 static HRESULT handle_redirect(nsChannelBSC *This, const WCHAR *new_url)
1564 {
1565     nsRedirectCallback *callback;
1566     nsIChannelEventSink *sink;
1567     nsChannel *new_channel;
1568     nsresult nsres;
1569     HRESULT hres;
1570
1571     TRACE("(%p)->(%s)\n", This, debugstr_w(new_url));
1572
1573     if(!This->nschannel || !This->nschannel->notif_callback)
1574         return S_OK;
1575
1576     nsres = nsIInterfaceRequestor_GetInterface(This->nschannel->notif_callback, &IID_nsIChannelEventSink, (void**)&sink);
1577     if(NS_FAILED(nsres))
1578         return S_OK;
1579
1580     hres = create_redirect_nschannel(new_url, This->nschannel, &new_channel);
1581     if(SUCCEEDED(hres)) {
1582         TRACE("%p %p->%p\n", This, This->nschannel, new_channel);
1583
1584         hres = create_redirect_callback(new_channel, This, &callback);
1585         nsIHttpChannel_Release(&new_channel->nsIHttpChannel_iface);
1586     }
1587
1588     if(SUCCEEDED(hres)) {
1589         nsres = nsIChannelEventSink_AsyncOnChannelRedirect(sink, (nsIChannel*)&This->nschannel->nsIHttpChannel_iface,
1590                 (nsIChannel*)&callback->nschannel->nsIHttpChannel_iface, REDIRECT_TEMPORARY, /* FIXME */
1591                 &callback->nsIAsyncVerifyRedirectCallback_iface);
1592
1593         if(NS_FAILED(nsres))
1594             FIXME("AsyncOnChannelRedirect failed: %08x\n", hres);
1595         else if(This->nschannel != callback->nschannel)
1596             FIXME("nschannel not updated\n");
1597
1598         nsIAsyncVerifyRedirectCallback_Release(&callback->nsIAsyncVerifyRedirectCallback_iface);
1599     }
1600
1601     nsIChannelEventSink_Release(sink);
1602     return hres;
1603 }
1604
1605 static HRESULT nsChannelBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
1606 {
1607     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1608
1609     switch(status_code) {
1610     case BINDSTATUS_MIMETYPEAVAILABLE:
1611         if(!This->nschannel)
1612             return S_OK;
1613
1614         heap_free(This->nschannel->content_type);
1615         This->nschannel->content_type = heap_strdupWtoA(status_text);
1616         break;
1617     case BINDSTATUS_REDIRECTING:
1618         return handle_redirect(This, status_text);
1619     case BINDSTATUS_BEGINDOWNLOADDATA: {
1620         IWinInetHttpInfo *http_info;
1621         DWORD status, size = sizeof(DWORD);
1622         HRESULT hres;
1623
1624         if(!This->bsc.binding)
1625             break;
1626
1627         hres = IBinding_QueryInterface(This->bsc.binding, &IID_IWinInetHttpInfo, (void**)&http_info);
1628         if(FAILED(hres))
1629             break;
1630
1631         hres = IWinInetHttpInfo_QueryInfo(http_info,
1632                 HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL, NULL);
1633         IWinInetHttpInfo_Release(http_info);
1634         if(FAILED(hres) || status == HTTP_STATUS_OK)
1635             break;
1636
1637         handle_navigation_error(This, status);
1638     }
1639     }
1640
1641     return S_OK;
1642 }
1643
1644 static HRESULT nsChannelBSC_on_response(BSCallback *bsc, DWORD response_code,
1645         LPCWSTR response_headers)
1646 {
1647     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1648     HRESULT hres;
1649
1650     This->response_processed = TRUE;
1651     This->nschannel->response_status = response_code;
1652
1653     if(response_headers) {
1654         const WCHAR *headers;
1655
1656         headers = strchrW(response_headers, '\r');
1657         if(headers && headers[1] == '\n') {
1658             headers += 2;
1659             hres = process_response_headers(This, headers);
1660             if(FAILED(hres)) {
1661                 WARN("parsing headers failed: %08x\n", hres);
1662                 return hres;
1663             }
1664         }
1665     }
1666
1667     return S_OK;
1668 }
1669
1670 static HRESULT nsChannelBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
1671 {
1672     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1673     http_header_t *iter;
1674     DWORD len = 0;
1675     WCHAR *ptr;
1676
1677     static const WCHAR content_lengthW[] =
1678         {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0};
1679
1680     if(!This->nschannel)
1681         return S_FALSE;
1682
1683     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->request_headers, http_header_t, entry) {
1684         if(strcmpW(iter->header, content_lengthW))
1685             len += strlenW(iter->header) + 2 /* ": " */ + strlenW(iter->data) + 2 /* "\r\n" */;
1686     }
1687
1688     if(!len)
1689         return S_OK;
1690
1691     *additional_headers = ptr = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
1692     if(!ptr)
1693         return E_OUTOFMEMORY;
1694
1695     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->request_headers, http_header_t, entry) {
1696         if(!strcmpW(iter->header, content_lengthW))
1697             continue;
1698
1699         len = strlenW(iter->header);
1700         memcpy(ptr, iter->header, len*sizeof(WCHAR));
1701         ptr += len;
1702
1703         *ptr++ = ':';
1704         *ptr++ = ' ';
1705
1706         len = strlenW(iter->data);
1707         memcpy(ptr, iter->data, len*sizeof(WCHAR));
1708         ptr += len;
1709
1710         *ptr++ = '\r';
1711         *ptr++ = '\n';
1712     }
1713
1714     *ptr = 0;
1715
1716     return S_OK;
1717 }
1718
1719 static const BSCallbackVtbl nsChannelBSCVtbl = {
1720     nsChannelBSC_destroy,
1721     nsChannelBSC_init_bindinfo,
1722     nsChannelBSC_start_binding,
1723     nsChannelBSC_stop_binding,
1724     nsChannelBSC_read_data,
1725     nsChannelBSC_on_progress,
1726     nsChannelBSC_on_response,
1727     nsChannelBSC_beginning_transaction
1728 };
1729
1730 HRESULT create_channelbsc(IMoniker *mon, const WCHAR *headers, BYTE *post_data, DWORD post_data_size,
1731         BOOL is_doc_binding, nsChannelBSC **retval)
1732 {
1733     nsChannelBSC *ret;
1734
1735     ret = heap_alloc_zero(sizeof(*ret));
1736     if(!ret)
1737         return E_OUTOFMEMORY;
1738
1739     init_bscallback(&ret->bsc, &nsChannelBSCVtbl, mon, BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA);
1740     ret->is_doc_channel = is_doc_binding;
1741
1742     if(headers) {
1743         ret->bsc.headers = heap_strdupW(headers);
1744         if(!ret->bsc.headers) {
1745             IBindStatusCallback_Release(&ret->bsc.IBindStatusCallback_iface);
1746             return E_OUTOFMEMORY;
1747         }
1748     }
1749
1750     if(post_data) {
1751         ret->bsc.post_data = GlobalAlloc(0, post_data_size);
1752         if(!ret->bsc.post_data) {
1753             heap_free(ret->bsc.headers);
1754             IBindStatusCallback_Release(&ret->bsc.IBindStatusCallback_iface);
1755             return E_OUTOFMEMORY;
1756         }
1757
1758         memcpy(ret->bsc.post_data, post_data, post_data_size);
1759         ret->bsc.post_data_len = post_data_size;
1760     }
1761
1762     *retval = ret;
1763     return S_OK;
1764 }
1765
1766 typedef struct {
1767     task_t header;
1768     HTMLOuterWindow *window;
1769     HTMLInnerWindow *pending_window;
1770 } start_doc_binding_task_t;
1771
1772 static void start_doc_binding_proc(task_t *_task)
1773 {
1774     start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task;
1775
1776     set_current_mon(task->window, task->pending_window->bscallback->bsc.mon, BINDING_NAVIGATED);
1777     start_binding(task->pending_window, &task->pending_window->bscallback->bsc, NULL);
1778 }
1779
1780 static void start_doc_binding_task_destr(task_t *_task)
1781 {
1782     start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task;
1783
1784     IHTMLWindow2_Release(&task->pending_window->base.IHTMLWindow2_iface);
1785     heap_free(task);
1786 }
1787
1788 HRESULT async_start_doc_binding(HTMLOuterWindow *window, HTMLInnerWindow *pending_window)
1789 {
1790     start_doc_binding_task_t *task;
1791
1792     TRACE("%p\n", pending_window);
1793
1794     task = heap_alloc(sizeof(start_doc_binding_task_t));
1795     if(!task)
1796         return E_OUTOFMEMORY;
1797
1798     task->window = window;
1799     task->pending_window = pending_window;
1800     IHTMLWindow2_AddRef(&pending_window->base.IHTMLWindow2_iface);
1801
1802     return push_task(&task->header, start_doc_binding_proc, start_doc_binding_task_destr, pending_window->task_magic);
1803 }
1804
1805 void abort_window_bindings(HTMLInnerWindow *window)
1806 {
1807     BSCallback *iter;
1808
1809     remove_target_tasks(window->task_magic);
1810
1811     while(!list_empty(&window->bindings)) {
1812         iter = LIST_ENTRY(window->bindings.next, BSCallback, entry);
1813
1814         TRACE("Aborting %p\n", iter);
1815
1816         IBindStatusCallback_AddRef(&iter->IBindStatusCallback_iface);
1817
1818         if(iter->binding)
1819             IBinding_Abort(iter->binding);
1820         else
1821             iter->vtbl->stop_binding(iter, E_ABORT);
1822
1823         iter->window = NULL;
1824         list_remove(&iter->entry);
1825         list_init(&iter->entry);
1826
1827         IBindStatusCallback_Release(&iter->IBindStatusCallback_iface);
1828     }
1829
1830     if(window->bscallback) {
1831         IBindStatusCallback_Release(&window->bscallback->bsc.IBindStatusCallback_iface);
1832         window->bscallback = NULL;
1833     }
1834
1835     if(window->mon) {
1836         IMoniker_Release(window->mon);
1837         window->mon = NULL;
1838     }
1839 }
1840
1841 HRESULT channelbsc_load_stream(HTMLInnerWindow *pending_window, IStream *stream)
1842 {
1843     nsChannelBSC *bscallback = pending_window->bscallback;
1844     HRESULT hres = S_OK;
1845
1846     if(!bscallback->nschannel) {
1847         ERR("NULL nschannel\n");
1848         return E_FAIL;
1849     }
1850
1851     bscallback->nschannel->content_type = heap_strdupA("text/html");
1852     if(!bscallback->nschannel->content_type)
1853         return E_OUTOFMEMORY;
1854
1855     bscallback->bsc.window = pending_window;
1856     if(stream)
1857         hres = read_stream_data(bscallback, stream);
1858     if(SUCCEEDED(hres))
1859         hres = async_stop_request(bscallback);
1860     if(FAILED(hres))
1861         IBindStatusCallback_OnStopBinding(&bscallback->bsc.IBindStatusCallback_iface, hres,
1862                 ERROR_SUCCESS);
1863
1864     return hres;
1865 }
1866
1867 void channelbsc_set_channel(nsChannelBSC *This, nsChannel *channel, nsIStreamListener *listener, nsISupports *context)
1868 {
1869     nsIHttpChannel_AddRef(&channel->nsIHttpChannel_iface);
1870     This->nschannel = channel;
1871
1872     nsIStreamListener_AddRef(listener);
1873     This->nslistener = listener;
1874
1875     if(context) {
1876         nsISupports_AddRef(context);
1877         This->nscontext = context;
1878     }
1879
1880     if(This->bsc.headers) {
1881         HRESULT hres;
1882
1883         hres = parse_headers(This->bsc.headers, &channel->request_headers);
1884         heap_free(This->bsc.headers);
1885         This->bsc.headers = NULL;
1886         if(FAILED(hres))
1887             WARN("parse_headers failed: %08x\n", hres);
1888     }
1889 }
1890
1891 typedef struct {
1892     task_t header;
1893     HTMLOuterWindow *window;
1894     IUri *uri;
1895 } navigate_javascript_task_t;
1896
1897 static void navigate_javascript_proc(task_t *_task)
1898 {
1899     navigate_javascript_task_t *task = (navigate_javascript_task_t*)_task;
1900     HTMLOuterWindow *window = task->window;
1901     VARIANT v;
1902     BSTR code;
1903     HRESULT hres;
1904
1905     static const WCHAR jscriptW[] = {'j','s','c','r','i','p','t',0};
1906
1907     task->window->readystate = READYSTATE_COMPLETE;
1908
1909     hres = IUri_GetPath(task->uri, &code);
1910     if(FAILED(hres))
1911         return;
1912
1913     hres = UrlUnescapeW(code, NULL, NULL, URL_UNESCAPE_INPLACE);
1914     if(FAILED(hres)) {
1915         SysFreeString(code);
1916         return;
1917     }
1918
1919     set_download_state(window->doc_obj, 1);
1920
1921     V_VT(&v) = VT_EMPTY;
1922     hres = exec_script(window->base.inner_window, code, jscriptW, &v);
1923     SysFreeString(code);
1924     if(SUCCEEDED(hres) && V_VT(&v) != VT_EMPTY) {
1925         FIXME("javascirpt URL returned %s\n", debugstr_variant(&v));
1926         VariantClear(&v);
1927     }
1928
1929     if(window->doc_obj->view_sink)
1930         IAdviseSink_OnViewChange(window->doc_obj->view_sink, DVASPECT_CONTENT, -1);
1931
1932     set_download_state(window->doc_obj, 0);
1933 }
1934
1935 static void navigate_javascript_task_destr(task_t *_task)
1936 {
1937     navigate_javascript_task_t *task = (navigate_javascript_task_t*)_task;
1938
1939     IUri_Release(task->uri);
1940     heap_free(task);
1941 }
1942
1943 typedef struct {
1944     task_t header;
1945     HTMLOuterWindow *window;
1946     nsChannelBSC *bscallback;
1947     DWORD flags;
1948     IMoniker *mon;
1949     IUri *uri;
1950 } navigate_task_t;
1951
1952 static void navigate_proc(task_t *_task)
1953 {
1954     navigate_task_t *task = (navigate_task_t*)_task;
1955     HRESULT hres;
1956
1957     hres = set_moniker(&task->window->doc_obj->basedoc, task->mon, task->uri, NULL, task->bscallback, TRUE);
1958     if(SUCCEEDED(hres)) {
1959         set_current_mon(task->window, task->bscallback->bsc.mon, task->flags);
1960         set_current_uri(task->window, task->uri);
1961         start_binding(task->window->pending_window, &task->bscallback->bsc, NULL);
1962     }
1963 }
1964
1965 static void navigate_task_destr(task_t *_task)
1966 {
1967     navigate_task_t *task = (navigate_task_t*)_task;
1968
1969     IBindStatusCallback_Release(&task->bscallback->bsc.IBindStatusCallback_iface);
1970     IMoniker_Release(task->mon);
1971     IUri_Release(task->uri);
1972     heap_free(task);
1973 }
1974
1975 static HRESULT navigate_fragment(HTMLOuterWindow *window, IUri *uri)
1976 {
1977     nsIDOMLocation *nslocation;
1978     nsAString nsfrag_str;
1979     WCHAR *selector;
1980     BSTR frag;
1981     nsresult nsres;
1982     HRESULT hres;
1983
1984     const WCHAR selector_formatW[] = {'a','[','i','d','=','"','%','s','"',']',0};
1985
1986     set_current_uri(window, uri);
1987
1988     nsres = nsIDOMWindow_GetLocation(window->nswindow, &nslocation);
1989     if(FAILED(nsres) || !nslocation)
1990         return E_FAIL;
1991
1992     hres = IUri_GetFragment(uri, &frag);
1993     if(FAILED(hres)) {
1994         nsIDOMLocation_Release(nslocation);
1995         return hres;
1996     }
1997
1998     nsAString_InitDepend(&nsfrag_str, frag);
1999     nsres = nsIDOMLocation_SetHash(nslocation, &nsfrag_str);
2000     nsAString_Finish(&nsfrag_str);
2001     nsIDOMLocation_Release(nslocation);
2002     if(NS_FAILED(nsres))
2003         ERR("SetHash failed: %08x\n", nsres);
2004
2005     /*
2006      * IE supports scrolling to anchor elements with "#hash" ids (note that '#' is part of the id),
2007      * while Gecko scrolls only to elements with "hash" ids. We scroll the page ourselves if
2008      * a[id="#hash"] element can be found.
2009      */
2010     selector = heap_alloc(sizeof(selector_formatW)+SysStringLen(frag)*sizeof(WCHAR));
2011     if(selector) {
2012         nsIDOMElement *nselem = NULL;
2013         nsAString selector_str;
2014
2015         sprintfW(selector, selector_formatW, frag);
2016         nsAString_InitDepend(&selector_str, selector);
2017         /* NOTE: Gecko doesn't set result to NULL if there is no match, so nselem must be initialized */
2018         nsres = nsIDOMNodeSelector_QuerySelector(window->base.inner_window->doc->nsnode_selector, &selector_str, &nselem);
2019         nsAString_Finish(&selector_str);
2020         heap_free(selector);
2021         if(NS_SUCCEEDED(nsres) && nselem) {
2022             nsIDOMHTMLElement *html_elem;
2023
2024             nsres = nsIDOMElement_QueryInterface(nselem, &IID_nsIDOMHTMLElement, (void**)&html_elem);
2025             nsIDOMElement_Release(nselem);
2026             if(NS_SUCCEEDED(nsres)) {
2027                 nsIDOMHTMLElement_ScrollIntoView(html_elem, TRUE, 1);
2028                 nsIDOMHTMLElement_Release(html_elem);
2029             }
2030         }
2031     }
2032
2033     SysFreeString(frag);
2034
2035     if(window->doc_obj->doc_object_service) {
2036         IDocObjectService_FireNavigateComplete2(window->doc_obj->doc_object_service, &window->base.IHTMLWindow2_iface, 0x10);
2037         IDocObjectService_FireDocumentComplete(window->doc_obj->doc_object_service, &window->base.IHTMLWindow2_iface, 0);
2038
2039     }
2040
2041     return S_OK;
2042 }
2043
2044 HRESULT super_navigate(HTMLOuterWindow *window, IUri *uri, DWORD flags, const WCHAR *headers, BYTE *post_data, DWORD post_data_size)
2045 {
2046     nsChannelBSC *bsc;
2047     IUri *uri_nofrag;
2048     IMoniker *mon;
2049     DWORD scheme;
2050     HRESULT hres;
2051
2052     uri_nofrag = get_uri_nofrag(uri);
2053     if(!uri_nofrag)
2054         return E_FAIL;
2055
2056     if(window->doc_obj->client && !(flags & BINDING_REFRESH)) {
2057         IOleCommandTarget *cmdtrg;
2058
2059         hres = IOleClientSite_QueryInterface(window->doc_obj->client, &IID_IOleCommandTarget, (void**)&cmdtrg);
2060         if(SUCCEEDED(hres)) {
2061             VARIANT in, out;
2062             BSTR url_str;
2063
2064             hres = IUri_GetDisplayUri(uri_nofrag, &url_str);
2065             if(SUCCEEDED(hres)) {
2066                 V_VT(&in) = VT_BSTR;
2067                 V_BSTR(&in) = url_str;
2068                 V_VT(&out) = VT_BOOL;
2069                 V_BOOL(&out) = VARIANT_TRUE;
2070                 hres = IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 67, 0, &in, &out);
2071                 IOleCommandTarget_Release(cmdtrg);
2072                 if(SUCCEEDED(hres))
2073                     VariantClear(&out);
2074                 SysFreeString(url_str);
2075             }
2076         }
2077     }
2078
2079     if(!(flags & BINDING_REFRESH) && window->uri_nofrag && !post_data_size) {
2080         BOOL eq;
2081
2082         hres = IUri_IsEqual(uri_nofrag, window->uri_nofrag, &eq);
2083         if(SUCCEEDED(hres) && eq) {
2084             IUri_Release(uri_nofrag);
2085             TRACE("fragment navigate\n");
2086             return navigate_fragment(window, uri);
2087         }
2088     }
2089
2090     hres = CreateURLMonikerEx2(NULL, uri_nofrag, &mon, URL_MK_UNIFORM);
2091     IUri_Release(uri_nofrag);
2092     if(FAILED(hres))
2093         return hres;
2094
2095     /* FIXME: Why not set_ready_state? */
2096     window->readystate = READYSTATE_UNINITIALIZED;
2097
2098     hres = create_channelbsc(mon, headers, post_data, post_data_size, TRUE, &bsc);
2099     if(FAILED(hres)) {
2100         IMoniker_Release(mon);
2101         return hres;
2102     }
2103
2104     prepare_for_binding(&window->doc_obj->basedoc, mon, flags);
2105
2106     hres = IUri_GetScheme(uri, &scheme);
2107     if(SUCCEEDED(hres) && scheme != URL_SCHEME_JAVASCRIPT) {
2108         navigate_task_t *task;
2109
2110         task = heap_alloc(sizeof(*task));
2111         if(!task) {
2112             IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
2113             IMoniker_Release(mon);
2114             return E_OUTOFMEMORY;
2115         }
2116
2117         /* Silently and repeated when real loading starts? */
2118         window->readystate = READYSTATE_LOADING;
2119         if(!(flags & (BINDING_FROMHIST|BINDING_REFRESH)))
2120             call_docview_84(window->doc_obj);
2121
2122         task->window = window;
2123         task->bscallback = bsc;
2124         task->flags = flags;
2125         task->mon = mon;
2126
2127         IUri_AddRef(uri);
2128         task->uri = uri;
2129         hres = push_task(&task->header, navigate_proc, navigate_task_destr, window->task_magic);
2130     }else {
2131         navigate_javascript_task_t *task;
2132
2133         IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
2134         IMoniker_Release(mon);
2135
2136         task = heap_alloc(sizeof(*task));
2137         if(!task)
2138             return E_OUTOFMEMORY;
2139
2140         /* Why silently? */
2141         window->readystate = READYSTATE_COMPLETE;
2142         if(!(flags & BINDING_FROMHIST))
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, DWORD flags)
2265 {
2266     nsWineURI *nsuri;
2267     HRESULT hres;
2268
2269     TRACE("%s\n", debugstr_w(display_uri));
2270
2271     if(window->doc_obj && window->doc_obj->webbrowser && window == window->doc_obj->basedoc.window) {
2272         if(!(flags & BINDING_REFRESH)) {
2273             BOOL cancel = FALSE;
2274
2275             hres = IDocObjectService_FireBeforeNavigate2(window->doc_obj->doc_object_service, NULL, display_uri, 0x40,
2276                     NULL, NULL, 0, NULL, TRUE, &cancel);
2277             if(SUCCEEDED(hres) && cancel) {
2278                 TRACE("Navigation canceled\n");
2279                 return S_OK;
2280             }
2281         }
2282
2283         return super_navigate(window, uri, flags, NULL, NULL, 0);
2284     }
2285
2286     if(window->doc_obj && window == window->doc_obj->basedoc.window) {
2287         BOOL cancel;
2288
2289         hres = hlink_frame_navigate(&window->base.inner_window->doc->basedoc, display_uri, NULL, 0, &cancel);
2290         if(FAILED(hres))
2291             return hres;
2292
2293         if(cancel) {
2294             TRACE("Navigation handled by hlink frame\n");
2295             return S_OK;
2296         }
2297     }
2298
2299     hres = create_doc_uri(window, uri, &nsuri);
2300     if(FAILED(hres))
2301         return hres;
2302
2303     hres = load_nsuri(window, nsuri, NULL, LOAD_FLAGS_NONE);
2304     nsISupports_Release((nsISupports*)nsuri);
2305     return hres;
2306 }
2307
2308 HRESULT load_uri(HTMLOuterWindow *window, IUri *uri, DWORD flags)
2309 {
2310     BSTR display_uri;
2311     HRESULT hres;
2312
2313     hres = IUri_GetDisplayUri(uri, &display_uri);
2314     if(FAILED(hres))
2315         return hres;
2316
2317     hres = navigate_uri(window, uri, display_uri, flags);
2318     SysFreeString(display_uri);
2319     return hres;
2320 }
2321
2322 HRESULT navigate_url(HTMLOuterWindow *window, const WCHAR *new_url, IUri *base_uri, DWORD flags)
2323 {
2324     BSTR display_uri;
2325     IUri *uri;
2326     HRESULT hres;
2327
2328     if(new_url && base_uri)
2329         hres = CoInternetCombineUrlEx(base_uri, new_url, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO,
2330                 &uri, 0);
2331     else
2332         hres = create_uri(new_url, 0, &uri);
2333     if(FAILED(hres))
2334         return hres;
2335
2336     hres = IUri_GetDisplayUri(uri, &display_uri);
2337     if(FAILED(hres)) {
2338         IUri_Release(uri);
2339         return hres;
2340     }
2341
2342     if(window->doc_obj && window->doc_obj->hostui) {
2343         OLECHAR *translated_url = NULL;
2344
2345         hres = IDocHostUIHandler_TranslateUrl(window->doc_obj->hostui, 0, display_uri,
2346                 &translated_url);
2347         if(hres == S_OK) {
2348             TRACE("%08x %s -> %s\n", hres, debugstr_w(display_uri), debugstr_w(translated_url));
2349             SysFreeString(display_uri);
2350             IUri_Release(uri);
2351             hres = create_uri(translated_url, 0, &uri);
2352             CoTaskMemFree(translated_url);
2353             if(FAILED(hres))
2354                 return hres;
2355
2356             hres = IUri_GetDisplayUri(uri, &display_uri);
2357             if(FAILED(hres)) {
2358                 IUri_Release(uri);
2359                 return hres;
2360             }
2361         }
2362     }
2363
2364     hres = navigate_uri(window, uri, display_uri, flags);
2365
2366     IUri_Release(uri);
2367     SysFreeString(display_uri);
2368     return hres;
2369 }