oleacc: Added CAccPropServices stub implementation.
[wine/multimedia.git] / dlls / mshtml / navigate.c
blobc29e211de4ae7c0f4800568c0f058a3bc5a050a3
1 /*
2 * Copyright 2006-2010 Jacek Caban for CodeWeavers
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.
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.
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
19 #include "config.h"
21 #include <stdarg.h>
22 #include <assert.h>
24 #define COBJMACROS
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
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"
40 #include "wine/debug.h"
42 #include "mshtml_private.h"
43 #include "htmlscript.h"
44 #include "binding.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
48 #define CONTENT_LENGTH "Content-Length"
49 #define UTF8_STR "utf-8"
50 #define UTF16_STR "utf-16"
52 static const WCHAR emptyW[] = {0};
53 static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
55 enum {
56 BOM_NONE,
57 BOM_UTF8,
58 BOM_UTF16
61 struct nsProtocolStream {
62 nsIInputStream nsIInputStream_iface;
64 LONG ref;
66 char buf[1024];
67 DWORD buf_size;
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**);
81 static inline nsProtocolStream *impl_from_nsIInputStream(nsIInputStream *iface)
83 return CONTAINING_RECORD(iface, nsProtocolStream, nsIInputStream_iface);
86 static nsresult NSAPI nsInputStream_QueryInterface(nsIInputStream *iface, nsIIDRef riid,
87 void **result)
89 nsProtocolStream *This = impl_from_nsIInputStream(iface);
91 *result = NULL;
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;
101 if(*result) {
102 nsIInputStream_AddRef(&This->nsIInputStream_iface);
103 return NS_OK;
106 WARN("unsupported interface %s\n", debugstr_guid(riid));
107 return NS_NOINTERFACE;
110 static nsrefcnt NSAPI nsInputStream_AddRef(nsIInputStream *iface)
112 nsProtocolStream *This = impl_from_nsIInputStream(iface);
113 LONG ref = InterlockedIncrement(&This->ref);
115 TRACE("(%p) ref=%d\n", This, ref);
117 return ref;
121 static nsrefcnt NSAPI nsInputStream_Release(nsIInputStream *iface)
123 nsProtocolStream *This = impl_from_nsIInputStream(iface);
124 LONG ref = InterlockedDecrement(&This->ref);
126 TRACE("(%p) ref=%d\n", This, ref);
128 if(!ref)
129 heap_free(This);
131 return ref;
134 static nsresult NSAPI nsInputStream_Close(nsIInputStream *iface)
136 nsProtocolStream *This = impl_from_nsIInputStream(iface);
137 FIXME("(%p)\n", This);
138 return NS_ERROR_NOT_IMPLEMENTED;
141 static nsresult NSAPI nsInputStream_Available(nsIInputStream *iface, UINT64 *_retval)
143 nsProtocolStream *This = impl_from_nsIInputStream(iface);
144 FIXME("(%p)->(%p)\n", This, _retval);
145 return NS_ERROR_NOT_IMPLEMENTED;
148 static nsresult NSAPI nsInputStream_Read(nsIInputStream *iface, char *aBuf, UINT32 aCount,
149 UINT32 *_retval)
151 nsProtocolStream *This = impl_from_nsIInputStream(iface);
152 DWORD read = aCount;
154 TRACE("(%p)->(%p %d %p)\n", This, aBuf, aCount, _retval);
156 if(read > This->buf_size)
157 read = This->buf_size;
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;
166 *_retval = read;
167 return NS_OK;
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)
174 nsProtocolStream *This = impl_from_nsIInputStream(iface);
175 UINT32 written = 0;
176 nsresult nsres;
178 TRACE("(%p)->(%p %p %d %p)\n", This, aWriter, aClousure, aCount, _retval);
180 if(!This->buf_size)
181 return S_OK;
183 if(aCount > This->buf_size)
184 aCount = This->buf_size;
186 nsres = aWriter(&This->nsIInputStream_iface, aClousure, This->buf, 0, aCount, &written);
187 if(NS_FAILED(nsres))
188 TRACE("aWriter failed: %08x\n", nsres);
189 else if(written != This->buf_size)
190 FIXME("written %d != buf_size %d\n", written, This->buf_size);
192 This->buf_size -= written;
194 *_retval = written;
195 return nsres;
198 static nsresult NSAPI nsInputStream_IsNonBlocking(nsIInputStream *iface, cpp_bool *_retval)
200 nsProtocolStream *This = impl_from_nsIInputStream(iface);
201 FIXME("(%p)->(%p)\n", This, _retval);
202 return NS_ERROR_NOT_IMPLEMENTED;
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
216 static nsProtocolStream *create_nsprotocol_stream(void)
218 nsProtocolStream *ret;
220 ret = heap_alloc(sizeof(nsProtocolStream));
221 if(!ret)
222 return NULL;
224 ret->nsIInputStream_iface.lpVtbl = &nsInputStreamVtbl;
225 ret->ref = 1;
226 ret->buf_size = 0;
228 return ret;
231 static void release_request_data(request_data_t *request_data)
233 heap_free(request_data->headers);
234 if(request_data->post_data)
235 GlobalFree(request_data->post_data);
238 static inline BSCallback *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
240 return CONTAINING_RECORD(iface, BSCallback, IBindStatusCallback_iface);
243 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
244 REFIID riid, void **ppv)
246 BSCallback *This = impl_from_IBindStatusCallback(iface);
248 *ppv = NULL;
249 if(IsEqualGUID(&IID_IUnknown, riid)) {
250 TRACE("(%p)->(IID_IUnknown, %p)\n", This, ppv);
251 *ppv = &This->IBindStatusCallback_iface;
252 }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) {
253 TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This, ppv);
254 *ppv = &This->IBindStatusCallback_iface;
255 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
256 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
257 *ppv = &This->IServiceProvider_iface;
258 }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
259 TRACE("(%p)->(IID_IHttpNegotiate %p)\n", This, ppv);
260 *ppv = &This->IHttpNegotiate2_iface;
261 }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
262 TRACE("(%p)->(IID_IHttpNegotiate2 %p)\n", This, ppv);
263 *ppv = &This->IHttpNegotiate2_iface;
264 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
265 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
266 *ppv = &This->IInternetBindInfo_iface;
269 if(*ppv) {
270 IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
271 return S_OK;
274 TRACE("Unsupported riid = %s\n", debugstr_guid(riid));
275 return E_NOINTERFACE;
278 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
280 BSCallback *This = impl_from_IBindStatusCallback(iface);
281 LONG ref = InterlockedIncrement(&This->ref);
283 TRACE("(%p) ref = %d\n", This, ref);
285 return ref;
288 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
290 BSCallback *This = impl_from_IBindStatusCallback(iface);
291 LONG ref = InterlockedDecrement(&This->ref);
293 TRACE("(%p) ref = %d\n", This, ref);
295 if(!ref) {
296 release_request_data(&This->request_data);
297 if(This->mon)
298 IMoniker_Release(This->mon);
299 if(This->binding)
300 IBinding_Release(This->binding);
301 list_remove(&This->entry);
302 list_init(&This->entry);
304 This->vtbl->destroy(This);
307 return ref;
310 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
311 DWORD dwReserved, IBinding *pbind)
313 BSCallback *This = impl_from_IBindStatusCallback(iface);
315 TRACE("(%p)->(%d %p)\n", This, dwReserved, pbind);
317 IBinding_AddRef(pbind);
318 This->binding = pbind;
320 if(This->window)
321 list_add_head(&This->window->bindings, &This->entry);
323 return This->vtbl->start_binding(This);
326 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
328 BSCallback *This = impl_from_IBindStatusCallback(iface);
329 FIXME("(%p)->(%p)\n", This, pnPriority);
330 return E_NOTIMPL;
333 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
335 BSCallback *This = impl_from_IBindStatusCallback(iface);
336 FIXME("(%p)->(%d)\n", This, reserved);
337 return E_NOTIMPL;
340 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
341 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
343 BSCallback *This = impl_from_IBindStatusCallback(iface);
345 TRACE("%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
346 debugstr_w(szStatusText));
348 return This->vtbl->on_progress(This, ulStatusCode, szStatusText);
351 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
352 HRESULT hresult, LPCWSTR szError)
354 BSCallback *This = impl_from_IBindStatusCallback(iface);
355 HRESULT hres;
357 TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
359 /* NOTE: IE7 calls GetBindResult here */
361 hres = This->vtbl->stop_binding(This, hresult);
363 if(This->binding) {
364 IBinding_Release(This->binding);
365 This->binding = NULL;
368 if(This->mon) {
369 IMoniker_Release(This->mon);
370 This->mon = NULL;
373 list_remove(&This->entry);
374 list_init(&This->entry);
375 This->window = NULL;
377 return hres;
380 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
381 DWORD *grfBINDF, BINDINFO *pbindinfo)
383 BSCallback *This = impl_from_IBindStatusCallback(iface);
384 DWORD size;
386 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
388 if(!This->bindinfo_ready) {
389 HRESULT hres;
391 hres = This->vtbl->init_bindinfo(This);
392 if(FAILED(hres))
393 return hres;
395 This->bindinfo_ready = TRUE;
398 *grfBINDF = This->bindf;
400 size = pbindinfo->cbSize;
401 memset(pbindinfo, 0, size);
402 pbindinfo->cbSize = size;
404 pbindinfo->cbstgmedData = This->request_data.post_data_len;
405 pbindinfo->dwCodePage = CP_UTF8;
406 pbindinfo->dwOptions = 0x80000;
408 if(This->request_data.post_data_len) {
409 pbindinfo->dwBindVerb = BINDVERB_POST;
411 pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
412 pbindinfo->stgmedData.u.hGlobal = This->request_data.post_data;
413 pbindinfo->stgmedData.pUnkForRelease = (IUnknown*)&This->IBindStatusCallback_iface;
414 IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
417 return S_OK;
420 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
421 DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
423 BSCallback *This = impl_from_IBindStatusCallback(iface);
425 TRACE("(%p)->(%08x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
427 return This->vtbl->read_data(This, pstgmed->u.pstm);
430 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
431 REFIID riid, IUnknown *punk)
433 BSCallback *This = impl_from_IBindStatusCallback(iface);
434 FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), punk);
435 return E_NOTIMPL;
438 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
439 BindStatusCallback_QueryInterface,
440 BindStatusCallback_AddRef,
441 BindStatusCallback_Release,
442 BindStatusCallback_OnStartBinding,
443 BindStatusCallback_GetPriority,
444 BindStatusCallback_OnLowResource,
445 BindStatusCallback_OnProgress,
446 BindStatusCallback_OnStopBinding,
447 BindStatusCallback_GetBindInfo,
448 BindStatusCallback_OnDataAvailable,
449 BindStatusCallback_OnObjectAvailable
452 static inline BSCallback *impl_from_IHttpNegotiate2(IHttpNegotiate2 *iface)
454 return CONTAINING_RECORD(iface, BSCallback, IHttpNegotiate2_iface);
457 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface,
458 REFIID riid, void **ppv)
460 BSCallback *This = impl_from_IHttpNegotiate2(iface);
461 return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
464 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate2 *iface)
466 BSCallback *This = impl_from_IHttpNegotiate2(iface);
467 return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
470 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface)
472 BSCallback *This = impl_from_IHttpNegotiate2(iface);
473 return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
476 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface,
477 LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
479 BSCallback *This = impl_from_IHttpNegotiate2(iface);
480 HRESULT hres;
482 TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders),
483 dwReserved, pszAdditionalHeaders);
485 *pszAdditionalHeaders = NULL;
487 hres = This->vtbl->beginning_transaction(This, pszAdditionalHeaders);
488 if(hres != S_FALSE)
489 return hres;
491 if(This->request_data.headers) {
492 DWORD size;
494 size = (strlenW(This->request_data.headers)+1)*sizeof(WCHAR);
495 *pszAdditionalHeaders = CoTaskMemAlloc(size);
496 if(!*pszAdditionalHeaders)
497 return E_OUTOFMEMORY;
498 memcpy(*pszAdditionalHeaders, This->request_data.headers, size);
501 return S_OK;
504 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
505 LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
507 BSCallback *This = impl_from_IHttpNegotiate2(iface);
509 TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
510 debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
512 return This->vtbl->on_response(This, dwResponseCode, szResponseHeaders);
515 static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
516 BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
518 BSCallback *This = impl_from_IHttpNegotiate2(iface);
519 FIXME("(%p)->(%p %p %ld)\n", This, pbSecurityId, pcbSecurityId, dwReserved);
520 return E_NOTIMPL;
523 static const IHttpNegotiate2Vtbl HttpNegotiate2Vtbl = {
524 HttpNegotiate_QueryInterface,
525 HttpNegotiate_AddRef,
526 HttpNegotiate_Release,
527 HttpNegotiate_BeginningTransaction,
528 HttpNegotiate_OnResponse,
529 HttpNegotiate_GetRootSecurityId
532 static inline BSCallback *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
534 return CONTAINING_RECORD(iface, BSCallback, IInternetBindInfo_iface);
537 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
538 REFIID riid, void **ppv)
540 BSCallback *This = impl_from_IInternetBindInfo(iface);
541 return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
544 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
546 BSCallback *This = impl_from_IInternetBindInfo(iface);
547 return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
550 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
552 BSCallback *This = impl_from_IInternetBindInfo(iface);
553 return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
556 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
557 DWORD *grfBINDF, BINDINFO *pbindinfo)
559 BSCallback *This = impl_from_IInternetBindInfo(iface);
560 FIXME("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
561 return E_NOTIMPL;
564 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
565 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
567 BSCallback *This = impl_from_IInternetBindInfo(iface);
568 FIXME("(%p)->(%u %p %u %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
569 return E_NOTIMPL;
572 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
573 InternetBindInfo_QueryInterface,
574 InternetBindInfo_AddRef,
575 InternetBindInfo_Release,
576 InternetBindInfo_GetBindInfo,
577 InternetBindInfo_GetBindString
580 static inline BSCallback *impl_from_IServiceProvider(IServiceProvider *iface)
582 return CONTAINING_RECORD(iface, BSCallback, IServiceProvider_iface);
585 static HRESULT WINAPI BSCServiceProvider_QueryInterface(IServiceProvider *iface,
586 REFIID riid, void **ppv)
588 BSCallback *This = impl_from_IServiceProvider(iface);
589 return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
592 static ULONG WINAPI BSCServiceProvider_AddRef(IServiceProvider *iface)
594 BSCallback *This = impl_from_IServiceProvider(iface);
595 return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
598 static ULONG WINAPI BSCServiceProvider_Release(IServiceProvider *iface)
600 BSCallback *This = impl_from_IServiceProvider(iface);
601 return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
604 static HRESULT WINAPI BSCServiceProvider_QueryService(IServiceProvider *iface,
605 REFGUID guidService, REFIID riid, void **ppv)
607 BSCallback *This = impl_from_IServiceProvider(iface);
609 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
611 if(This->window && IsEqualGUID(guidService, &IID_IWindowForBindingUI))
612 return IServiceProvider_QueryService(&This->window->base.IServiceProvider_iface, guidService, riid, ppv);
613 return E_NOINTERFACE;
616 static const IServiceProviderVtbl ServiceProviderVtbl = {
617 BSCServiceProvider_QueryInterface,
618 BSCServiceProvider_AddRef,
619 BSCServiceProvider_Release,
620 BSCServiceProvider_QueryService
623 static void init_bscallback(BSCallback *This, const BSCallbackVtbl *vtbl, IMoniker *mon, DWORD bindf)
625 This->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl;
626 This->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
627 This->IHttpNegotiate2_iface.lpVtbl = &HttpNegotiate2Vtbl;
628 This->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl;
629 This->vtbl = vtbl;
630 This->ref = 1;
631 This->bindf = bindf;
632 This->bom = BOM_NONE;
634 list_init(&This->entry);
636 if(mon)
637 IMoniker_AddRef(mon);
638 This->mon = mon;
641 static HRESULT read_stream(BSCallback *This, IStream *stream, void *buf, DWORD size, DWORD *ret_size)
643 DWORD read_size = 0, skip=0;
644 BYTE *data = buf;
645 HRESULT hres;
647 hres = IStream_Read(stream, buf, size, &read_size);
649 if(!This->readed && This->bom == BOM_NONE) {
650 if(read_size >= 2 && data[0] == 0xff && data[1] == 0xfe) {
651 This->bom = BOM_UTF16;
652 skip = 2;
653 }else if(read_size >= 3 && data[0] == 0xef && data[1] == 0xbb && data[2] == 0xbf) {
654 This->bom = BOM_UTF8;
655 skip = 3;
657 if(skip) {
658 read_size -= skip;
659 if(read_size)
660 memmove(data, data+skip, read_size);
664 This->readed += read_size;
665 *ret_size = read_size;
666 return hres;
669 static void parse_content_type(nsChannelBSC *This, const WCHAR *value)
671 const WCHAR *ptr;
672 size_t len;
674 static const WCHAR charsetW[] = {'c','h','a','r','s','e','t','='};
676 ptr = strchrW(value, ';');
677 if(!ptr)
678 return;
680 ptr++;
681 while(*ptr && isspaceW(*ptr))
682 ptr++;
684 len = strlenW(value);
685 if(ptr + sizeof(charsetW)/sizeof(WCHAR) < value+len && !memicmpW(ptr, charsetW, sizeof(charsetW)/sizeof(WCHAR))) {
686 size_t charset_len, lena;
687 nsACString charset_str;
688 const WCHAR *charset;
689 char *charseta;
691 ptr += sizeof(charsetW)/sizeof(WCHAR);
693 if(*ptr == '\'') {
694 FIXME("Quoted value\n");
695 return;
696 }else {
697 charset = ptr;
698 while(*ptr && *ptr != ',')
699 ptr++;
700 charset_len = ptr-charset;
703 lena = WideCharToMultiByte(CP_ACP, 0, charset, charset_len, NULL, 0, NULL, NULL);
704 charseta = heap_alloc(lena+1);
705 if(!charseta)
706 return;
708 WideCharToMultiByte(CP_ACP, 0, charset, charset_len, charseta, lena, NULL, NULL);
709 charseta[lena] = 0;
711 nsACString_InitDepend(&charset_str, charseta);
712 nsIHttpChannel_SetContentCharset(&This->nschannel->nsIHttpChannel_iface, &charset_str);
713 nsACString_Finish(&charset_str);
714 heap_free(charseta);
715 }else {
716 FIXME("unhandled: %s\n", debugstr_wn(ptr, len - (ptr-value)));
720 static HRESULT parse_headers(const WCHAR *headers, struct list *headers_list)
722 const WCHAR *header, *header_end, *colon, *value;
723 HRESULT hres;
725 header = headers;
726 while(*header) {
727 if(header[0] == '\r' && header[1] == '\n' && !header[2])
728 break;
729 for(colon = header; *colon && *colon != ':' && *colon != '\r'; colon++);
730 if(*colon != ':')
731 return E_FAIL;
733 value = colon+1;
734 while(*value == ' ')
735 value++;
736 if(!*value)
737 return E_FAIL;
739 for(header_end = value+1; *header_end && *header_end != '\r'; header_end++);
741 hres = set_http_header(headers_list, header, colon-header, value, header_end-value);
742 if(FAILED(hres))
743 return hres;
745 header = header_end;
746 if(header[0] == '\r' && header[1] == '\n')
747 header += 2;
750 return S_OK;
753 static HRESULT process_response_headers(nsChannelBSC *This, const WCHAR *headers)
755 http_header_t *iter;
756 HRESULT hres;
758 static const WCHAR content_typeW[] = {'c','o','n','t','e','n','t','-','t','y','p','e',0};
760 hres = parse_headers(headers, &This->nschannel->response_headers);
761 if(FAILED(hres))
762 return hres;
764 LIST_FOR_EACH_ENTRY(iter, &This->nschannel->response_headers, http_header_t, entry) {
765 if(!strcmpiW(iter->header, content_typeW))
766 parse_content_type(This, iter->data);
769 return S_OK;
772 static void query_http_info(nsChannelBSC *This, IWinInetHttpInfo *wininet_info)
774 const WCHAR *ptr;
775 DWORD len = 0;
776 WCHAR *buf;
778 IWinInetHttpInfo_QueryInfo(wininet_info, HTTP_QUERY_RAW_HEADERS_CRLF, NULL, &len, NULL, NULL);
779 if(!len)
780 return;
782 buf = heap_alloc(len);
783 if(!buf)
784 return;
786 IWinInetHttpInfo_QueryInfo(wininet_info, HTTP_QUERY_RAW_HEADERS_CRLF, buf, &len, NULL, NULL);
787 if(!len) {
788 heap_free(buf);
789 return;
792 ptr = strchrW(buf, '\r');
793 if(ptr && ptr[1] == '\n') {
794 ptr += 2;
795 process_response_headers(This, ptr);
798 heap_free(buf);
801 HRESULT start_binding(HTMLInnerWindow *inner_window, BSCallback *bscallback, IBindCtx *bctx)
803 IStream *str = NULL;
804 HRESULT hres;
806 TRACE("(%p %p %p)\n", inner_window, bscallback, bctx);
808 bscallback->window = inner_window;
810 /* NOTE: IE7 calls IsSystemMoniker here*/
812 if(bctx) {
813 hres = RegisterBindStatusCallback(bctx, &bscallback->IBindStatusCallback_iface, NULL, 0);
814 if(SUCCEEDED(hres))
815 IBindCtx_AddRef(bctx);
816 }else {
817 hres = CreateAsyncBindCtx(0, &bscallback->IBindStatusCallback_iface, NULL, &bctx);
820 if(FAILED(hres)) {
821 bscallback->vtbl->stop_binding(bscallback, hres);
822 return hres;
825 hres = IMoniker_BindToStorage(bscallback->mon, bctx, NULL, &IID_IStream, (void**)&str);
826 IBindCtx_Release(bctx);
827 if(FAILED(hres)) {
828 WARN("BindToStorage failed: %08x\n", hres);
829 bscallback->vtbl->stop_binding(bscallback, hres);
830 return hres;
833 if(str)
834 IStream_Release(str);
836 return S_OK;
839 typedef struct {
840 BSCallback bsc;
842 DWORD size;
843 char *buf;
844 HRESULT hres;
845 } BufferBSC;
847 static inline BufferBSC *BufferBSC_from_BSCallback(BSCallback *iface)
849 return CONTAINING_RECORD(iface, BufferBSC, bsc);
852 static void BufferBSC_destroy(BSCallback *bsc)
854 BufferBSC *This = BufferBSC_from_BSCallback(bsc);
856 heap_free(This->buf);
857 heap_free(This);
860 static HRESULT BufferBSC_init_bindinfo(BSCallback *bsc)
862 return S_OK;
865 static HRESULT BufferBSC_start_binding(BSCallback *bsc)
867 return S_OK;
870 static HRESULT BufferBSC_stop_binding(BSCallback *bsc, HRESULT result)
872 BufferBSC *This = BufferBSC_from_BSCallback(bsc);
874 This->hres = result;
876 if(FAILED(result)) {
877 heap_free(This->buf);
878 This->buf = NULL;
879 This->size = 0;
882 return S_OK;
885 static HRESULT BufferBSC_read_data(BSCallback *bsc, IStream *stream)
887 BufferBSC *This = BufferBSC_from_BSCallback(bsc);
888 DWORD readed;
889 HRESULT hres;
891 if(!This->buf) {
892 This->buf = heap_alloc(128);
893 if(!This->buf)
894 return E_OUTOFMEMORY;
895 This->size = 128;
898 do {
899 if(This->bsc.readed >= This->size) {
900 This->size <<= 1;
901 This->buf = heap_realloc(This->buf, This->size);
904 hres = read_stream(&This->bsc, stream, This->buf+This->bsc.readed, This->size-This->bsc.readed, &readed);
905 }while(hres == S_OK);
907 return S_OK;
910 static HRESULT BufferBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
912 return S_OK;
915 static HRESULT BufferBSC_on_response(BSCallback *bsc, DWORD response_code,
916 LPCWSTR response_headers)
918 return S_OK;
921 static HRESULT BufferBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
923 return S_FALSE;
926 static const BSCallbackVtbl BufferBSCVtbl = {
927 BufferBSC_destroy,
928 BufferBSC_init_bindinfo,
929 BufferBSC_start_binding,
930 BufferBSC_stop_binding,
931 BufferBSC_read_data,
932 BufferBSC_on_progress,
933 BufferBSC_on_response,
934 BufferBSC_beginning_transaction
938 HRESULT bind_mon_to_wstr(HTMLInnerWindow *window, IMoniker *mon, WCHAR **ret)
940 BufferBSC *bsc;
941 int cp = CP_ACP;
942 WCHAR *text;
943 HRESULT hres;
945 bsc = heap_alloc_zero(sizeof(*bsc));
946 if(!bsc)
947 return E_OUTOFMEMORY;
949 init_bscallback(&bsc->bsc, &BufferBSCVtbl, mon, 0);
950 bsc->hres = E_FAIL;
952 hres = start_binding(window, &bsc->bsc, NULL);
953 if(SUCCEEDED(hres))
954 hres = bsc->hres;
955 if(FAILED(hres)) {
956 IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
957 return hres;
960 if(!bsc->bsc.readed) {
961 *ret = NULL;
962 return S_OK;
965 switch(bsc->bsc.bom) {
966 case BOM_UTF16:
967 if(bsc->bsc.readed % sizeof(WCHAR)) {
968 FIXME("The buffer is not a valid utf16 string\n");
969 hres = E_FAIL;
970 break;
973 text = heap_alloc(bsc->bsc.readed+sizeof(WCHAR));
974 if(!text) {
975 hres = E_OUTOFMEMORY;
976 break;
979 memcpy(text, bsc->buf, bsc->bsc.readed);
980 text[bsc->bsc.readed/sizeof(WCHAR)] = 0;
981 break;
983 case BOM_UTF8:
984 cp = CP_UTF8;
985 /* fallthrough */
986 default: {
987 DWORD len;
989 len = MultiByteToWideChar(cp, 0, bsc->buf, bsc->bsc.readed, NULL, 0);
990 text = heap_alloc((len+1)*sizeof(WCHAR));
991 if(!text) {
992 hres = E_OUTOFMEMORY;
993 break;
996 MultiByteToWideChar(cp, 0, bsc->buf, bsc->bsc.readed, text, len);
997 text[len] = 0;
1001 IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
1002 if(FAILED(hres))
1003 return hres;
1005 *ret = text;
1006 return S_OK;
1009 static HRESULT read_post_data_stream(nsIInputStream *stream, BOOL contains_headers, struct list *headers_list,
1010 request_data_t *request_data)
1012 UINT64 available = 0;
1013 UINT32 data_len = 0;
1014 char *data, *post_data;
1015 nsresult nsres;
1016 HRESULT hres = S_OK;
1018 if(!stream)
1019 return S_OK;
1021 nsres = nsIInputStream_Available(stream, &available);
1022 if(NS_FAILED(nsres))
1023 return E_FAIL;
1025 post_data = data = GlobalAlloc(0, available+1);
1026 if(!data)
1027 return E_OUTOFMEMORY;
1029 nsres = nsIInputStream_Read(stream, data, available, &data_len);
1030 if(NS_FAILED(nsres)) {
1031 GlobalFree(data);
1032 return E_FAIL;
1035 if(contains_headers) {
1036 if(data_len >= 2 && data[0] == '\r' && data[1] == '\n') {
1037 post_data = data+2;
1038 data_len -= 2;
1039 }else {
1040 WCHAR *headers;
1041 DWORD size;
1042 char *ptr;
1044 post_data += data_len;
1045 for(ptr = data; ptr+4 < data+data_len; ptr++) {
1046 if(!memcmp(ptr, "\r\n\r\n", 4)) {
1047 ptr += 2;
1048 post_data = ptr+2;
1049 break;
1053 data_len -= post_data-data;
1055 size = MultiByteToWideChar(CP_ACP, 0, data, ptr-data, NULL, 0);
1056 headers = heap_alloc((size+1)*sizeof(WCHAR));
1057 if(headers) {
1058 MultiByteToWideChar(CP_ACP, 0, data, ptr-data, headers, size);
1059 headers[size] = 0;
1060 if(headers_list)
1061 hres = parse_headers(headers, headers_list);
1062 if(SUCCEEDED(hres))
1063 request_data->headers = headers;
1064 else
1065 heap_free(headers);
1066 }else {
1067 hres = E_OUTOFMEMORY;
1072 if(FAILED(hres)) {
1073 GlobalFree(data);
1074 return hres;
1077 if(!data_len) {
1078 GlobalFree(data);
1079 post_data = NULL;
1080 }else if(post_data != data) {
1081 char *new_data;
1083 new_data = GlobalAlloc(0, data_len+1);
1084 if(new_data)
1085 memcpy(new_data, post_data, data_len);
1086 GlobalFree(data);
1087 if(!new_data)
1088 return E_OUTOFMEMORY;
1089 post_data = new_data;
1092 post_data[data_len] = 0;
1093 request_data->post_data = post_data;
1094 request_data->post_data_len = data_len;
1095 TRACE("post_data = %s\n", debugstr_an(request_data->post_data, request_data->post_data_len));
1096 return S_OK;
1099 static HRESULT on_start_nsrequest(nsChannelBSC *This)
1101 nsresult nsres;
1103 /* FIXME: it's needed for http connections from BindToObject. */
1104 if(!This->nschannel->response_status)
1105 This->nschannel->response_status = 200;
1107 nsres = nsIStreamListener_OnStartRequest(This->nslistener,
1108 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext);
1109 if(NS_FAILED(nsres)) {
1110 FIXME("OnStartRequest failed: %08x\n", nsres);
1111 return E_FAIL;
1114 if(This->is_doc_channel) {
1115 update_window_doc(This->bsc.window);
1116 if(This->bsc.window->base.outer_window->readystate != READYSTATE_LOADING)
1117 set_ready_state(This->bsc.window->base.outer_window, READYSTATE_LOADING);
1120 return S_OK;
1123 static void on_stop_nsrequest(nsChannelBSC *This, HRESULT result)
1125 nsresult nsres, request_result;
1127 switch(result) {
1128 case S_OK:
1129 request_result = NS_OK;
1130 break;
1131 case E_ABORT:
1132 request_result = NS_BINDING_ABORTED;
1133 break;
1134 default:
1135 request_result = NS_ERROR_FAILURE;
1138 if(This->nslistener) {
1139 nsres = nsIStreamListener_OnStopRequest(This->nslistener,
1140 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext,
1141 request_result);
1142 if(NS_FAILED(nsres))
1143 WARN("OnStopRequest failed: %08x\n", nsres);
1146 if(This->nschannel && This->nschannel->load_group) {
1147 nsres = nsILoadGroup_RemoveRequest(This->nschannel->load_group,
1148 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, NULL, request_result);
1149 if(NS_FAILED(nsres))
1150 ERR("RemoveRequest failed: %08x\n", nsres);
1154 static HRESULT read_stream_data(nsChannelBSC *This, IStream *stream)
1156 DWORD read;
1157 nsresult nsres;
1158 HRESULT hres;
1160 if(!This->response_processed) {
1161 IWinInetHttpInfo *wininet_info;
1163 This->response_processed = TRUE;
1164 if(This->bsc.binding) {
1165 hres = IBinding_QueryInterface(This->bsc.binding, &IID_IWinInetHttpInfo, (void**)&wininet_info);
1166 if(SUCCEEDED(hres)) {
1167 query_http_info(This, wininet_info);
1168 IWinInetHttpInfo_Release(wininet_info);
1173 if(!This->nschannel)
1174 return S_OK;
1176 if(!This->nslistener) {
1177 BYTE buf[1024];
1179 do {
1180 hres = read_stream(&This->bsc, stream, buf, sizeof(buf), &read);
1181 }while(hres == S_OK && read);
1183 return S_OK;
1186 if(!This->nsstream) {
1187 This->nsstream = create_nsprotocol_stream();
1188 if(!This->nsstream)
1189 return E_OUTOFMEMORY;
1192 do {
1193 BOOL first_read = !This->bsc.readed;
1195 hres = read_stream(&This->bsc, stream, This->nsstream->buf+This->nsstream->buf_size,
1196 sizeof(This->nsstream->buf)-This->nsstream->buf_size, &read);
1197 if(!read)
1198 break;
1200 This->nsstream->buf_size += read;
1202 if(first_read) {
1203 switch(This->bsc.bom) {
1204 case BOM_UTF8:
1205 This->nschannel->charset = heap_strdupA(UTF8_STR);
1206 break;
1207 case BOM_UTF16:
1208 This->nschannel->charset = heap_strdupA(UTF16_STR);
1211 if(!This->nschannel->content_type) {
1212 WCHAR *mime;
1214 hres = FindMimeFromData(NULL, NULL, This->nsstream->buf, This->nsstream->buf_size,
1215 This->is_doc_channel ? text_htmlW : NULL, 0, &mime, 0);
1216 if(FAILED(hres))
1217 return hres;
1219 TRACE("Found MIME %s\n", debugstr_w(mime));
1221 This->nschannel->content_type = heap_strdupWtoA(mime);
1222 CoTaskMemFree(mime);
1223 if(!This->nschannel->content_type)
1224 return E_OUTOFMEMORY;
1227 on_start_nsrequest(This);
1230 nsres = nsIStreamListener_OnDataAvailable(This->nslistener,
1231 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext,
1232 &This->nsstream->nsIInputStream_iface, This->bsc.readed-This->nsstream->buf_size,
1233 This->nsstream->buf_size);
1234 if(NS_FAILED(nsres))
1235 ERR("OnDataAvailable failed: %08x\n", nsres);
1237 if(This->nsstream->buf_size == sizeof(This->nsstream->buf)) {
1238 ERR("buffer is full\n");
1239 break;
1241 }while(hres == S_OK);
1243 return S_OK;
1246 typedef struct {
1247 nsIAsyncVerifyRedirectCallback nsIAsyncVerifyRedirectCallback_iface;
1249 LONG ref;
1251 nsChannel *nschannel;
1252 nsChannelBSC *bsc;
1253 } nsRedirectCallback;
1255 static nsRedirectCallback *impl_from_nsIAsyncVerifyRedirectCallback(nsIAsyncVerifyRedirectCallback *iface)
1257 return CONTAINING_RECORD(iface, nsRedirectCallback, nsIAsyncVerifyRedirectCallback_iface);
1260 static nsresult NSAPI nsAsyncVerifyRedirectCallback_QueryInterface(nsIAsyncVerifyRedirectCallback *iface,
1261 nsIIDRef riid, void **result)
1263 nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1265 if(IsEqualGUID(&IID_nsISupports, riid)) {
1266 TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
1267 *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1268 }else if(IsEqualGUID(&IID_nsIAsyncVerifyRedirectCallback, riid)) {
1269 TRACE("(%p)->(IID_nsIAsyncVerifyRedirectCallback %p)\n", This, result);
1270 *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1271 }else {
1272 *result = NULL;
1273 WARN("unimplemented iface %s\n", debugstr_guid(riid));
1274 return NS_NOINTERFACE;
1277 nsISupports_AddRef((nsISupports*)*result);
1278 return NS_OK;
1281 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_AddRef(nsIAsyncVerifyRedirectCallback *iface)
1283 nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1284 LONG ref = InterlockedIncrement(&This->ref);
1286 TRACE("(%p) ref=%d\n", This, ref);
1288 return ref;
1291 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_Release(nsIAsyncVerifyRedirectCallback *iface)
1293 nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1294 LONG ref = InterlockedDecrement(&This->ref);
1296 TRACE("(%p) ref=%d\n", This, ref);
1298 if(!ref) {
1299 IBindStatusCallback_Release(&This->bsc->bsc.IBindStatusCallback_iface);
1300 nsIHttpChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1301 heap_free(This);
1304 return ref;
1307 static nsresult NSAPI nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect(nsIAsyncVerifyRedirectCallback *iface, nsresult result)
1309 nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1310 nsChannel *old_nschannel;
1311 nsresult nsres;
1313 TRACE("(%p)->(%08x)\n", This, result);
1315 old_nschannel = This->bsc->nschannel;
1316 nsIHttpChannel_AddRef(&This->nschannel->nsIHttpChannel_iface);
1317 This->bsc->nschannel = This->nschannel;
1319 if(This->nschannel->load_group) {
1320 nsres = nsILoadGroup_AddRequest(This->nschannel->load_group, (nsIRequest*)&This->nschannel->nsIHttpChannel_iface,
1321 NULL);
1322 if(NS_FAILED(nsres))
1323 ERR("AddRequest failed: %08x\n", nsres);
1326 if(This->bsc->is_doc_channel) {
1327 IUri *uri = nsuri_get_uri(This->nschannel->uri);
1329 if(uri) {
1330 set_current_uri(This->bsc->bsc.window->base.outer_window, uri);
1331 IUri_Release(uri);
1332 }else {
1333 WARN("Could not get IUri from nsWineURI\n");
1337 if(old_nschannel) {
1338 if(old_nschannel->load_group) {
1339 nsres = nsILoadGroup_RemoveRequest(old_nschannel->load_group,
1340 (nsIRequest*)&old_nschannel->nsIHttpChannel_iface, NULL, NS_OK);
1341 if(NS_FAILED(nsres))
1342 ERR("RemoveRequest failed: %08x\n", nsres);
1344 nsIHttpChannel_Release(&old_nschannel->nsIHttpChannel_iface);
1347 return NS_OK;
1350 static const nsIAsyncVerifyRedirectCallbackVtbl nsAsyncVerifyRedirectCallbackVtbl = {
1351 nsAsyncVerifyRedirectCallback_QueryInterface,
1352 nsAsyncVerifyRedirectCallback_AddRef,
1353 nsAsyncVerifyRedirectCallback_Release,
1354 nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect
1357 static HRESULT create_redirect_callback(nsChannel *nschannel, nsChannelBSC *bsc, nsRedirectCallback **ret)
1359 nsRedirectCallback *callback;
1361 callback = heap_alloc(sizeof(*callback));
1362 if(!callback)
1363 return E_OUTOFMEMORY;
1365 callback->nsIAsyncVerifyRedirectCallback_iface.lpVtbl = &nsAsyncVerifyRedirectCallbackVtbl;
1366 callback->ref = 1;
1368 nsIHttpChannel_AddRef(&nschannel->nsIHttpChannel_iface);
1369 callback->nschannel = nschannel;
1371 IBindStatusCallback_AddRef(&bsc->bsc.IBindStatusCallback_iface);
1372 callback->bsc = bsc;
1374 *ret = callback;
1375 return S_OK;
1378 static inline nsChannelBSC *nsChannelBSC_from_BSCallback(BSCallback *iface)
1380 return CONTAINING_RECORD(iface, nsChannelBSC, bsc);
1383 static void nsChannelBSC_destroy(BSCallback *bsc)
1385 nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1387 if(This->nschannel)
1388 nsIHttpChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1389 if(This->nslistener)
1390 nsIStreamListener_Release(This->nslistener);
1391 if(This->nscontext)
1392 nsISupports_Release(This->nscontext);
1393 if(This->nsstream)
1394 nsIInputStream_Release(&This->nsstream->nsIInputStream_iface);
1395 heap_free(This);
1398 static HRESULT nsChannelBSC_start_binding(BSCallback *bsc)
1400 nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1402 if(This->is_doc_channel)
1403 This->bsc.window->base.outer_window->base.inner_window->doc->skip_mutation_notif = FALSE;
1405 return S_OK;
1408 static HRESULT nsChannelBSC_init_bindinfo(BSCallback *bsc)
1410 nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1411 nsChannel *nschannel = This->nschannel;
1412 HRESULT hres;
1414 if(nschannel && nschannel->post_data_stream) {
1415 hres = read_post_data_stream(nschannel->post_data_stream, nschannel->post_data_contains_headers,
1416 &nschannel->request_headers, &This->bsc.request_data);
1417 if(FAILED(hres))
1418 return hres;
1421 return S_OK;
1424 typedef struct {
1425 task_t header;
1426 nsChannelBSC *bsc;
1427 } stop_request_task_t;
1429 static void stop_request_proc(task_t *_task)
1431 stop_request_task_t *task = (stop_request_task_t*)_task;
1433 TRACE("(%p)\n", task->bsc);
1435 list_remove(&task->bsc->bsc.entry);
1436 list_init(&task->bsc->bsc.entry);
1437 on_stop_nsrequest(task->bsc, S_OK);
1440 static void stop_request_task_destr(task_t *_task)
1442 stop_request_task_t *task = (stop_request_task_t*)_task;
1444 IBindStatusCallback_Release(&task->bsc->bsc.IBindStatusCallback_iface);
1445 heap_free(task);
1448 static HRESULT async_stop_request(nsChannelBSC *This)
1450 stop_request_task_t *task;
1452 if(!This->bsc.readed) {
1453 TRACE("No data read, calling OnStartRequest\n");
1454 on_start_nsrequest(This);
1457 task = heap_alloc(sizeof(*task));
1458 if(!task)
1459 return E_OUTOFMEMORY;
1461 IBindStatusCallback_AddRef(&This->bsc.IBindStatusCallback_iface);
1462 task->bsc = This;
1464 return push_task(&task->header, stop_request_proc, stop_request_task_destr, This->bsc.window->task_magic);
1467 static void handle_navigation_error(nsChannelBSC *This, DWORD result)
1469 HTMLOuterWindow *outer_window;
1470 HTMLDocumentObj *doc;
1471 BOOL is_error_url;
1472 SAFEARRAY *sa;
1473 SAFEARRAYBOUND bound;
1474 VARIANT var, varOut;
1475 LONG ind;
1476 BSTR unk;
1477 HRESULT hres;
1479 if(!This->is_doc_channel || !This->bsc.window)
1480 return;
1482 outer_window = This->bsc.window->base.outer_window;
1484 doc = outer_window->doc_obj;
1485 if(!doc || !doc->doc_object_service || !doc->client)
1486 return;
1488 hres = IDocObjectService_IsErrorUrl(doc->doc_object_service,
1489 outer_window->url, &is_error_url);
1490 if(FAILED(hres) || is_error_url)
1491 return;
1493 if(!doc->client_cmdtrg)
1494 return;
1496 bound.lLbound = 0;
1497 bound.cElements = 8;
1498 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1499 if(!sa)
1500 return;
1502 ind = 0;
1503 V_VT(&var) = VT_I4;
1504 V_I4(&var) = result;
1505 SafeArrayPutElement(sa, &ind, &var);
1507 ind = 1;
1508 V_VT(&var) = VT_BSTR;
1509 V_BSTR(&var) = outer_window->url;
1510 SafeArrayPutElement(sa, &ind, &var);
1512 ind = 3;
1513 V_VT(&var) = VT_UNKNOWN;
1514 V_UNKNOWN(&var) = (IUnknown*)&outer_window->base.IHTMLWindow2_iface;
1515 SafeArrayPutElement(sa, &ind, &var);
1517 /* FIXME: what are the following fields for? */
1518 ind = 2;
1519 V_VT(&var) = VT_UNKNOWN;
1520 V_UNKNOWN(&var) = NULL;
1521 SafeArrayPutElement(sa, &ind, &var);
1523 ind = 4;
1524 V_VT(&var) = VT_BOOL;
1525 V_BOOL(&var) = FALSE;
1526 SafeArrayPutElement(sa, &ind, &var);
1528 ind = 5;
1529 V_VT(&var) = VT_BOOL;
1530 V_BOOL(&var) = FALSE;
1531 SafeArrayPutElement(sa, &ind, &var);
1533 ind = 6;
1534 V_VT(&var) = VT_BSTR;
1535 unk = SysAllocString(NULL);
1536 V_BSTR(&var) = unk;
1537 SafeArrayPutElement(sa, &ind, &var);
1539 ind = 7;
1540 V_VT(&var) = VT_UNKNOWN;
1541 V_UNKNOWN(&var) = NULL;
1542 SafeArrayPutElement(sa, &ind, &var);
1544 V_VT(&var) = VT_ARRAY;
1545 V_ARRAY(&var) = sa;
1546 V_VT(&varOut) = VT_BOOL;
1547 V_BOOL(&varOut) = VARIANT_TRUE;
1548 IOleCommandTarget_Exec(doc->client_cmdtrg, &CGID_DocHostCmdPriv, 1, 0, &var, FAILED(hres)?NULL:&varOut);
1550 SysFreeString(unk);
1551 SafeArrayDestroy(sa);
1554 static HRESULT nsChannelBSC_stop_binding(BSCallback *bsc, HRESULT result)
1556 nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1558 if(result != E_ABORT) {
1559 if(FAILED(result))
1560 handle_navigation_error(This, result);
1561 else if(This->is_doc_channel && This->nschannel) {
1562 result = async_stop_request(This);
1563 if(SUCCEEDED(result))
1564 return S_OK;
1568 on_stop_nsrequest(This, result);
1569 return S_OK;
1572 static HRESULT nsChannelBSC_read_data(BSCallback *bsc, IStream *stream)
1574 nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1576 return read_stream_data(This, stream);
1579 static HRESULT handle_redirect(nsChannelBSC *This, const WCHAR *new_url)
1581 nsRedirectCallback *callback;
1582 nsIChannelEventSink *sink;
1583 nsChannel *new_channel;
1584 nsresult nsres;
1585 HRESULT hres;
1587 TRACE("(%p)->(%s)\n", This, debugstr_w(new_url));
1589 if(!This->nschannel || !This->nschannel->notif_callback)
1590 return S_OK;
1592 nsres = nsIInterfaceRequestor_GetInterface(This->nschannel->notif_callback, &IID_nsIChannelEventSink, (void**)&sink);
1593 if(NS_FAILED(nsres))
1594 return S_OK;
1596 hres = create_redirect_nschannel(new_url, This->nschannel, &new_channel);
1597 if(SUCCEEDED(hres)) {
1598 TRACE("%p %p->%p\n", This, This->nschannel, new_channel);
1600 hres = create_redirect_callback(new_channel, This, &callback);
1601 nsIHttpChannel_Release(&new_channel->nsIHttpChannel_iface);
1604 if(SUCCEEDED(hres)) {
1605 nsres = nsIChannelEventSink_AsyncOnChannelRedirect(sink, (nsIChannel*)&This->nschannel->nsIHttpChannel_iface,
1606 (nsIChannel*)&callback->nschannel->nsIHttpChannel_iface, REDIRECT_TEMPORARY, /* FIXME */
1607 &callback->nsIAsyncVerifyRedirectCallback_iface);
1609 if(NS_FAILED(nsres))
1610 FIXME("AsyncOnChannelRedirect failed: %08x\n", hres);
1611 else if(This->nschannel != callback->nschannel)
1612 FIXME("nschannel not updated\n");
1614 nsIAsyncVerifyRedirectCallback_Release(&callback->nsIAsyncVerifyRedirectCallback_iface);
1617 nsIChannelEventSink_Release(sink);
1618 return hres;
1621 static BOOL is_supported_doc_mime(const WCHAR *mime)
1623 char *nscat, *mimea;
1624 BOOL ret;
1626 mimea = heap_strdupWtoA(mime);
1627 if(!mimea)
1628 return FALSE;
1630 nscat = get_nscategory_entry("Gecko-Content-Viewers", mimea);
1632 ret = nscat != NULL && !strcmp(nscat, "@mozilla.org/content/document-loader-factory;1");
1634 heap_free(mimea);
1635 nsfree(nscat);
1636 return ret;
1639 static IUri *get_moniker_uri(IMoniker *mon)
1641 IUriContainer *uri_container;
1642 IUri *ret = NULL;
1643 HRESULT hres;
1645 hres = IMoniker_QueryInterface(mon, &IID_IUriContainer, (void**)&uri_container);
1646 if(SUCCEEDED(hres)) {
1647 hres = IUriContainer_GetIUri(uri_container, &ret);
1648 IUriContainer_Release(uri_container);
1649 if(FAILED(hres))
1650 return NULL;
1651 }else {
1652 FIXME("No IUriContainer\n");
1655 return ret;
1658 static void handle_extern_mime_navigation(nsChannelBSC *This)
1660 IWebBrowserPriv2IE9 *webbrowser_priv;
1661 IOleCommandTarget *cmdtrg;
1662 HTMLDocumentObj *doc_obj;
1663 IBindCtx *bind_ctx;
1664 IUri *uri;
1665 VARIANT flags;
1666 HRESULT hres;
1668 if(!This->bsc.window || !This->bsc.window->base.outer_window || !This->bsc.window->base.outer_window->doc_obj)
1669 return;
1671 doc_obj = This->bsc.window->base.outer_window->doc_obj;
1673 hres = IOleClientSite_QueryInterface(doc_obj->client, &IID_IOleCommandTarget, (void**)&cmdtrg);
1674 if(SUCCEEDED(hres)) {
1675 IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 62, 0, NULL, NULL);
1676 IOleCommandTarget_Release(cmdtrg);
1679 set_document_navigation(doc_obj, FALSE);
1681 if(!doc_obj->webbrowser) {
1682 FIXME("unimplemented in non-webbrowser mode\n");
1683 return;
1686 uri = get_moniker_uri(This->bsc.mon);
1687 if(!uri)
1688 return;
1690 hres = CreateBindCtx(0, &bind_ctx);
1691 if(FAILED(hres)) {
1692 IUri_Release(uri);
1693 return;
1696 V_VT(&flags) = VT_I4;
1697 V_I4(&flags) = navHyperlink;
1699 hres = IUnknown_QueryInterface(doc_obj->webbrowser, &IID_IWebBrowserPriv2IE8, (void**)&webbrowser_priv);
1700 if(SUCCEEDED(hres)) {
1701 hres = IWebBrowserPriv2IE9_NavigateWithBindCtx2(webbrowser_priv, uri, &flags, NULL, NULL, NULL, bind_ctx, NULL, 0);
1702 IWebBrowserPriv2IE9_Release(webbrowser_priv);
1703 }else {
1704 IWebBrowserPriv *webbrowser_priv_old;
1705 VARIANT uriv;
1707 hres = IUnknown_QueryInterface(doc_obj->webbrowser, &IID_IWebBrowserPriv, (void**)&webbrowser_priv_old);
1708 if(SUCCEEDED(hres)) {
1709 V_VT(&uriv) = VT_BSTR;
1710 IUri_GetDisplayUri(uri, &V_BSTR(&uriv));
1712 hres = IWebBrowserPriv_NavigateWithBindCtx(webbrowser_priv_old, &uriv, &flags, NULL, NULL, NULL, bind_ctx, NULL);
1714 SysFreeString(V_BSTR(&uriv));
1715 IWebBrowserPriv_Release(webbrowser_priv_old);
1719 IUri_Release(uri);
1722 static HRESULT nsChannelBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
1724 nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1726 switch(status_code) {
1727 case BINDSTATUS_MIMETYPEAVAILABLE:
1728 if(This->is_doc_channel && !is_supported_doc_mime(status_text)) {
1729 FIXME("External MIME: %s\n", debugstr_w(status_text));
1731 handle_extern_mime_navigation(This);
1733 This->nschannel = NULL;
1736 if(!This->nschannel)
1737 return S_OK;
1739 heap_free(This->nschannel->content_type);
1740 This->nschannel->content_type = heap_strdupWtoA(status_text);
1741 break;
1742 case BINDSTATUS_REDIRECTING:
1743 return handle_redirect(This, status_text);
1744 case BINDSTATUS_BEGINDOWNLOADDATA: {
1745 IWinInetHttpInfo *http_info;
1746 DWORD status, size = sizeof(DWORD);
1747 HRESULT hres;
1749 if(!This->bsc.binding)
1750 break;
1752 hres = IBinding_QueryInterface(This->bsc.binding, &IID_IWinInetHttpInfo, (void**)&http_info);
1753 if(FAILED(hres))
1754 break;
1756 hres = IWinInetHttpInfo_QueryInfo(http_info,
1757 HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL, NULL);
1758 IWinInetHttpInfo_Release(http_info);
1759 if(FAILED(hres) || status == HTTP_STATUS_OK)
1760 break;
1762 handle_navigation_error(This, status);
1766 return S_OK;
1769 static HRESULT nsChannelBSC_on_response(BSCallback *bsc, DWORD response_code,
1770 LPCWSTR response_headers)
1772 nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1773 HRESULT hres;
1775 This->response_processed = TRUE;
1776 This->nschannel->response_status = response_code;
1778 if(response_headers) {
1779 const WCHAR *headers;
1781 headers = strchrW(response_headers, '\r');
1782 if(headers && headers[1] == '\n') {
1783 headers += 2;
1784 hres = process_response_headers(This, headers);
1785 if(FAILED(hres)) {
1786 WARN("parsing headers failed: %08x\n", hres);
1787 return hres;
1792 return S_OK;
1795 static HRESULT nsChannelBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
1797 nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1798 http_header_t *iter;
1799 DWORD len = 0;
1800 WCHAR *ptr;
1802 static const WCHAR content_lengthW[] =
1803 {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0};
1805 if(!This->nschannel)
1806 return S_FALSE;
1808 LIST_FOR_EACH_ENTRY(iter, &This->nschannel->request_headers, http_header_t, entry) {
1809 if(strcmpW(iter->header, content_lengthW))
1810 len += strlenW(iter->header) + 2 /* ": " */ + strlenW(iter->data) + 2 /* "\r\n" */;
1813 if(!len)
1814 return S_OK;
1816 *additional_headers = ptr = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
1817 if(!ptr)
1818 return E_OUTOFMEMORY;
1820 LIST_FOR_EACH_ENTRY(iter, &This->nschannel->request_headers, http_header_t, entry) {
1821 if(!strcmpW(iter->header, content_lengthW))
1822 continue;
1824 len = strlenW(iter->header);
1825 memcpy(ptr, iter->header, len*sizeof(WCHAR));
1826 ptr += len;
1828 *ptr++ = ':';
1829 *ptr++ = ' ';
1831 len = strlenW(iter->data);
1832 memcpy(ptr, iter->data, len*sizeof(WCHAR));
1833 ptr += len;
1835 *ptr++ = '\r';
1836 *ptr++ = '\n';
1839 *ptr = 0;
1841 return S_OK;
1844 static const BSCallbackVtbl nsChannelBSCVtbl = {
1845 nsChannelBSC_destroy,
1846 nsChannelBSC_init_bindinfo,
1847 nsChannelBSC_start_binding,
1848 nsChannelBSC_stop_binding,
1849 nsChannelBSC_read_data,
1850 nsChannelBSC_on_progress,
1851 nsChannelBSC_on_response,
1852 nsChannelBSC_beginning_transaction
1855 HRESULT create_channelbsc(IMoniker *mon, const WCHAR *headers, BYTE *post_data, DWORD post_data_size,
1856 BOOL is_doc_binding, nsChannelBSC **retval)
1858 nsChannelBSC *ret;
1859 DWORD bindf;
1861 ret = heap_alloc_zero(sizeof(*ret));
1862 if(!ret)
1863 return E_OUTOFMEMORY;
1865 bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
1866 if(post_data_size)
1867 bindf |= BINDF_FORMS_SUBMIT | BINDF_PRAGMA_NO_CACHE | BINDF_HYPERLINK | BINDF_GETNEWESTVERSION;
1869 init_bscallback(&ret->bsc, &nsChannelBSCVtbl, mon, bindf);
1870 ret->is_doc_channel = is_doc_binding;
1872 if(headers) {
1873 ret->bsc.request_data.headers = heap_strdupW(headers);
1874 if(!ret->bsc.request_data.headers) {
1875 IBindStatusCallback_Release(&ret->bsc.IBindStatusCallback_iface);
1876 return E_OUTOFMEMORY;
1880 if(post_data) {
1881 ret->bsc.request_data.post_data = GlobalAlloc(0, post_data_size+1);
1882 if(!ret->bsc.request_data.post_data) {
1883 release_request_data(&ret->bsc.request_data);
1884 IBindStatusCallback_Release(&ret->bsc.IBindStatusCallback_iface);
1885 return E_OUTOFMEMORY;
1888 memcpy(ret->bsc.request_data.post_data, post_data, post_data_size);
1889 ((BYTE*)ret->bsc.request_data.post_data)[post_data_size] = 0;
1890 ret->bsc.request_data.post_data_len = post_data_size;
1893 TRACE("created %p\n", ret);
1894 *retval = ret;
1895 return S_OK;
1898 typedef struct {
1899 task_t header;
1900 HTMLOuterWindow *window;
1901 HTMLInnerWindow *pending_window;
1902 } start_doc_binding_task_t;
1904 static void start_doc_binding_proc(task_t *_task)
1906 start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task;
1908 set_current_mon(task->window, task->pending_window->bscallback->bsc.mon, BINDING_NAVIGATED);
1909 start_binding(task->pending_window, &task->pending_window->bscallback->bsc, NULL);
1912 static void start_doc_binding_task_destr(task_t *_task)
1914 start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task;
1916 IHTMLWindow2_Release(&task->pending_window->base.IHTMLWindow2_iface);
1917 heap_free(task);
1920 HRESULT async_start_doc_binding(HTMLOuterWindow *window, HTMLInnerWindow *pending_window)
1922 start_doc_binding_task_t *task;
1924 TRACE("%p\n", pending_window);
1926 task = heap_alloc(sizeof(start_doc_binding_task_t));
1927 if(!task)
1928 return E_OUTOFMEMORY;
1930 task->window = window;
1931 task->pending_window = pending_window;
1932 IHTMLWindow2_AddRef(&pending_window->base.IHTMLWindow2_iface);
1934 return push_task(&task->header, start_doc_binding_proc, start_doc_binding_task_destr, pending_window->task_magic);
1937 void abort_window_bindings(HTMLInnerWindow *window)
1939 BSCallback *iter;
1941 remove_target_tasks(window->task_magic);
1943 while(!list_empty(&window->bindings)) {
1944 iter = LIST_ENTRY(window->bindings.next, BSCallback, entry);
1946 TRACE("Aborting %p\n", iter);
1948 IBindStatusCallback_AddRef(&iter->IBindStatusCallback_iface);
1950 if(iter->binding)
1951 IBinding_Abort(iter->binding);
1952 else
1953 iter->vtbl->stop_binding(iter, E_ABORT);
1955 iter->window = NULL;
1956 list_remove(&iter->entry);
1957 list_init(&iter->entry);
1959 IBindStatusCallback_Release(&iter->IBindStatusCallback_iface);
1962 if(window->bscallback) {
1963 IBindStatusCallback_Release(&window->bscallback->bsc.IBindStatusCallback_iface);
1964 window->bscallback = NULL;
1967 if(window->mon) {
1968 IMoniker_Release(window->mon);
1969 window->mon = NULL;
1973 HRESULT channelbsc_load_stream(HTMLInnerWindow *pending_window, IMoniker *mon, IStream *stream)
1975 nsChannelBSC *bscallback = pending_window->bscallback;
1976 HRESULT hres = S_OK;
1978 if(!bscallback->nschannel) {
1979 ERR("NULL nschannel\n");
1980 return E_FAIL;
1983 bscallback->nschannel->content_type = heap_strdupA("text/html");
1984 if(!bscallback->nschannel->content_type)
1985 return E_OUTOFMEMORY;
1987 set_current_mon(pending_window->base.outer_window, mon, 0);
1989 bscallback->bsc.window = pending_window;
1990 if(stream)
1991 hres = read_stream_data(bscallback, stream);
1992 if(SUCCEEDED(hres))
1993 hres = async_stop_request(bscallback);
1994 if(FAILED(hres))
1995 IBindStatusCallback_OnStopBinding(&bscallback->bsc.IBindStatusCallback_iface, hres,
1996 ERROR_SUCCESS);
1998 return hres;
2001 void channelbsc_set_channel(nsChannelBSC *This, nsChannel *channel, nsIStreamListener *listener, nsISupports *context)
2003 nsIHttpChannel_AddRef(&channel->nsIHttpChannel_iface);
2004 This->nschannel = channel;
2006 nsIStreamListener_AddRef(listener);
2007 This->nslistener = listener;
2009 if(context) {
2010 nsISupports_AddRef(context);
2011 This->nscontext = context;
2014 if(This->bsc.request_data.headers) {
2015 HRESULT hres;
2017 hres = parse_headers(This->bsc.request_data.headers, &channel->request_headers);
2018 heap_free(This->bsc.request_data.headers);
2019 This->bsc.request_data.headers = NULL;
2020 if(FAILED(hres))
2021 WARN("parse_headers failed: %08x\n", hres);
2025 typedef struct {
2026 task_t header;
2027 HTMLOuterWindow *window;
2028 IUri *uri;
2029 } navigate_javascript_task_t;
2031 static void navigate_javascript_proc(task_t *_task)
2033 navigate_javascript_task_t *task = (navigate_javascript_task_t*)_task;
2034 HTMLOuterWindow *window = task->window;
2035 VARIANT v;
2036 BSTR code;
2037 HRESULT hres;
2039 static const WCHAR jscriptW[] = {'j','s','c','r','i','p','t',0};
2041 task->window->readystate = READYSTATE_COMPLETE;
2043 hres = IUri_GetPath(task->uri, &code);
2044 if(FAILED(hres))
2045 return;
2047 hres = UrlUnescapeW(code, NULL, NULL, URL_UNESCAPE_INPLACE);
2048 if(FAILED(hres)) {
2049 SysFreeString(code);
2050 return;
2053 set_download_state(window->doc_obj, 1);
2055 V_VT(&v) = VT_EMPTY;
2056 hres = exec_script(window->base.inner_window, code, jscriptW, &v);
2057 SysFreeString(code);
2058 if(SUCCEEDED(hres) && V_VT(&v) != VT_EMPTY) {
2059 FIXME("javascirpt URL returned %s\n", debugstr_variant(&v));
2060 VariantClear(&v);
2063 if(window->doc_obj->view_sink)
2064 IAdviseSink_OnViewChange(window->doc_obj->view_sink, DVASPECT_CONTENT, -1);
2066 set_download_state(window->doc_obj, 0);
2069 static void navigate_javascript_task_destr(task_t *_task)
2071 navigate_javascript_task_t *task = (navigate_javascript_task_t*)_task;
2073 IUri_Release(task->uri);
2074 heap_free(task);
2077 typedef struct {
2078 task_t header;
2079 HTMLOuterWindow *window;
2080 nsChannelBSC *bscallback;
2081 DWORD flags;
2082 IMoniker *mon;
2083 IUri *uri;
2084 } navigate_task_t;
2086 static void navigate_proc(task_t *_task)
2088 navigate_task_t *task = (navigate_task_t*)_task;
2089 HRESULT hres;
2091 hres = set_moniker(task->window, task->mon, task->uri, NULL, task->bscallback, TRUE);
2092 if(SUCCEEDED(hres)) {
2093 set_current_mon(task->window, task->bscallback->bsc.mon, task->flags);
2094 set_current_uri(task->window, task->uri);
2095 start_binding(task->window->pending_window, &task->bscallback->bsc, NULL);
2099 static void navigate_task_destr(task_t *_task)
2101 navigate_task_t *task = (navigate_task_t*)_task;
2103 IBindStatusCallback_Release(&task->bscallback->bsc.IBindStatusCallback_iface);
2104 IMoniker_Release(task->mon);
2105 IUri_Release(task->uri);
2106 heap_free(task);
2109 static HRESULT navigate_fragment(HTMLOuterWindow *window, IUri *uri)
2111 nsIDOMLocation *nslocation;
2112 nsAString nsfrag_str;
2113 WCHAR *selector;
2114 BSTR frag;
2115 nsresult nsres;
2116 HRESULT hres;
2118 const WCHAR selector_formatW[] = {'a','[','i','d','=','"','%','s','"',']',0};
2120 set_current_uri(window, uri);
2122 nsres = nsIDOMWindow_GetLocation(window->nswindow, &nslocation);
2123 if(FAILED(nsres) || !nslocation)
2124 return E_FAIL;
2126 hres = IUri_GetFragment(uri, &frag);
2127 if(FAILED(hres)) {
2128 nsIDOMLocation_Release(nslocation);
2129 return hres;
2132 nsAString_InitDepend(&nsfrag_str, frag);
2133 nsres = nsIDOMLocation_SetHash(nslocation, &nsfrag_str);
2134 nsAString_Finish(&nsfrag_str);
2135 nsIDOMLocation_Release(nslocation);
2136 if(NS_FAILED(nsres))
2137 ERR("SetHash failed: %08x\n", nsres);
2140 * IE supports scrolling to anchor elements with "#hash" ids (note that '#' is part of the id),
2141 * while Gecko scrolls only to elements with "hash" ids. We scroll the page ourselves if
2142 * a[id="#hash"] element can be found.
2144 selector = heap_alloc(sizeof(selector_formatW)+SysStringLen(frag)*sizeof(WCHAR));
2145 if(selector) {
2146 nsIDOMElement *nselem = NULL;
2147 nsAString selector_str;
2149 sprintfW(selector, selector_formatW, frag);
2150 nsAString_InitDepend(&selector_str, selector);
2151 /* NOTE: Gecko doesn't set result to NULL if there is no match, so nselem must be initialized */
2152 nsres = nsIDOMNodeSelector_QuerySelector(window->base.inner_window->doc->nsnode_selector, &selector_str, &nselem);
2153 nsAString_Finish(&selector_str);
2154 heap_free(selector);
2155 if(NS_SUCCEEDED(nsres) && nselem) {
2156 nsIDOMHTMLElement *html_elem;
2158 nsres = nsIDOMElement_QueryInterface(nselem, &IID_nsIDOMHTMLElement, (void**)&html_elem);
2159 nsIDOMElement_Release(nselem);
2160 if(NS_SUCCEEDED(nsres)) {
2161 nsIDOMHTMLElement_ScrollIntoView(html_elem, TRUE, 1);
2162 nsIDOMHTMLElement_Release(html_elem);
2167 SysFreeString(frag);
2169 if(window->doc_obj->doc_object_service) {
2170 IDocObjectService_FireNavigateComplete2(window->doc_obj->doc_object_service, &window->base.IHTMLWindow2_iface, 0x10);
2171 IDocObjectService_FireDocumentComplete(window->doc_obj->doc_object_service, &window->base.IHTMLWindow2_iface, 0);
2175 return S_OK;
2178 HRESULT super_navigate(HTMLOuterWindow *window, IUri *uri, DWORD flags, const WCHAR *headers, BYTE *post_data, DWORD post_data_size)
2180 nsChannelBSC *bsc;
2181 IUri *uri_nofrag;
2182 IMoniker *mon;
2183 DWORD scheme;
2184 HRESULT hres;
2186 uri_nofrag = get_uri_nofrag(uri);
2187 if(!uri_nofrag)
2188 return E_FAIL;
2190 if(window->doc_obj->client && !(flags & BINDING_REFRESH)) {
2191 IOleCommandTarget *cmdtrg;
2193 hres = IOleClientSite_QueryInterface(window->doc_obj->client, &IID_IOleCommandTarget, (void**)&cmdtrg);
2194 if(SUCCEEDED(hres)) {
2195 VARIANT in, out;
2196 BSTR url_str;
2198 hres = IUri_GetDisplayUri(uri_nofrag, &url_str);
2199 if(SUCCEEDED(hres)) {
2200 V_VT(&in) = VT_BSTR;
2201 V_BSTR(&in) = url_str;
2202 V_VT(&out) = VT_BOOL;
2203 V_BOOL(&out) = VARIANT_TRUE;
2204 hres = IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 67, 0, &in, &out);
2205 IOleCommandTarget_Release(cmdtrg);
2206 if(SUCCEEDED(hres))
2207 VariantClear(&out);
2208 SysFreeString(url_str);
2213 if(!(flags & BINDING_NOFRAG) && window->uri_nofrag && !post_data_size) {
2214 BOOL eq;
2216 hres = IUri_IsEqual(uri_nofrag, window->uri_nofrag, &eq);
2217 if(SUCCEEDED(hres) && eq) {
2218 IUri_Release(uri_nofrag);
2219 TRACE("fragment navigate\n");
2220 return navigate_fragment(window, uri);
2224 hres = CreateURLMonikerEx2(NULL, uri_nofrag, &mon, URL_MK_UNIFORM);
2225 IUri_Release(uri_nofrag);
2226 if(FAILED(hres))
2227 return hres;
2229 /* FIXME: Why not set_ready_state? */
2230 window->readystate = READYSTATE_UNINITIALIZED;
2232 hres = create_channelbsc(mon, headers, post_data, post_data_size, TRUE, &bsc);
2233 if(FAILED(hres)) {
2234 IMoniker_Release(mon);
2235 return hres;
2238 prepare_for_binding(&window->doc_obj->basedoc, mon, flags);
2240 hres = IUri_GetScheme(uri, &scheme);
2241 if(SUCCEEDED(hres) && scheme == URL_SCHEME_JAVASCRIPT) {
2242 navigate_javascript_task_t *task;
2244 IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
2245 IMoniker_Release(mon);
2247 task = heap_alloc(sizeof(*task));
2248 if(!task)
2249 return E_OUTOFMEMORY;
2251 /* Why silently? */
2252 window->readystate = READYSTATE_COMPLETE;
2253 if(!(flags & BINDING_FROMHIST))
2254 call_docview_84(window->doc_obj);
2256 IUri_AddRef(uri);
2257 task->window = window;
2258 task->uri = uri;
2259 hres = push_task(&task->header, navigate_javascript_proc, navigate_javascript_task_destr, window->task_magic);
2260 }else if(flags & BINDING_SUBMIT) {
2261 hres = set_moniker(window, mon, uri, NULL, bsc, TRUE);
2262 if(SUCCEEDED(hres))
2263 hres = start_binding(window->pending_window, &bsc->bsc, NULL);
2264 IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
2265 IMoniker_Release(mon);
2266 }else {
2267 navigate_task_t *task;
2269 task = heap_alloc(sizeof(*task));
2270 if(!task) {
2271 IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
2272 IMoniker_Release(mon);
2273 return E_OUTOFMEMORY;
2276 /* Silently and repeated when real loading starts? */
2277 window->readystate = READYSTATE_LOADING;
2278 if(!(flags & (BINDING_FROMHIST|BINDING_REFRESH)))
2279 call_docview_84(window->doc_obj);
2281 task->window = window;
2282 task->bscallback = bsc;
2283 task->flags = flags;
2284 task->mon = mon;
2286 IUri_AddRef(uri);
2287 task->uri = uri;
2288 hres = push_task(&task->header, navigate_proc, navigate_task_destr, window->task_magic);
2291 return hres;
2294 HRESULT navigate_new_window(HTMLOuterWindow *window, IUri *uri, const WCHAR *name, IHTMLWindow2 **ret)
2296 IWebBrowser2 *web_browser;
2297 IHTMLWindow2 *new_window;
2298 IBindCtx *bind_ctx;
2299 nsChannelBSC *bsc;
2300 HRESULT hres;
2302 hres = create_channelbsc(NULL, NULL, NULL, 0, FALSE, &bsc);
2303 if(FAILED(hres))
2304 return hres;
2306 hres = CreateAsyncBindCtx(0, &bsc->bsc.IBindStatusCallback_iface, NULL, &bind_ctx);
2307 if(FAILED(hres)) {
2308 IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
2309 return hres;
2312 hres = CoCreateInstance(&CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER,
2313 &IID_IWebBrowser2, (void**)&web_browser);
2314 if(SUCCEEDED(hres)) {
2315 ITargetFramePriv2 *target_frame_priv;
2317 hres = IWebBrowser2_QueryInterface(web_browser, &IID_ITargetFramePriv2, (void**)&target_frame_priv);
2318 if(SUCCEEDED(hres)) {
2319 hres = ITargetFramePriv2_AggregatedNavigation2(target_frame_priv,
2320 HLNF_DISABLEWINDOWRESTRICTIONS|HLNF_OPENINNEWWINDOW, bind_ctx, &bsc->bsc.IBindStatusCallback_iface,
2321 name, uri, emptyW);
2322 ITargetFramePriv2_Release(target_frame_priv);
2324 if(SUCCEEDED(hres))
2325 hres = do_query_service((IUnknown*)web_browser, &SID_SHTMLWindow, &IID_IHTMLWindow2, (void**)&new_window);
2327 if(FAILED(hres)) {
2328 IWebBrowser2_Quit(web_browser);
2329 IWebBrowser2_Release(web_browser);
2331 }else {
2332 WARN("Could not create InternetExplorer instance: %08x\n", hres);
2335 IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
2336 IBindCtx_Release(bind_ctx);
2337 if(FAILED(hres))
2338 return hres;
2340 IWebBrowser2_put_Visible(web_browser, VARIANT_TRUE);
2341 IWebBrowser2_Release(web_browser);
2343 if(ret)
2344 *ret = new_window;
2345 else
2346 IHTMLWindow2_Release(new_window);
2347 return S_OK;
2350 HRESULT hlink_frame_navigate(HTMLDocument *doc, LPCWSTR url, nsChannel *nschannel, DWORD hlnf, BOOL *cancel)
2352 IHlinkFrame *hlink_frame;
2353 nsChannelBSC *callback;
2354 IBindCtx *bindctx;
2355 IMoniker *mon;
2356 IHlink *hlink;
2357 HRESULT hres;
2359 *cancel = FALSE;
2361 hres = do_query_service((IUnknown*)doc->doc_obj->client, &IID_IHlinkFrame, &IID_IHlinkFrame,
2362 (void**)&hlink_frame);
2363 if(FAILED(hres))
2364 return S_OK;
2366 hres = create_channelbsc(NULL, NULL, NULL, 0, FALSE, &callback);
2367 if(FAILED(hres)) {
2368 IHlinkFrame_Release(hlink_frame);
2369 return hres;
2372 if(nschannel)
2373 read_post_data_stream(nschannel->post_data_stream, nschannel->post_data_contains_headers,
2374 &nschannel->request_headers, &callback->bsc.request_data);
2376 hres = CreateAsyncBindCtx(0, &callback->bsc.IBindStatusCallback_iface, NULL, &bindctx);
2377 if(SUCCEEDED(hres))
2378 hres = CoCreateInstance(&CLSID_StdHlink, NULL, CLSCTX_INPROC_SERVER,
2379 &IID_IHlink, (LPVOID*)&hlink);
2381 if(SUCCEEDED(hres))
2382 hres = CreateURLMoniker(NULL, url, &mon);
2384 if(SUCCEEDED(hres)) {
2385 IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET, mon, NULL);
2387 if(hlnf & HLNF_OPENINNEWWINDOW) {
2388 static const WCHAR wszBlank[] = {'_','b','l','a','n','k',0};
2389 IHlink_SetTargetFrameName(hlink, wszBlank); /* FIXME */
2392 hres = IHlinkFrame_Navigate(hlink_frame, hlnf, bindctx,
2393 &callback->bsc.IBindStatusCallback_iface, hlink);
2394 IMoniker_Release(mon);
2395 *cancel = hres == S_OK;
2396 hres = S_OK;
2399 IHlinkFrame_Release(hlink_frame);
2400 IBindCtx_Release(bindctx);
2401 IBindStatusCallback_Release(&callback->bsc.IBindStatusCallback_iface);
2402 return hres;
2405 static HRESULT navigate_uri(HTMLOuterWindow *window, IUri *uri, const WCHAR *display_uri, const request_data_t *request_data,
2406 DWORD flags)
2408 nsWineURI *nsuri;
2409 HRESULT hres;
2411 TRACE("%s\n", debugstr_w(display_uri));
2413 if(window->doc_obj && window->doc_obj->webbrowser && window == window->doc_obj->basedoc.window) {
2414 DWORD post_data_len = request_data ? request_data->post_data_len : 0;
2415 void *post_data = post_data_len ? request_data->post_data : NULL;
2416 const WCHAR *headers = request_data ? request_data->headers : NULL;
2418 if(!(flags & BINDING_REFRESH)) {
2419 BOOL cancel = FALSE;
2421 hres = IDocObjectService_FireBeforeNavigate2(window->doc_obj->doc_object_service, NULL, display_uri, 0x40,
2422 NULL, post_data, post_data_len ? post_data_len+1 : 0, headers, TRUE, &cancel);
2423 if(SUCCEEDED(hres) && cancel) {
2424 TRACE("Navigation canceled\n");
2425 return S_OK;
2429 return super_navigate(window, uri, flags, headers, post_data, post_data_len);
2432 if(window->doc_obj && window == window->doc_obj->basedoc.window) {
2433 BOOL cancel;
2435 hres = hlink_frame_navigate(&window->base.inner_window->doc->basedoc, display_uri, NULL, 0, &cancel);
2436 if(FAILED(hres))
2437 return hres;
2439 if(cancel) {
2440 TRACE("Navigation handled by hlink frame\n");
2441 return S_OK;
2445 hres = create_doc_uri(window, uri, &nsuri);
2446 if(FAILED(hres))
2447 return hres;
2449 hres = load_nsuri(window, nsuri, NULL, LOAD_FLAGS_NONE);
2450 nsISupports_Release((nsISupports*)nsuri);
2451 return hres;
2454 HRESULT load_uri(HTMLOuterWindow *window, IUri *uri, DWORD flags)
2456 BSTR display_uri;
2457 HRESULT hres;
2459 hres = IUri_GetDisplayUri(uri, &display_uri);
2460 if(FAILED(hres))
2461 return hres;
2463 hres = navigate_uri(window, uri, display_uri, NULL, flags);
2464 SysFreeString(display_uri);
2465 return hres;
2468 static HRESULT translate_uri(HTMLOuterWindow *window, IUri *orig_uri, BSTR *ret_display_uri, IUri **ret_uri)
2470 IUri *uri = NULL;
2471 BSTR display_uri;
2472 HRESULT hres;
2474 hres = IUri_GetDisplayUri(orig_uri, &display_uri);
2475 if(FAILED(hres))
2476 return hres;
2478 if(window->doc_obj && window->doc_obj->hostui) {
2479 OLECHAR *translated_url = NULL;
2481 hres = IDocHostUIHandler_TranslateUrl(window->doc_obj->hostui, 0, display_uri,
2482 &translated_url);
2483 if(hres == S_OK) {
2484 TRACE("%08x %s -> %s\n", hres, debugstr_w(display_uri), debugstr_w(translated_url));
2485 SysFreeString(display_uri);
2486 hres = create_uri(translated_url, 0, &uri);
2487 CoTaskMemFree(translated_url);
2488 if(FAILED(hres))
2489 return hres;
2491 hres = IUri_GetDisplayUri(uri, &display_uri);
2492 if(FAILED(hres)) {
2493 IUri_Release(uri);
2494 return hres;
2499 if(!uri) {
2500 IUri_AddRef(orig_uri);
2501 uri = orig_uri;
2504 *ret_display_uri = display_uri;
2505 *ret_uri = uri;
2506 return S_OK;
2509 HRESULT submit_form(HTMLOuterWindow *window, IUri *submit_uri, nsIInputStream *post_stream)
2511 request_data_t request_data = {NULL};
2512 BSTR display_uri;
2513 IUri *uri;
2514 HRESULT hres;
2516 hres = read_post_data_stream(post_stream, TRUE, NULL, &request_data);
2517 if(FAILED(hres))
2518 return hres;
2520 hres = translate_uri(window, submit_uri, &display_uri, &uri);
2521 if(SUCCEEDED(hres)) {
2522 hres = navigate_uri(window, uri, display_uri, &request_data, BINDING_NAVIGATED|BINDING_SUBMIT);
2523 IUri_Release(uri);
2524 SysFreeString(display_uri);
2526 release_request_data(&request_data);
2527 return hres;
2530 HRESULT navigate_url(HTMLOuterWindow *window, const WCHAR *new_url, IUri *base_uri, DWORD flags)
2532 IUri *uri, *nav_uri;
2533 BSTR display_uri;
2534 HRESULT hres;
2536 if(new_url && base_uri)
2537 hres = CoInternetCombineUrlEx(base_uri, new_url, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO,
2538 &nav_uri, 0);
2539 else
2540 hres = create_uri(new_url, 0, &nav_uri);
2541 if(FAILED(hres))
2542 return hres;
2544 hres = translate_uri(window, nav_uri, &display_uri, &uri);
2545 IUri_Release(nav_uri);
2546 if(FAILED(hres))
2547 return hres;
2549 hres = navigate_uri(window, uri, display_uri, NULL, flags);
2550 IUri_Release(uri);
2551 SysFreeString(display_uri);
2552 return hres;