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